PixarAnimationStudios / OpenSubdiv

An Open-Source subdivision surface library.
graphics.pixar.com/opensubdiv
Other
2.88k stars 558 forks source link

Evaluate positions on limit surface depending on vertex #1302

Closed roquo closed 1 year ago

roquo commented 1 year ago

With the new Bfr or with using the Far::PatchTable it is possible to evaluate positions on the limit surface depending on u and v parameters, for example from tutorial 5.1:

for (int face=0, count=0; face<nfaces; ++face) {

    for (int sample=0; sample<nsamplesPerFace; ++sample, ++count) {

        Real s = (Real)rand()/(Real)RAND_MAX,
             t = (Real)rand()/(Real)RAND_MAX;

        // Locate the patch corresponding to the face ptex idx and (s,t)
        Far::PatchTable::PatchHandle const * handle =
            patchmap.FindPatch(face, s, t);
        assert(handle);

        // Evaluate the patch weights, identify the CVs and compute the limit frame:
        patchTable->EvaluateBasis(*handle, s, t, pWeights, dsWeights, dtWeights);

        Far::ConstIndexArray cvs = patchTable->GetPatchVertices(*handle);

        LimitFrame & dst = samples[count];
        dst.Clear();
        for (int cv=0; cv < cvs.size(); ++cv) {
            dst.AddWithWeight(verts[cvs[cv]], pWeights[cv], dsWeights[cv], dtWeights[cv]);
        }

    }
}

In this example, arbitrary positions are evaluated.

My goal is to evaluate positions based on the vertices in the mesh (maybe of any level) like this:

  int lastLevel = 2;
  auto& level = refiner->GetLevel(lastLevel);
  auto numVertices = level.GetNumVertices();
  for (auto vertex = 0; vertex < numVertices; ++vertex)
  {
    double u, v;
    // this method does nox exist right now
    level.GetUVFromVertex(vertex, u, v);

    // Evaluate the patch weights, identify the CVs and compute the limit frame:
    patchTable->EvaluateBasis(*handle, u, v, pWeights, dsWeights, dtWeights);

    //...//
  }

Is something like this possible? So my end goal is to evaluate the limit position of any vertex. My idea was somehow to get the corresponding u and v value but I am unsure how to do this. For level 0 I could imagine to find out the 4 values {(0,0), (0,1), (1,1), (1,0)} but I do not know how to do this for the sublevels.

barfowl commented 1 year ago

Rather than trying to use patches to compute the limit positions for refined vertices, you may be able to accomplish what you want with the Far::PrimvarRefiner.

In addition to methods to interpolate values for successive refined levels, it also has Limit() methods to snap the values from the last level of refinement to the limit surface. The Far tutorial 2.3 illustrates use of the Limit() method in computing limit positions and normals for refined vertices (one of three ways this tutorial computes normals).

Trying to use patches for this process is possible but awkward for a couple of reasons. I can provide more details on that later if the PrimvarRefiner::Limit() methods don't meet your needs.

roquo commented 1 year ago

Thanks! I did not know that I could do this with the PrimvarRefiner. It works like expected