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