https://github.com/PixarAnimationStudios/OpenSubdiv/blob/release/tutorials/far/tutorial_5_1/far_tutorial_5_1.cpp
using namespace OpenSubdiv;
typedef double Real;
static int const g_nverts = 5;
static Real const g_verts[24] = { 0.0f, 0.0f, 2.0f,
0.0f, -2.0f, 0.0f,
2.0f, 0.0f, 0.0f,
0.0f, 2.0f, 0.0f,
-2.0f, 0.0f, 0.0f, };
static int const g_vertsperface[5] = { 3, 3, 3, 3, 4 };
static int const g_nfaces = 5;
static int const g_faceverts[16] = { 0, 1, 2,
0, 2, 3,
0, 3, 4,
0, 4, 1,
4, 3, 2, 1 };
static int const g_ncreases = 4;
static int const g_creaseverts[8] = { 4, 3, 3, 2, 2, 1, 1, 4 };
static float const g_creaseweights[4] = { 3.0f, 3.0f, 3.0f, 3.0f };
static Far::TopologyRefiner * createTopologyRefiner();
struct Vertex {
Vertex() { }
void Clear( void * =0 ) {
point[0] = point[1] = point[2] = 0.0f;
}
void AddWithWeight(Vertex const & src, Real weight) {
point[0] += weight * src.point[0];
point[1] += weight * src.point[1];
point[2] += weight * src.point[2];
}
Real point[3];
};
struct LimitFrame {
void Clear( void * =0 ) {
point[0] = point[1] = point[2] = 0.0f;
deriv1[0] = deriv1[1] = deriv1[2] = 0.0f;
deriv2[0] = deriv2[1] = deriv2[2] = 0.0f;
}
void AddWithWeight(Vertex const & src,
Real weight, Real d1Weight, Real d2Weight) {
point[0] += weight * src.point[0];
point[1] += weight * src.point[1];
point[2] += weight * src.point[2];
deriv1[0] += d1Weight * src.point[0];
deriv1[1] += d1Weight * src.point[1];
deriv1[2] += d1Weight * src.point[2];
deriv2[0] += d2Weight * src.point[0];
deriv2[1] += d2Weight * src.point[1];
deriv2[2] += d2Weight * src.point[2];
}
Real point[3],
deriv1[3],
deriv2[3];
};
int main(int, char **) {
Far::TopologyRefiner * refiner = createTopologyRefiner();
int maxPatchLevel = 3;
Far::PatchTableFactory::Options patchOptions(maxPatchLevel);
patchOptions.SetPatchPrecision<Real>();
patchOptions.useInfSharpPatch = true;
patchOptions.generateVaryingTables = false;
patchOptions.endCapType =
Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS;
Far::TopologyRefiner::AdaptiveOptions adaptiveOptions(maxPatchLevel);
bool assignAdaptiveOptionsExplicitly = false;
if (assignAdaptiveOptionsExplicitly) {
adaptiveOptions.useInfSharpPatch = true;
} else {
adaptiveOptions = patchOptions.GetRefineAdaptiveOptions();
}
assert(adaptiveOptions.useInfSharpPatch == patchOptions.useInfSharpPatch);
refiner->RefineAdaptive(adaptiveOptions);
Far::PatchTable const * patchTable =
Far::PatchTableFactory::Create(*refiner, patchOptions);
int nRefinerVertices = refiner->GetNumVerticesTotal();
int nLocalPoints = patchTable->GetNumLocalPoints();
std::vector<Vertex> verts(nRefinerVertices + nLocalPoints);
std::memcpy(&verts[0], g_verts, g_nverts*3*sizeof(Real));
int nRefinedLevels = refiner->GetNumLevels();
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;
}
if (nLocalPoints) {
patchTable->GetLocalPointStencilTable<Real>()->UpdateValues(
&verts[0], &verts[nRefinerVertices]);
}
Far::PatchMap patchmap(*patchTable);
Far::PtexIndices ptexIndices(*refiner);
int nsamplesPerFace = 200,
nfaces = ptexIndices.GetNumFaces();
std::vector<LimitFrame> samples(nsamplesPerFace * nfaces);
srand( static_cast<int>(2147483647) );
Real pWeights[20], dsWeights[20], dtWeights[20];
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;
Far::PatchTable::PatchHandle const * handle =
patchmap.FindPatch(face, s, t);
assert(handle);
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]);
}
}
}
{
int nsamples = (int)samples.size();
printf("file -f -new;\n");
printf("particle -n deriv1 ");
for (int sample=0; sample<nsamples; ++sample) {
Real const * pos = samples[sample].point;
printf("-p %f %f %f\n", pos[0], pos[1], pos[2]);
}
printf(";\n");
printf("setAttr \"deriv1.particleRenderType\" 6;\n");
printf("setAttr \"deriv1.velocity\" -type \"vectorArray\" %d ",nsamples);
for (int sample=0; sample<nsamples; ++sample) {
Real const * tan1 = samples[sample].deriv1;
printf("%f %f %f\n", tan1[0], tan1[1], tan1[2]);
}
printf(";\n");
printf("particle -n deriv2 ");
for (int sample=0; sample<nsamples; ++sample) {
Real const * pos = samples[sample].point;
printf("-p %f %f %f\n", pos[0], pos[1], pos[2]);
}
printf(";\n");
printf("setAttr \"deriv2.particleRenderType\" 6;\n");
printf("setAttr \"deriv2.velocity\" -type \"vectorArray\" %d ",nsamples);
for (int sample=0; sample<nsamples; ++sample) {
Real const * tan2 = samples[sample].deriv2;
printf("%f %f %f\n", tan2[0], tan2[1], tan2[2]);
}
printf(";\n");
printf("currentTime -edit `currentTime -q`;\n");
printf("select deriv1Shape deriv2Shape;\n");
}
delete refiner;
delete patchTable;
return EXIT_SUCCESS;
}
static Far::TopologyRefiner *
createTopologyRefiner() {
typedef Far::TopologyDescriptor Descriptor;
Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;
Sdc::Options options;
options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
Descriptor desc;
desc.numVertices = g_nverts;
desc.numFaces = g_nfaces;
desc.numVertsPerFace = g_vertsperface;
desc.vertIndicesPerFace = g_faceverts;
desc.numCreases = g_ncreases;
desc.creaseVertexIndexPairs = g_creaseverts;
desc.creaseWeights = g_creaseweights;
Far::TopologyRefiner * refiner =
Far::TopologyRefinerFactory<Descriptor>::Create(desc,
Far::TopologyRefinerFactory<Descriptor>::Options(type, options));
return refiner;
}