//------------------------------------------------------------------------------ static void createVtrMesh(Shape * shape, int maxlevel) { Stopwatch s; s.Start(); // create Vtr mesh (topology) OpenSubdiv::Sdc::Type sdctype = GetSdcType(*shape); OpenSubdiv::Sdc::Options sdcoptions = GetSdcOptions(*shape); OpenSubdiv::Far::TopologyRefiner * refiner = OpenSubdiv::Far::TopologyRefinerFactory<Shape>::Create(sdctype, sdcoptions, *shape); OpenSubdiv::Far::PatchTables * patchTables = 0; if (g_Adaptive) { refiner->RefineAdaptive(maxlevel, /*fullTopology*/true); patchTables = OpenSubdiv::Far::PatchTablesFactory::Create(*refiner); g_numPatches = patchTables->GetNumPatches(); } else { refiner->RefineUniform(maxlevel, /*fullTopology*/true); } s.Stop(); // create vertex primvar data buffer std::vector<Vertex> vertexBuffer(refiner->GetNumVerticesTotal()); Vertex * verts = &vertexBuffer[0]; //printf("Vtr time: %f ms (topology)\n", float(s.GetElapsed())*1000.0f); // 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]); } //#define no_stencils #ifdef no_stencils { s.Start(); // populate buffer with Vtr interpolated vertex data refiner->Interpolate(verts, verts + ncoarseverts); s.Stop(); //printf(" %f ms (interpolate)\n", float(s.GetElapsed())*1000.0f); //printf(" %f ms (total)\n", float(s.GetTotalElapsed())*1000.0f); } #else { OpenSubdiv::Far::StencilTablesFactory::Options options; options.generateOffsets=true; options.generateAllLevels=true; options.sortBySize=false; OpenSubdiv::Far::StencilTables const * stencilTables = OpenSubdiv::Far::StencilTablesFactory::Create(*refiner, options); stencilTables->UpdateValues(verts, verts + ncoarseverts); } #endif if (g_VtrDrawVertIDs) { createVertNumbers(*refiner, vertexBuffer); } if (g_VtrDrawFaceIDs) { createFaceNumbers(*refiner, vertexBuffer); } if (g_VtrDrawPtexIDs and patchTables) { createPtexNumbers(*patchTables, vertexBuffer); } if (g_Adaptive and patchTables) { createPatchNumbers(*patchTables, vertexBuffer); } createEdgeNumbers(*refiner, vertexBuffer, g_VtrDrawEdgeIDs!=0, g_VtrDrawEdgeSharpness!=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; if (g_Adaptive) { g_vtr_glmesh.Initialize(options, *refiner, patchTables, (float *)&verts[0]); g_vtr_glmesh.SetDiffuseColor(1.0f, 1.0f, 1.0f, 1.0f); } else { g_vtr_glmesh.Initialize(options, *refiner, patchTables, (float *)&verts[0]); g_vtr_glmesh.SetDiffuseColor(0.75f, 0.9f, 1.0f, 1.0f); } //setFaceColors(*refiner); g_vtr_glmesh.InitializeDeviceBuffers(); delete refiner; delete patchTables; }
//------------------------------------------------------------------------------ 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; }
//------------------------------------------------------------------------------ static void createHbrMesh(Shape * shape, int maxlevel) { Stopwatch s; s.Start(); // create Hbr mesh using functions from hbr_utils Hmesh * hmesh = createMesh<Vertex>(shape->scheme, /*fvarwidth*/ 0); createVerticesWithPositions<Vertex>(shape, hmesh); createTopology<Vertex>(shape, hmesh, shape->scheme); s.Stop(); std::vector<Hface const *> coarseFaces, // list of Hbr coarse faces refinedFaces; // list of Hbr faces refined at maxlevel int nfaces = hmesh->GetNumFaces(); { // create control cage GL mesh coarseFaces.resize(nfaces); for (int i=0; i<nfaces; ++i) { coarseFaces[i] = hmesh->GetFace(i); } GLMesh::Options coarseOptions; coarseOptions.vertColorMode=GLMesh::VERTCOLOR_BY_SHARPNESS; coarseOptions.edgeColorMode=GLMesh::EDGECOLOR_BY_SHARPNESS; coarseOptions.faceColorMode=GLMesh::FACECOLOR_SOLID; g_base_glmesh.Initialize(coarseOptions, coarseFaces); g_base_glmesh.InitializeDeviceBuffers(); } { // create maxlevel refined GL mesh s.Start(); OpenSubdiv::Far::PatchTables const * patchTables = 0; if (g_Adaptive) { int maxvalence = RefineAdaptive(*hmesh, maxlevel, refinedFaces); patchTables = CreatePatchTables(*hmesh, maxvalence); patchTables->GetNumPatches(); delete patchTables; } else { RefineUniform(*hmesh, maxlevel, refinedFaces); } s.Stop(); //printf("Hbr time: %f ms\n", float(s.GetElapsed())*1000.0f); if (g_HbrDrawVertIDs) { createVertNumbers(refinedFaces); } // Hbr is a half-edge rep, so edges do not have unique IDs that // can be displayed if (g_HbrDrawEdgeSharpness) { createEdgeNumbers(refinedFaces); } if (g_HbrDrawFaceIDs) { createFaceNumbers(refinedFaces, /*ptex*/ false); } if (g_HbrDrawPtexIDs) { createFaceNumbers(refinedFaces, /*ptex*/ true); } GLMesh::Options refinedOptions; refinedOptions.vertColorMode=GLMesh::VERTCOLOR_BY_SHARPNESS; refinedOptions.edgeColorMode=GLMesh::EDGECOLOR_BY_SHARPNESS; refinedOptions.faceColorMode=GLMesh::FACECOLOR_SOLID; g_hbr_glmesh.Initialize(refinedOptions, refinedFaces); g_hbr_glmesh.SetDiffuseColor(1.0f,0.75f,0.9f, 1.0f); } g_hbr_glmesh.InitializeDeviceBuffers(); delete hmesh; }
static void createGregoryBasis(OpenSubdiv::Far::PatchTable const & patchTable, std::vector<Vertex> const & vertexBuffer) { typedef OpenSubdiv::Far::PatchDescriptor PatchDescriptor; int npatches = 0; int patchArray = 0; for (int array=0; array<(int)patchTable.GetNumPatchArrays(); ++array) { if (patchTable.GetPatchArrayDescriptor(array).GetType()== PatchDescriptor::GREGORY_BASIS) { npatches = patchTable.GetNumPatches(array); patchArray = array; break; } } int nedges = npatches * 20; std::vector<int> vertsperedge(nedges), edgeindices(nedges*2); for (int patch=0; patch<npatches; ++patch) { static int basisedges[40] = { 0, 1, 0, 2, 1, 3, 2, 4, 5, 6, 5, 7, 6, 8, 7, 9, 10, 11, 10, 12, 11, 13, 12, 14, 15, 16, 15, 17, 16, 18, 17, 19, 1, 7, 6, 12, 11, 17, 16, 2 }; int offset = patch * 20, * vpe = &vertsperedge[offset], * indices = &edgeindices[patch * 40]; OpenSubdiv::Far::ConstIndexArray const cvs = patchTable.GetPatchVertices(patchArray, patch); for (int i=0; i<20; ++i) { vpe[i] = 2; indices[i*2] = cvs[basisedges[i*2]]; indices[i*2+1] = cvs[basisedges[i*2+1]]; } //Vertex const * verts = &edgeverts[offset]; static char buf[16]; for (int i=0; i<4; ++i) { int vid = patch * 20 + i * 5; const float *P = vertexBuffer[cvs[i*5+0]].GetPos(); const float *Ep = vertexBuffer[cvs[i*5+1]].GetPos(); const float *Em = vertexBuffer[cvs[i*5+2]].GetPos(); const float *Fp = vertexBuffer[cvs[i*5+3]].GetPos(); const float *Fm = vertexBuffer[cvs[i*5+4]].GetPos(); snprintf(buf, 16, " P%d (%d)", i, vid); g_font->Print3D(P, buf, 3); snprintf(buf, 16, " Ep%d (%d)", i, vid+1); g_font->Print3D(Ep, buf, 3); snprintf(buf, 16, " Em%d (%d)", i, vid+2); g_font->Print3D(Em, buf, 3); snprintf(buf, 16, " Fp%d (%d)", i, vid+3); g_font->Print3D(Fp, buf, 3); snprintf(buf, 16, " Fm%d (%d)", i, vid+4); g_font->Print3D(Fm, buf, 3); } } GLMesh::Options options; gregoryWire.Initialize(options, (int)vertexBuffer.size(), (int)vertsperedge.size(), &vertsperedge[0], &edgeindices[0], (float const *)&vertexBuffer[0]); }