//------------------------------------------------------------------------------ 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 **) { 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"); } } }