far_tutorial_3_1.cpp
System Message: WARNING/2 (/wrkdirs/usr/ports/graphics/opensubdiv/work/.build/documentation/far_tutorial_3_1.rst, line 9)
Cannot analyze code. Pygments package not found.
.. code:: c++ //------------------------------------------------------------------------------ // Tutorial description: // // This tutorial shows how to interface a high-level topology representation // with Far for better efficiency. In tutorial 0, we showed how to instantiate // topology from a simple face-vertex list. Here we will show how to take // advantage of more complex data structures. // // Many client applications that manipulate geometry use advanced data structures // such as half-edge, quad-edge or winged-edge in order to represent complex // topological relationships beyond the usual face-vertex lists. We can take // advantage of this information. // // Far provides an advanced interface that allows such a client application to // communicate advanced component relationships directly and avoid having Far // rebuilding them redundantly. // #include <opensubdiv/far/topologyRefinerFactory.h> #include <opensubdiv/far/primvarRefiner.h> #include <cstdio> //------------------------------------------------------------------------------ using namespace OpenSubdiv; //------------------------------------------------------------------------------ // // For this tutorial, we provide the complete topological representation of a // simple pyramid. In our case, we store it as a simple sequence of integers, // with the understanding that client-code would provide a fully implemented // data-structure such as quad-edges or winged-edges. // // Pyramid geometry from catmark_pyramid.h - extended for this tutorial // static int g_nverts = 5, g_nedges = 8, g_nfaces = 5; // vertex positions static float g_verts[5][3] = {{ 0.0f, 0.0f, 2.0f}, { 0.0f, -2.0f, 0.0f}, { 2.0f, 0.0f, 0.0f}, { 0.0f, 2.0f, 0.0f}, {-2.0f, 0.0f, 0.0f}}; // number of vertices in each face static int g_facenverts[5] = { 3, 3, 3, 3, 4 }; // index of face vertices static int g_faceverts[16] = { 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 1, 4, 3, 2, 1 }; // index of edge vertices (2 per edge) static int g_edgeverts[16] = { 0, 1, 1, 2, 2, 0, 2, 3, 3, 0, 3, 4, 4, 0, 4, 1 }; // index of face edges static int g_faceedges[16] = { 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 0, 5, 3, 1, 7 }; // number of faces adjacent to each edge static int g_edgenfaces[8] = { 2, 2, 2, 2, 2, 2, 2, 2 }; // index of faces incident to a given edge static int g_edgefaces[16] = { 0, 3, 0, 4, 0, 1, 1, 4, 1, 2, 2, 4, 2, 3, 3, 4 }; // number of faces incident to each vertex static int g_vertexnfaces[5] = { 4, 3, 3, 3, 3 }; // index of faces incident to each vertex static int g_vertexfaces[25] = { 0, 1, 2, 3, 0, 3, 4, 0, 4, 1, 1, 4, 2, 2, 4, 3 }; // number of edges incident to each vertex static int g_vertexnedges[5] = { 4, 3, 3, 3, 3 }; // index of edges incident to each vertex static int g_vertexedges[25] = { 0, 2, 4, 6, 1, 0, 7, 2, 1, 3, 4, 3, 5, 6, 5, 7 }; // Edge crease sharpness static float g_edgeCreases[8] = { 0.0f, 2.5f, 0.0f, 2.5f, 0.0f, 2.5f, 0.0f, 2.5f }; //------------------------------------------------------------------------------ // // Because existing client-code may not provide an exact match for the // topological queries required by Far's interface, we can provide a converter // class. This can be particularly useful for instance if the client // data-structure requires additional relationships to be mapped. For instance, // half-edge representations do not store unique edge indices and it can be // difficult to traverse edges or faces adjacent to a given vertex. // // Using an intermediate wrapper class allows us to leverage existing // relationships information from a mesh, and generate the missing components // temporarily. // // For a practical example, you can look at the file 'hbr_to_vtr.h' in the same // tutorial directory. This example implements a 'OsdHbrConverter' class as a // way of interfacing PRman's half-edge representation to Far. // struct Converter { public: Sdc::SchemeType GetType() const { return Sdc::SCHEME_CATMARK; } Sdc::Options GetOptions() const { Sdc::Options options; options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY); return options; } int GetNumFaces() const { return g_nfaces; } int GetNumEdges() const { return g_nedges; } int GetNumVertices() const { return g_nverts; } // // Face relationships // int GetNumFaceVerts(int face) const { return g_facenverts[face]; } int const * GetFaceVerts(int face) const { return g_faceverts+getCompOffset(g_facenverts, face); } int const * GetFaceEdges(int face) const { return g_faceedges+getCompOffset(g_facenverts, face); } // // Edge relationships // int const * GetEdgeVertices(int edge) const { return g_edgeverts+edge*2; } int GetNumEdgeFaces(int edge) const { return g_edgenfaces[edge]; } int const * GetEdgeFaces(int edge) const { return g_edgefaces+getCompOffset(g_edgenfaces, edge); } // // Vertex relationships // int GetNumVertexEdges(int vert) const { return g_vertexnedges[vert]; } int const * GetVertexEdges(int vert) const { return g_vertexedges+getCompOffset(g_vertexnedges, vert); } int GetNumVertexFaces(int vert) const { return g_vertexnfaces[vert]; } int const * GetVertexFaces(int vert) const { return g_vertexfaces+getCompOffset(g_vertexnfaces, vert); } private: int getCompOffset(int const * comps, int comp) const { int ofs=0; for (int i=0; i<comp; ++i) { ofs += comps[i]; } return ofs; } }; //------------------------------------------------------------------------------ namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { namespace Far { template <> bool TopologyRefinerFactory<Converter>::resizeComponentTopology( TopologyRefiner & refiner, Converter const & conv) { // Faces and face-verts int nfaces = conv.GetNumFaces(); setNumBaseFaces(refiner, nfaces); for (int face=0; face<nfaces; ++face) { int nv = conv.GetNumFaceVerts(face); setNumBaseFaceVertices(refiner, face, nv); } // Edges and edge-faces int nedges = conv.GetNumEdges(); setNumBaseEdges(refiner, nedges); for (int edge=0; edge<nedges; ++edge) { int nf = conv.GetNumEdgeFaces(edge); setNumBaseEdgeFaces(refiner, edge, nf); } // Vertices and vert-faces and vert-edges int nverts = conv.GetNumVertices(); setNumBaseVertices(refiner, nverts); for (int vert=0; vert<nverts; ++vert) { int ne = conv.GetNumVertexEdges(vert), nf = conv.GetNumVertexFaces(vert); setNumBaseVertexEdges(refiner, vert, ne); setNumBaseVertexFaces(refiner, vert, nf); } return true; } template <> bool TopologyRefinerFactory<Converter>::assignComponentTopology( TopologyRefiner & refiner, Converter const & conv) { using Far::IndexArray; { // Face relations: int nfaces = conv.GetNumFaces(); for (int face=0; face<nfaces; ++face) { IndexArray dstFaceVerts = getBaseFaceVertices(refiner, face); IndexArray dstFaceEdges = getBaseFaceEdges(refiner, face); int const * faceverts = conv.GetFaceVerts(face); int const * faceedges = conv.GetFaceEdges(face); for (int vert=0; vert<conv.GetNumFaceVerts(face); ++vert) { dstFaceVerts[vert] = faceverts[vert]; dstFaceEdges[vert] = faceedges[vert]; } } } { // Edge relations // // Note: if your representation is unable to provide edge relationships // (ex: half-edges), you can comment out this section and Far will // automatically generate the missing information. // int nedges = conv.GetNumEdges(); for (int edge=0; edge<nedges; ++edge) { // Edge-vertices: IndexArray dstEdgeVerts = getBaseEdgeVertices(refiner, edge); dstEdgeVerts[0] = conv.GetEdgeVertices(edge)[0]; dstEdgeVerts[1] = conv.GetEdgeVertices(edge)[1]; // Edge-faces IndexArray dstEdgeFaces = getBaseEdgeFaces(refiner, edge); for (int face=0; face<conv.GetNumEdgeFaces(face); ++face) { dstEdgeFaces[face] = conv.GetEdgeFaces(edge)[face]; } } } { // Vertex relations int nverts = conv.GetNumVertices(); for (int vert=0; vert<nverts; ++vert) { // Vert-Faces: IndexArray vertFaces = getBaseVertexFaces(refiner, vert); //LocalIndexArray vertInFaceIndices = getBaseVertexFaceLocalIndices(refiner, vert); for (int face=0; face<conv.GetNumVertexFaces(vert); ++face) { vertFaces[face] = conv.GetVertexFaces(vert)[face]; } // Vert-Edges: IndexArray vertEdges = getBaseVertexEdges(refiner, vert); //LocalIndexArray vertInEdgeIndices = getBaseVertexEdgeLocalIndices(refiner, vert); for (int edge=0; edge<conv.GetNumVertexEdges(vert); ++edge) { vertEdges[edge] = conv.GetVertexEdges(vert)[edge]; } } } populateBaseLocalIndices(refiner); return true; }; template <> bool TopologyRefinerFactory<Converter>::assignComponentTags( TopologyRefiner & refiner, Converter const & conv) { // arbitrarily sharpen the 4 bottom edges of the pyramid to 2.5f for (int edge=0; edge<conv.GetNumEdges(); ++edge) { setBaseEdgeSharpness(refiner, edge, g_edgeCreases[edge]); } return true; } #ifdef _MSC_VER template <> void TopologyRefinerFactory<Converter>::reportInvalidTopology( TopologyError /* errCode */, char const * msg, Converter const& /* mesh */) { // // Optional topology validation error reporting: // This method is called whenever the factory encounters topology validation // errors. By default, nothing is reported // Warning(msg); } template <> bool TopologyRefinerFactory<Converter>::assignFaceVaryingTopology( TopologyRefiner & /* refiner */, Converter const & /* conv */) { // Because of the way MSVC++ specializes templated functions, we had to // remove the default stubs in Far::TopologyRefinerFactory. In this // example, no face-varying data is being added, but we still need to // implement a template specialization or MSVC++ linker fails. return true; } #endif } // namespace Far } // namespace OPENSUBDIV_VERSION } // namespace OpenSubdiv //------------------------------------------------------------------------------ // // Vertex container implementation. // struct Vertex { // Minimal required interface ---------------------- Vertex() { } Vertex(Vertex const & src) { _position[0] = src._position[0]; _position[1] = src._position[1]; _position[2] = src._position[2]; } void Clear( void * =0 ) { _position[0]=_position[1]=_position[2]=0.0f; } void AddWithWeight(Vertex const & src, float weight) { _position[0]+=weight*src._position[0]; _position[1]+=weight*src._position[1]; _position[2]+=weight*src._position[2]; } // Public interface ------------------------------------ void SetPosition(float x, float y, float z) { _position[0]=x; _position[1]=y; _position[2]=z; } const float * GetPosition() const { return _position; } private: float _position[3]; }; //------------------------------------------------------------------------------ int main(int, char **) { Converter conv; Far::TopologyRefiner * refiner = Far::TopologyRefinerFactory<Converter>::Create(conv, Far::TopologyRefinerFactory<Converter>::Options(conv.GetType(), conv.GetOptions())); int maxlevel = 5; // Uniformly refine the topology up to 'maxlevel' refiner->RefineUniform(Far::TopologyRefiner::UniformOptions(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 positions 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]); } // Interpolate vertex primvar data Far::PrimvarRefiner primvarRefiner(*refiner); Vertex * src = verts; for (int level = 1; level <= maxlevel; ++level) { Vertex * dst = src + refiner->GetLevel(level-1).GetNumVertices(); primvarRefiner.Interpolate(level, src, dst); src = dst; } { // Output OBJ of the highest level refined ----------- Far::TopologyLevel const & refLastLevel = refiner->GetLevel(maxlevel); int nverts = refLastLevel.GetNumVertices(); int nfaces = refLastLevel.GetNumFaces(); // Print vertex positions int firstOfLastVerts = refiner->GetNumVerticesTotal() - nverts; for (int vert = 0; vert < nverts; ++vert) { float const * pos = verts[firstOfLastVerts + vert].GetPosition(); printf("v %f %f %f\n", pos[0], pos[1], pos[2]); } // Print faces for (int face = 0; face < nfaces; ++face) { Far::ConstIndexArray fverts = refLastLevel.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]+1); // OBJ uses 1-based arrays... } printf("\n"); } } delete refiner; return EXIT_SUCCESS; } //------------------------------------------------------------------------------
Generated on: 2025-03-29 14:11 UTC.