Using Far::PatchTable to evaluate limit surface AND limit face varying data

49 views
Skip to first unread message

Jean Ben

unread,
Nov 3, 2022, 1:01:41 PM11/3/22
to OpenSubdiv Forum

Hi,

We're currently implementing a variable rate subdiv scheme for a renderer (where each coarse polygon is tessellated according to its screen appearance) using Far::PatchTable as in far_tutorial_5_1.

We've extended the tutorial for face varying data (uv texture coordinates), but this doesn't seem to generate the correct values. Specifically, the result does not seem to be smooth, and there some cracks between patches.

Is this supported in OSD, and is there something specific to do regarding face varying data?


Here is an indicative bit of code that represents what we do to handle face varying data:

unsigned channel = 0;

TopologyDescriptor::FVarChannel desc;
desc.numValues = nfvData;
desc.valueIndices = fvIndices.data ();
fvChannels.push_back (desc);
fvChannelsIndices.push_back (channel);

TopologyDescriptor descriptor = {};
descriptor.numVertices = numVertices;
descriptor.numFaces = numFaces;
descriptor.numVertsPerFace = numVertPerFace.data ();
descriptor.vertIndicesPerFace = vertIndicesPerFace.data ();
descriptor.numFVarChannels = fvChannels.size ();
descriptor.fvarChannels = fvChannels.data ();

PatchTableFactory::Options patchOptions (4);
patchOptions.SetPatchPrecision<float>();
patchOptions.generateVaryingTables = true;
patchOptions.generateVaryingLocalPoints = true;
patchOptions.generateFVarTables = true;
patchOptions.endCapType = PatchTableFactory::Options::ENDCAP_GREGORY_BASIS;
patchOptions.numFVarChannels = fvChannelsIndices.size ();
patchOptions.fvarChannelIndices = fvChannelsIndices.data ();




// This is adapted from lines 186-216 in far_tutorial_5_1.cpp

unsigned nRefinerVertices = refiner->GetNumFVarValuesTotal (channel);
unsigned nLocalPoints = patchTable->GetNumLocalPointsFaceVarying (channel);

std::vector<floatn<N>> facevar (nRefinerVertices + nLocalPoints);
std::memcpy (facevar.data (), fvData.data (), nfvData*N*sizeof (float));

Far::PrimvarRefinerReal<float> pvrefiner (*refiner);

floatn<N>   *src = facevar.data ();
for (int level = 1; level < refiner->GetNumLevels (); ++level)
{
    floatn<N>   *dst = src+refiner->GetLevel (level-1).GetNumFVarValues (channel);
    pvrefiner.InterpolateFaceVarying (level, src, dst, channel);
    src = dst;
}
if (nLocalPoints > 0)
{
    src = facevar.data ();
    patchTable->GetLocalPointFaceVaryingStencilTable<float> ()->UpdateValues (src, src+nRefinerVertices, channel);
}


// This is adapted from lines 240-255 in far_tutorial_5_1.cpp

float   wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
Far::ConstIndexArray    cvs;

const Far::PatchTable::PatchHandle  *handle = patchmap->FindPatch (patchId, u, v);

patchTable->EvaluateBasisFaceVarying (*handle, u, v, wP, wDu, wDv, wDuu, wDuv, wDvv, channel);
cvs = patchTable->GetPatchFVarValues (*handle, channel);


floatn<N>   result (0);
for (int cv = 0; cv < cvs.size (); ++cv)
    result.AddWithWeight (refined[cvs[cv]], wP[cv]);


I've put in bold the parts of the patch table prep and lookup that we adapted to face varying.

Sorry for the code dump, but I'm a bit lost here about what we do wrong.

Thanks,

Ben



Barry F

unread,
Nov 8, 2022, 4:10:45 PM11/8/22
to OpenSubdiv Forum
The use case you are attempting is supported by OpenSubdiv and has been in active use by many clients since version 3.1 (2016).

It looks like the issue here is that your Options for the PatchTable includes default settings that do not override the legacy behavior of face-varying patches.  Unfortunately early versions of the Far::PatchTable did not properly support smooth face-varying patches -- approximating them with linear -- and it was necessary to continue to support that linear approximation after smooth patches were added (due to the higher costs).

The definition of Far::PatchTableFactory::Options includes the following:

    // legacy behaviors (default to true)
    generateFVarLegacyLinearPatches  : 1, ///< Generate all linear face-varying patches (legacy)
    generateLegacySharpCornerPatches : 1; ///< Generate sharp regular patches at smooth corners (legacy)

So when generating face-varying patches, the following line is needed when initializing your Options:

    patchOptions.generateFVarLegacyLinearPatches = false;

Please confirm if that is the source of your problem ("does not seem to be smooth, and there some cracks between patches").

I believe far/tutorial_5_1 was written before smooth face-varying patches were properly supported and those legacy options added. So mention of these legacy options could be added as a comment in the tutorial when the Options are initialized to prevent others running into this.

And if you do not need to keep the Far::PatchTable around after your tessellation (which can take a lot of memory for large meshes) and you can advance to version 3.5 of OpenSubdiv, then I recommend you consider using the new surface evaluation interface provided by 3.5 as it greatly simplifies this task. The release notes for 3.5 include a summary and links to more relevant documentation and tutorials.

Thanks
Reply all
Reply to author
Forward
0 new messages