//------------------------------------------------------------------------------ static Far::TopologyRefiner const * createTopologyRefiner(int maxlevel) { // Populate a topology descriptor with our raw data typedef Far::TopologyRefinerFactoryBase::TopologyDescriptor Descriptor; Sdc::Type type = OpenSubdiv::Sdc::TYPE_CATMARK; Sdc::Options options; options.SetVVarBoundaryInterpolation(Sdc::Options::VVAR_BOUNDARY_EDGE_ONLY); Descriptor desc; desc.numVertices = g_nverts; desc.numFaces = g_nfaces; desc.vertsPerFace = g_vertsperface; desc.vertIndices = g_vertIndices; // Instantiate a FarTopologyRefiner from the descriptor Far::TopologyRefiner * refiner = Far::TopologyRefinerFactory<Descriptor>::Create(type, options, desc); // Uniformly refine the topolgy up to 'maxlevel' refiner->RefineUniform( maxlevel ); return refiner; }
CpuSmoothNormalContext::CpuSmoothNormalContext( Far::TopologyRefiner const & refiner, int level, bool resetMemory) : _numVertices(0), _resetMemory(resetMemory) { int nfaces = refiner.GetNumFaces(level), nverts = nfaces * 4; _faceVerts.resize(nverts); Far::Index * dest = &_faceVerts[0]; for (int face=0; face<nfaces; ++face, dest+=4) { Far::ConstIndexArray fverts = refiner.GetFaceVertices(level, face); memcpy(dest, fverts.begin(), 4 * sizeof(Far::Index)); } }
inline bool TopologyRefinerFactory<PXR_NS::Converter>::assignComponentTopology( Far::TopologyRefiner & refiner, PXR_NS::Converter const & converter) { PXR_NAMESPACE_USING_DIRECTIVE PxOsdMeshTopology const topology = converter.topology; int const * vertIndices = topology.GetFaceVertexIndices().cdata(); bool flip = (topology.GetOrientation() != PxOsdOpenSubdivTokens->rightHanded); for (int face=0, idx=0; face<refiner.GetLevel(0).GetNumFaces(); ++face) { IndexArray dstFaceVerts = getBaseFaceVertices(refiner, face); if (flip) { dstFaceVerts[0] = vertIndices[idx++]; for (int vert=dstFaceVerts.size()-1; vert > 0; --vert) { dstFaceVerts[vert] = vertIndices[idx++]; } } else { for (int vert=0; vert<dstFaceVerts.size(); ++vert) { dstFaceVerts[vert] = vertIndices[idx++]; } } } return true; }
//------------------------------------------------------------------------------ int main(int, char **) { // Generate some FarTopologyRefiner (see far_tutorial_0 for details). Far::TopologyRefiner * refiner = createTopologyRefiner(); // Uniformly refine the topolgy up to 'maxlevel'. int maxlevel = 4; refiner->RefineUniform(Far::TopologyRefiner::UniformOptions(maxlevel)); // Use the FarStencilTable factory to create cascading stencil table // note: we want stencils for the each refinement level // "cascade" mode is achieved by setting "factorizeIntermediateLevels" // to false Far::StencilTableFactory::Options options; options.generateIntermediateLevels=true; options.factorizeIntermediateLevels=false; options.generateOffsets=true; Far::StencilTable const * stencilTable = Far::StencilTableFactory::Create(*refiner, options); std::vector<Vertex> vertexBuffer(refiner->GetNumVerticesTotal()-g_nverts); Vertex * destVerts = &vertexBuffer[0]; int start = 0, end = 0; // stencils batches for each level of subdivision for (int level=0; level<maxlevel; ++level) { int nverts = refiner->GetLevel(level+1).GetNumVertices(); Vertex const * srcVerts = reinterpret_cast<Vertex *>(g_verts); if (level>0) { srcVerts = &vertexBuffer[start]; } start = end; end += nverts; stencilTable->UpdateValues(srcVerts, destVerts, start, end); // apply 2 hierarchical edits on level 1 vertices if (level==1) { float * pos = destVerts[start+5].GetPosition(); pos[1] += 0.5f; pos = destVerts[start+20].GetPosition(); pos[0] += 0.25f; } } { // Output OBJ of the highest level refined ----------- Vertex * verts = &vertexBuffer[0]; // Print vertex positions for (int level=1, firstvert=0; level<=maxlevel; ++level) { Far::TopologyLevel const & refLevel = refiner->GetLevel(level); printf("g level_%d\n", level); int nverts = refLevel.GetNumVertices(); for (int vert=0; vert<nverts; ++vert) { float const * pos = verts[vert].GetPosition(); printf("v %f %f %f\n", pos[0], pos[1], pos[2]); } verts += nverts; // Print faces for (int face=0; face<refLevel.GetNumFaces(); ++face) { Far::ConstIndexArray fverts = refLevel.GetFaceVertices(face); // all refined Catmark faces should be quads assert(fverts.size()==4); printf("f "); for (int vert=0; vert<fverts.size(); ++vert) { printf("%d ", fverts[vert]+firstvert+1); // OBJ uses 1-based arrays... } printf("\n"); } firstvert+=nverts; } } delete refiner; delete stencilTable; }
//------------------------------------------------------------------------------ static void createFarGLMesh(Shape * shape, int maxlevel) { Stopwatch s; s.Start(); using namespace OpenSubdiv; // create Far mesh (topology) Sdc::SchemeType sdctype = GetSdcType(*shape); Sdc::Options sdcoptions = GetSdcOptions(*shape); sdcoptions.SetFVarLinearInterpolation(g_fvarInterpolation); Far::TopologyRefiner * refiner = Far::TopologyRefinerFactory<Shape>::Create(*shape, Far::TopologyRefinerFactory<Shape>::Options(sdctype, sdcoptions)); if (g_Adaptive) { Far::TopologyRefiner::AdaptiveOptions options(maxlevel); options.useSingleCreasePatch = false; refiner->RefineAdaptive(options); } else { Far::TopologyRefiner::UniformOptions options(maxlevel); options.fullTopologyInLastLevel = true; refiner->RefineUniform(options); } int numTotalVerts = refiner->GetNumVerticesTotal(); // // Patch table // std::vector<Vertex> fvarBuffer; Far::PatchTable * patchTable = 0; bool createFVarWire = g_FarDrawFVarPatches or g_FarDrawFVarVerts; if (g_Adaptive) { Far::PatchTableFactory::Options options; options.generateFVarTables = createFVarWire; options.shareEndCapPatchPoints = false; patchTable = Far::PatchTableFactory::Create(*refiner, options); // increase vertex buffer for the additional local points if (patchTable->GetLocalPointStencilTable()) { numTotalVerts += patchTable->GetLocalPointStencilTable()->GetNumStencils(); } g_numPatches = patchTable->GetNumPatchesTotal(); g_maxValence = patchTable->GetMaxValence(); if (createFVarWire) { // interpolate fvar values int channel = 0; // XXXX should use a (u,v) vertex class fvarBuffer.resize(refiner->GetNumFVarValuesTotal(channel), 0); Vertex * values = &fvarBuffer[0]; int nCoarseValues = refiner->GetLevel(0).GetNumFVarValues(channel); for (int i=0; i<nCoarseValues; ++i) { float const * ptr = &shape->uvs[i*2]; values[i].SetPosition(ptr[0], ptr[1], 0.0f); } int lastLevel = refiner->GetMaxLevel(); Vertex * src = values; for (int level = 1; level <= lastLevel; ++level) { Vertex * dst = src + refiner->GetLevel(level-1).GetNumFVarValues(channel); Far::PrimvarRefiner(*refiner).InterpolateFaceVarying(level, src, dst, channel); src = dst; } } } // // interpolate vertices // // create vertex primvar data buffer std::vector<Vertex> vertexBuffer(numTotalVerts); Vertex * verts = &vertexBuffer[0]; // copy coarse vertices positions int ncoarseverts = shape->GetNumVertices(); for (int i=0; i<ncoarseverts; ++i) { float * ptr = &shape->verts[i*3]; verts[i].SetPosition(ptr[0], ptr[1], ptr[2]); } s.Start(); if (g_useStencils) { // // Stencil interpolation // Far::StencilTable const * stencilTable = 0; Far::StencilTableFactory::Options options; options.generateOffsets=true; options.generateIntermediateLevels=true; stencilTable = Far::StencilTableFactory::Create(*refiner, options); // append local point stencils if needed if (patchTable and patchTable->GetLocalPointStencilTable()) { if (Far::StencilTable const * stencilTableWithLocalPoints = Far::StencilTableFactory::AppendLocalPointStencilTable( *refiner, stencilTable, patchTable->GetLocalPointStencilTable())) { delete stencilTable; stencilTable = stencilTableWithLocalPoints; } } // // apply stencils // stencilTable->UpdateValues(verts, verts + ncoarseverts); delete stencilTable; } else { // // TopologyRefiner interpolation // // populate buffer with Far interpolated vertex data int lastLevel = refiner->GetMaxLevel(); Vertex * src = verts; for (int level = 1; level <= lastLevel; ++level) { Vertex * dst = src + refiner->GetLevel(level-1).GetNumVertices(); Far::PrimvarRefiner(*refiner).Interpolate(level, src, dst); src = dst; } //printf(" %f ms (interpolate)\n", float(s.GetElapsed())*1000.0f); //printf(" %f ms (total)\n", float(s.GetTotalElapsed())*1000.0f); // TODO: endpatch basis conversion comes here } s.Stop(); // // Misc display // //printf("Far time: %f ms (topology)\n", float(s.GetElapsed())*1000.0f); if (g_FarDrawVertIDs) { createVertNumbers(*refiner, vertexBuffer); } if (g_FarDrawFaceIDs) { createFaceNumbers(*refiner, vertexBuffer); } if (g_FarDrawPtexIDs and patchTable) { createPtexNumbers(*patchTable, vertexBuffer); } if (g_Adaptive) { createPatchNumbers(*patchTable, vertexBuffer); } if (g_Adaptive and g_FarDrawGregogyBasis) { createGregoryBasis(*patchTable, vertexBuffer); } if (g_Adaptive and createFVarWire) { createFVarPatches(*refiner, *patchTable, fvarBuffer); createFVarPatchNumbers(*patchTable, fvarBuffer); } createEdgeNumbers(*refiner, vertexBuffer, g_FarDrawEdgeIDs!=0, g_FarDrawEdgeSharpness!=0); GLMesh::Options options; options.vertColorMode=g_Adaptive ? GLMesh::VERTCOLOR_BY_LEVEL : GLMesh::VERTCOLOR_BY_SHARPNESS; options.edgeColorMode=g_Adaptive ? GLMesh::EDGECOLOR_BY_PATCHTYPE : GLMesh::EDGECOLOR_BY_SHARPNESS; options.faceColorMode=g_Adaptive ? GLMesh::FACECOLOR_BY_PATCHTYPE :GLMesh::FACECOLOR_SOLID; g_far_glmesh.Initialize(options, *refiner, patchTable, (float *)&verts[0]); if (g_Adaptive) { g_far_glmesh.SetDiffuseColor(1.0f, 1.0f, 1.0f, 1.0f); } else { g_far_glmesh.SetDiffuseColor(0.75f, 0.9f, 1.0f, 1.0f); } //setFaceColors(*refiner); g_far_glmesh.InitializeDeviceBuffers(); // save coarse topology (used for control mesh display) g_controlMeshDisplay.SetTopology(refiner->GetLevel(0)); // save coarse points in a GPU buffer (used for control mesh display) if (not g_controlMeshDisplayVBO) { glGenBuffers(1, &g_controlMeshDisplayVBO); } glBindBuffer(GL_ARRAY_BUFFER, g_controlMeshDisplayVBO); glBufferData(GL_ARRAY_BUFFER, 3*sizeof(float)*vertexBuffer.size(), (GLfloat*)&vertexBuffer[0], GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); // compute model bounds float min[3] = { FLT_MAX, FLT_MAX, FLT_MAX}; float max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; for (size_t i=0; i <vertexBuffer.size(); ++i) { for(int j=0; j<3; ++j) { float v = vertexBuffer[i].GetPos()[j]; min[j] = std::min(min[j], v); max[j] = std::max(max[j], v); } } for (int j=0; j<3; ++j) { g_center[j] = (min[j] + max[j]) * 0.5f; g_size += (max[j]-min[j])*(max[j]-min[j]); } g_size = sqrtf(g_size); delete refiner; delete patchTable; }
//------------------------------------------------------------------------------ int main(int, char **) { // Generate some FarTopologyRefiner (see far_tutorial_0 for details). Far::TopologyRefiner * refiner = createTopologyRefiner(); // Uniformly refine the topolgy up to 'maxlevel'. int maxlevel = 4; refiner->RefineUniform(Far::TopologyRefiner::UniformOptions(maxlevel)); int nverts = refiner->GetLevel(maxlevel).GetNumVertices(); // Use the Far::StencilTable factory to create discrete stencil table Far::StencilTableFactory::Options options; options.generateIntermediateLevels=false; // only the highest refinement level. options.generateOffsets=true; // // Vertex primvar data // // Create stencils table for 'vertex' interpolation options.interpolationMode=Far::StencilTableFactory::INTERPOLATE_VERTEX; Far::StencilTable const * vertexStencils = Far::StencilTableFactory::Create(*refiner, options); assert(nverts==vertexStencils->GetNumStencils()); // Allocate vertex primvar buffer (1 stencil for each vertex) std::vector<Vertex> vertexBuffer(vertexStencils->GetNumStencils()); // Use the cube vertex positions as 'vertex' primvar data Vertex * vertexCVs = reinterpret_cast<Vertex *>(g_verts); // // Varying primvar data // // Create stencils table for 'varying' interpolation options.interpolationMode=Far::StencilTableFactory::INTERPOLATE_VARYING; Far::StencilTable const * varyingStencils = Far::StencilTableFactory::Create(*refiner, options); assert(nverts==varyingStencils->GetNumStencils()); // Allocate varying primvar buffer (1 stencil for each vertex) std::vector<Vertex> varyingBuffer(varyingStencils->GetNumStencils()); // Use the a per-vertex array of RGB colors as 'varying' primvar data Vertex * varyingCVs = reinterpret_cast<Vertex *>(g_colors); delete refiner; // // Apply stencils (in frame loop) // { // This section would be applied every frame after control vertices have // been moved. // Apply stencils on the control vertex data to update the primvar data // of the refined vertices. vertexStencils->UpdateValues(vertexCVs, &vertexBuffer[0]); varyingStencils->UpdateValues(varyingCVs, &varyingBuffer[0]); } { // Visualization with Maya : print a MEL script that generates particles // at the location of the refined vertices printf("particle "); for (int vert=0; vert<(int)nverts; ++vert) { float const * pos = vertexBuffer[vert].GetData(); printf("-p %f %f %f\n", pos[0], pos[1], pos[2]); } printf("-c 1;\n"); // Set particle point size (20 -- very large) printf("addAttr -is true -ln \"pointSize\" -at long -dv 20 particleShape1;\n"); // Add per-particle color attribute ('rgbPP') printf("addAttr -ln \"rgbPP\" -dt vectorArray particleShape1;\n"); // Set per-particle color values from our 'varying' primvar data printf("setAttr \"particleShape1.rgbPP\" -type \"vectorArray\" %d ", nverts); for (int vert=0; vert<nverts; ++vert) { float const * color = varyingBuffer[vert].GetData(); printf("%f %f %f\n", color[0], color[1], color[2]); } printf(";\n"); } delete vertexStencils; delete varyingStencils; }
//------------------------------------------------------------------------------ int main(int, char **) { int maxlevel = 3; typedef Far::TopologyRefinerFactoryBase::TopologyDescriptor Descriptor; Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK; Sdc::Options options; options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY); options.SetFVarLinearInterpolation(Sdc::Options::FVAR_LINEAR_NONE); // Populate a topology descriptor with our raw data Descriptor desc; desc.numVertices = g_nverts; desc.numFaces = g_nfaces; desc.numVertsPerFace = g_vertsperface; desc.vertIndicesPerFace = g_vertIndices; // Create a face-varying channel descriptor Descriptor::FVarChannel uvs; uvs.numValues = g_nuvs; uvs.valueIndices = g_uvIndices; // Add the channel topology to the main descriptor desc.numFVarChannels = 1; desc.fvarChannels = & uvs; // Instantiate a FarTopologyRefiner from the descriptor Far::TopologyRefiner * refiner = Far::TopologyRefinerFactory<Descriptor>::Create(desc, Far::TopologyRefinerFactory<Descriptor>::Options(type, options)); // Uniformly refine the topolgy up to 'maxlevel' // note: fullTopologyInLastLevel must be true to work with face-varying data { Far::TopologyRefiner::UniformOptions options(maxlevel); options.fullTopologyInLastLevel = true; refiner->RefineUniform(options); } // Allocate & interpolate the 'vertex' primvar data (see tutorial 2 for // more details). std::vector<Vertex> vbuffer(refiner->GetNumVerticesTotal()); Vertex * verts = &vbuffer[0]; int nCoarseVerts = g_nverts; for (int i=0; i<nCoarseVerts; ++i) { verts[i].SetPosition(g_verts[i][0], g_verts[i][1], g_verts[i][2]); } refiner->Interpolate(verts, verts + nCoarseVerts); // Allocate & interpolate the 'face-varying' primvar data int channel = 0, nCoarseFVVerts = refiner->GetNumFVarValues(0, channel); std::vector<FVarVertex> fvBuffer(refiner->GetNumFVarValuesTotal(channel)); FVarVertex * fvVerts = &fvBuffer[0]; for (int i=0; i<g_nuvs; ++i) { fvVerts[i].u = g_uvs[i][0]; fvVerts[i].v = g_uvs[i][1]; } refiner->InterpolateFaceVarying(fvVerts, fvVerts + nCoarseFVVerts, channel); { // Output OBJ of the highest level refined ----------- // Print vertex positions for (int level=0, firstVert=0; level<=maxlevel; ++level) { if (level==maxlevel) { for (int vert=0; vert<refiner->GetNumVertices(level); ++vert) { float const * pos = verts[firstVert+vert].GetPosition(); printf("v %f %f %f\n", pos[0], pos[1], pos[2]); } } else { firstVert += refiner->GetNumVertices(level); } } // Print uvs for (int level=0, firstVert=0; level<=maxlevel; ++level) { if (level==maxlevel) { for (int vert=0; vert<refiner->GetNumFVarValues(level, channel); ++vert) { FVarVertex const & uv = fvVerts[firstVert+vert]; printf("vt %f %f\n", uv.u, uv.v); } } else { firstVert += refiner->GetNumFVarValues(level, channel); } } // Print faces for (int face=0; face<refiner->GetNumFaces(maxlevel); ++face) { Far::ConstIndexArray fverts = refiner->GetFaceVertices(maxlevel, face), fvverts = refiner->GetFVarFaceValues(maxlevel, face, channel); // all refined Catmark faces should be quads assert(fverts.size()==4 and fvverts.size()==4); printf("f "); for (int vert=0; vert<fverts.size(); ++vert) { // OBJ uses 1-based arrays... printf("%d/%d ", fverts[vert]+1, fvverts[vert]+1); } printf("\n"); } } }
inline bool TopologyRefinerFactory<PXR_NS::Converter>::assignComponentTags( Far::TopologyRefiner & refiner, PXR_NS::Converter const & converter) { PXR_NAMESPACE_USING_DIRECTIVE PxOsdMeshTopology const & topology = converter.topology; PxOsdSubdivTags const & tags = topology.GetSubdivTags(); // // creases // // The sharpnesses can be defined either per-crease or per-edge. VtIntArray const creaseIndices = tags.GetCreaseIndices(), creaseLengths = tags.GetCreaseLengths(); VtFloatArray const creaseWeights = tags.GetCreaseWeights(); size_t numCreaseSets = creaseLengths.size(); bool perEdgeCrease = creaseWeights.size() != numCreaseSets; if (perEdgeCrease) { // validate per-edge crease. int numEdges = 0; for (size_t i = 0; i < numCreaseSets; ++i) { numEdges += creaseLengths[i] - 1; } if (creaseWeights.size() != static_cast<size_t>(numEdges)) { TF_WARN("Invalid length of crease sharpnesses (%s)\n", converter.name.GetText()); numCreaseSets = 0; } } for (size_t i=0, cindex=0, sindex=0; i < numCreaseSets; ++i) { int numSegments = creaseLengths[i] - 1; for (int j = 0; j < numSegments; ++j) { int v0 = creaseIndices[cindex+j], v1 = creaseIndices[cindex+j+1]; OpenSubdiv::Vtr::Index edge = refiner.GetLevel(0).FindEdge(v0, v1); if (edge==OpenSubdiv::Vtr::INDEX_INVALID) { TF_WARN("Set edge sharpness cannot find edge (%d-%d) (%s)", v0, v1, converter.name.GetText()); } else { setBaseEdgeSharpness(refiner, edge, std::max(0.0f, creaseWeights[sindex])); } if (perEdgeCrease) ++sindex; } if (!perEdgeCrease) ++sindex; cindex += creaseLengths[i]; } // // corners // VtIntArray const cornerIndices = tags.GetCornerIndices(); VtFloatArray const cornerWeights = tags.GetCornerWeights(); size_t numCorners = cornerIndices.size(); if (cornerWeights.size() != numCorners) { TF_WARN("Invalid length of corner sharpnesses at prim %s\n", converter.name.GetText()); numCorners = 0; } for (size_t i=0; i < numCorners; ++i) { int vert = cornerIndices[i]; if (vert >= 0 && vert < refiner.GetLevel(0).GetNumVertices()) { setBaseVertexSharpness(refiner, vert, std::max(0.0f, cornerWeights[i])); } else { TF_WARN("Set vertex sharpness cannot find vertex (%d) (%s)", vert, converter.name.GetText()); } } // // holes // VtIntArray const holeIndices = tags.GetHoleIndices(); int numHoles = holeIndices.size(); for (int i=0; i < numHoles; ++i) { int face = holeIndices[i]; if (face >= 0 && face < refiner.GetLevel(0).GetNumFaces()) { setBaseFaceHole(refiner, face, true); } else { TF_WARN("Set hole cannot find face (%d) (%s)", face, converter.name.GetText()); } } return true; }
//------------------------------------------------------------------------------ static void createOsdMesh(ShapeDesc const & shapeDesc, int level) { Shape * shape = Shape::parseObj(shapeDesc.data.c_str(), shapeDesc.scheme); // create Far mesh (topology) OpenSubdiv::Sdc::SchemeType sdctype = GetSdcType(*shape); OpenSubdiv::Sdc::Options sdcoptions = GetSdcOptions(*shape); Far::TopologyRefiner *topologyRefiner = OpenSubdiv::Far::TopologyRefinerFactory<Shape>::Create(*shape, OpenSubdiv::Far::TopologyRefinerFactory<Shape>::Options(sdctype, sdcoptions)); g_orgPositions=shape->verts; g_positions.resize(g_orgPositions.size(), 0.0f); delete shape; float speed = g_particles ? g_particles->GetSpeed() : 0.2f; // save coarse topology (used for coarse mesh drawing) g_controlMeshDisplay.SetTopology(topologyRefiner->GetLevel(0)); // create random varying color { int numCoarseVerts = topologyRefiner->GetLevel(0).GetNumVertices(); g_varyingColors.resize(numCoarseVerts*3); createRandomColors(numCoarseVerts, 3, &g_varyingColors[0]); } Far::StencilTable const * vertexStencils = NULL; Far::StencilTable const * varyingStencils = NULL; int nverts=0; { bool adaptive = (sdctype == OpenSubdiv::Sdc::SCHEME_CATMARK); if (adaptive) { // Apply feature adaptive refinement to the mesh so that we can use the // limit evaluation API features. Far::TopologyRefiner::AdaptiveOptions options(level); topologyRefiner->RefineAdaptive(options); } else { Far::TopologyRefiner::UniformOptions options(level); topologyRefiner->RefineUniform(options); } // Generate stencil table to update the bi-cubic patches control // vertices after they have been re-posed (both for vertex & varying // interpolation) Far::StencilTableFactory::Options soptions; soptions.generateOffsets=true; soptions.generateIntermediateLevels=adaptive; vertexStencils = Far::StencilTableFactory::Create(*topologyRefiner, soptions); soptions.interpolationMode = Far::StencilTableFactory::INTERPOLATE_VARYING; varyingStencils = Far::StencilTableFactory::Create(*topologyRefiner, soptions); // Generate bi-cubic patch table for the limit surface Far::PatchTableFactory::Options poptions; if (g_endCap == kEndCapBSplineBasis) { poptions.SetEndCapType( Far::PatchTableFactory::Options::ENDCAP_BSPLINE_BASIS); } else { poptions.SetEndCapType( Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS); } Far::PatchTable const * patchTable = Far::PatchTableFactory::Create(*topologyRefiner, poptions); // append local points stencils if (Far::StencilTable const *localPointStencilTable = patchTable->GetLocalPointStencilTable()) { Far::StencilTable const *table = Far::StencilTableFactory::AppendLocalPointStencilTable( *topologyRefiner, vertexStencils, localPointStencilTable); delete vertexStencils; vertexStencils = table; } if (Far::StencilTable const *localPointVaryingStencilTable = patchTable->GetLocalPointVaryingStencilTable()) { Far::StencilTable const *table = Far::StencilTableFactory::AppendLocalPointStencilTable( *topologyRefiner, varyingStencils, localPointVaryingStencilTable); delete varyingStencils; varyingStencils = table; } // total number of vertices = coarse verts + refined verts + gregory basis verts nverts = vertexStencils->GetNumControlVertices() + vertexStencils->GetNumStencils(); if (g_patchTable) delete g_patchTable; g_patchTable = patchTable; } // note that for patch eval we need coarse+refined combined buffer. int nCoarseVertices = topologyRefiner->GetLevel(0).GetNumVertices(); // In following template instantiations, same type of vertex buffers are // used for both source and destination (first and second template // parameters), since we'd like to draw control mesh wireframe too in // this example viewer. // If we don't need to draw the coarse control mesh, the src buffer doesn't // have to be interoperable to GL (it can be CpuVertexBuffer etc). delete g_evalOutput; if (g_kernel == kCPU) { g_evalOutput = new EvalOutput<Osd::CpuGLVertexBuffer, Osd::CpuGLVertexBuffer, Far::StencilTable, Osd::CpuPatchTable, Osd::CpuEvaluator> (vertexStencils, varyingStencils, nCoarseVertices, nverts, g_nParticles, g_patchTable); #ifdef OPENSUBDIV_HAS_OPENMP } else if (g_kernel == kOPENMP) { g_evalOutput = new EvalOutput<Osd::CpuGLVertexBuffer, Osd::CpuGLVertexBuffer, Far::StencilTable, Osd::CpuPatchTable, Osd::OmpEvaluator> (vertexStencils, varyingStencils, nCoarseVertices, nverts, g_nParticles, g_patchTable); #endif #ifdef OPENSUBDIV_HAS_TBB } else if (g_kernel == kTBB) { g_evalOutput = new EvalOutput<Osd::CpuGLVertexBuffer, Osd::CpuGLVertexBuffer, Far::StencilTable, Osd::CpuPatchTable, Osd::TbbEvaluator> (vertexStencils, varyingStencils, nCoarseVertices, nverts, g_nParticles, g_patchTable); #endif #ifdef OPENSUBDIV_HAS_CUDA } else if (g_kernel == kCUDA) { g_evalOutput = new EvalOutput<Osd::CudaGLVertexBuffer, Osd::CudaGLVertexBuffer, Osd::CudaStencilTable, Osd::CudaPatchTable, Osd::CudaEvaluator> (vertexStencils, varyingStencils, nCoarseVertices, nverts, g_nParticles, g_patchTable); #endif #ifdef OPENSUBDIV_HAS_OPENCL } else if (g_kernel == kCL) { static Osd::EvaluatorCacheT<Osd::CLEvaluator> clEvaluatorCache; g_evalOutput = new EvalOutput<Osd::CLGLVertexBuffer, Osd::CLGLVertexBuffer, Osd::CLStencilTable, Osd::CLPatchTable, Osd::CLEvaluator, CLDeviceContext> (vertexStencils, varyingStencils, nCoarseVertices, nverts, g_nParticles, g_patchTable, &clEvaluatorCache, &g_clDeviceContext); #endif #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK } else if (g_kernel == kGLXFB) { static Osd::EvaluatorCacheT<Osd::GLXFBEvaluator> glXFBEvaluatorCache; g_evalOutput = new EvalOutput<Osd::GLVertexBuffer, Osd::GLVertexBuffer, Osd::GLStencilTableTBO, Osd::GLPatchTable, Osd::GLXFBEvaluator> (vertexStencils, varyingStencils, nCoarseVertices, nverts, g_nParticles, g_patchTable, &glXFBEvaluatorCache); #endif #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE } else if (g_kernel == kGLCompute) { static Osd::EvaluatorCacheT<Osd::GLComputeEvaluator> glComputeEvaluatorCache; g_evalOutput = new EvalOutput<Osd::GLVertexBuffer, Osd::GLVertexBuffer, Osd::GLStencilTableSSBO, Osd::GLPatchTable, Osd::GLComputeEvaluator> (vertexStencils, varyingStencils, nCoarseVertices, nverts, g_nParticles, g_patchTable, &glComputeEvaluatorCache); #endif } // Create the 'uv particles' manager - this class manages the limit // location samples (ptex face index, (s,t) and updates them between frames. // Note: the number of limit locations can be entirely arbitrary delete g_particles; g_particles = new STParticles(*topologyRefiner, g_patchTable, g_nParticles, !g_randomStart); g_nParticles = g_particles->GetNumParticles(); g_particles->SetSpeed(speed); g_prevTime = -1; g_currentTime = 0; updateGeom(); delete topologyRefiner; }
//------------------------------------------------------------------------------ int main(int, char **) { int maxlevel = 5; Far::TopologyRefiner * refiner = createFarTopologyRefiner(); // Uniformly refine the topolgy up to 'maxlevel' refiner->RefineUniform( maxlevel ); // Allocate a buffer for vertex primvar data. The buffer length is set to // be the sum of all children vertices up to the highest level of refinement. std::vector<Vertex> vbuffer(refiner->GetNumVerticesTotal()); Vertex * verts = &vbuffer[0]; // Initialize coarse mesh primvar data int nCoarseVerts = g_nverts; for (int i=0; i<nCoarseVerts; ++i) { verts[i].SetPosition(g_verts[i][0], g_verts[i][1], g_verts[i][2]); verts[i].SetColor(g_colors[i][0], g_colors[i][1], g_colors[i][2]); } // Interpolate all primvar data - not that this will perform both 'vertex' and // 'varying' interpolation at once by calling each specialized method in our // Vertex class with the appropriate weights. refiner->Interpolate(verts, verts + nCoarseVerts); { // Visualization with Maya : print a MEL script that generates colored // particles at the location of the refined vertices (don't forget to // turn shading on in the viewport to see the colors) int nverts = refiner->GetNumVertices(maxlevel); // Position the 'verts' pointer to the first vertex of our 'maxlevel' level for (int level=0; level<maxlevel; ++level) { verts += refiner->GetNumVertices(level); } // Output particle positions printf("particle "); for (int vert=0; vert<nverts; ++vert) { float const * pos = verts[vert].GetPosition(); printf("-p %f %f %f\n", pos[0], pos[1], pos[2]); } printf(";\n"); // Set particle point size (20 -- very large) printf("addAttr -is true -ln \"pointSize\" -at long -dv 20 particleShape1;\n"); // Add per-particle color attribute ('rgbPP') printf("addAttr -ln \"rgbPP\" -dt vectorArray particleShape1;\n"); // Set per-particle color values from our 'varying' primvar data printf("setAttr \"particleShape1.rgbPP\" -type \"vectorArray\" %d ", nverts); for (int vert=0; vert<nverts; ++vert) { float const * color = verts[vert].GetColor(); printf("%f %f %f\n", color[0], color[1], color[2]); } printf(";\n"); } }