Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create uniform b-spline patches with adaptive refinement #1292

Open
roquo opened this issue Jan 12, 2023 · 2 comments
Open

Create uniform b-spline patches with adaptive refinement #1292

roquo opened this issue Jan 12, 2023 · 2 comments

Comments

@roquo
Copy link

roquo commented Jan 12, 2023

Hi there!

I am trying to create uniform b-spline patches with adaptive refinement. As an example, I took the catmark_torus an set a crease value to one of the inner circle edges.

Refiner:

  Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;

  Sdc::Options options;
  options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);

  Descriptor desc;
  desc.numVertices = quadMesh.Vertices.size();
  desc.numFaces = quadMesh.Faces.size();
  desc.numVertsPerFace = quadMesh.VerticesPerFace.data();

  const auto* vec = static_cast<void*>(quadMesh.Faces.data());
  desc.vertIndicesPerFace = static_cast<const Far::Index*>(vec);
  desc.numCreases = 8;
  std::vector<int> crease_verts{1, 29, 29, 25, 25, 21, 21, 17, 17, 13, 13, 9, 9, 5, 5, 1};
  std::vector<float> crease_weights{3.0f, 3.0f, 3.0f, 3.0f, 3.0f, 3.0f, 3.0f, 3.0f};
  desc.creaseVertexIndexPairs = crease_verts.data();
  desc.creaseWeights = crease_weights.data();

  // Instantiate a Far::TopologyRefiner from the descriptor.
  Far::TopologyRefiner* refiner = Far::TopologyRefinerFactory<Descriptor>::Create(
    desc, Far::TopologyRefinerFactory<Descriptor>::Options(type, options));

Code to create b-splines:

  int maxPatchLevel = 3;

  Far::PatchTableFactory::Options patchOptions(maxPatchLevel);
  patchOptions.SetPatchPrecision<Real>();
  patchOptions.useInfSharpPatch = true;
  patchOptions.generateVaryingTables = false;
  patchOptions.endCapType = Far::PatchTableFactory::Options::ENDCAP_BSPLINE_BASIS;

  // Initialize corresonding options for adaptive refinement:
  Far::TopologyRefiner::AdaptiveOptions adaptiveOptions = patchOptions.GetRefineAdaptiveOptions();

  // Apply adaptive refinement and construct the associated PatchTable to
  // evaluate the limit surface:
  refiner->RefineAdaptive(adaptiveOptions);

  Far::PatchTable const* patchTable = Far::PatchTableFactory::Create(*refiner, patchOptions);

  // Compute the total number of points we need to evaluate the PatchTable.
  // Approximations at irregular or extraordinary features require the use
  // of additional points associated with the patches that are referred to
  // as "local points" (i.e. local to the PatchTable).
  int nRefinerVertices = refiner->GetNumVerticesTotal();
  int nLocalPoints = patchTable->GetNumLocalPoints();

  // Create a buffer to hold the position of the refined verts and
  // local points, then copy the coarse positions at the beginning.
  std::vector<Vertex> verts(nRefinerVertices + nLocalPoints);
  auto index = 0;
  for(auto& vertex : quadMesh.Vertices)
  {
    verts[index].point[0] = vertex[0];
    verts[index].point[1] = vertex[1];
    verts[index].point[2] = vertex[2];
    ++index;
  }
  //std::memcpy(&verts[0], quadMesh.Vertices.data(), quadMesh.Vertices.size() * 3 * sizeof(float));

  // Adaptive refinement may result in fewer levels than the max specified.
  int nRefinedLevels = refiner->GetNumLevels();

  // Interpolate vertex primvar data : they are the control vertices
  // of the limit patches (see tutorial_1_1 for details)
  Far::PrimvarRefinerReal<Real> primvarRefiner(*refiner);

  Vertex* src = &verts[0];
  for (int level = 1; level < nRefinedLevels; ++level)
  {
    Vertex* dst = src + refiner->GetLevel(level - 1).GetNumVertices();
    primvarRefiner.Interpolate(level, src, dst);
    src = dst;
  }

  // Evaluate local points from interpolated vertex primvars.
  if (nLocalPoints)
  {
    patchTable->GetLocalPointStencilTable<Real>()->UpdateValues(&verts[0], &verts[nRefinerVertices]);
  }

  // Create a Far::PatchMap to help locating patches in the table
  Far::PatchMap patchmap(*patchTable);

  // Create a Far::PtexIndices to help find indices of ptex faces.
  Far::PtexIndices ptexIndices(*refiner);
  
  int face = 0;
  for (auto& handle : patchmap._handles)
  {
    Far::ConstIndexArray cvs = patchTable->GetPatchVertices(handle);

    // tessellate b-spline
    // done with other library
  }

Then this is my result, I did draw in the actual borders for better visibility:
first

So the inner circle of the torus has got the crease as expected and the patches are getting smaller and are adaptively refined

What I need now is that the smallest adaptive refinement is globally uniformly applied. So at one border of a b-spline patch is also only one other patch. I tried to draw what I mean from the example above:
first

Is something like that possible with OpenSubdiv?

@davidgyu
Copy link
Member

Filed as internal issue #OSD-404

@davidgyu
Copy link
Member

The short answer is that OpenSubdiv does not currently provide the patch representation you want.

We've considered adding support for generating a uniform patch representations of the surface and agree that could be useful and would help to fill out the feature set, but we haven't done so yet.

In practice, it should be pretty straightforward to further subdivide adaptive patches to match the patches at the highest level of refinement while taking care of the additional state in the corresponding patch parameter tags, e.g. to account for infinitely sharp boundaries, etc.

Curious if you could share more about your specific use case in case there are other ways to achieve your desired result.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants