//------------------------------------------------------------------------------ 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 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; }