# far_tutorial_2_2.cpp

https://github.com/PixarAnimationStudios/OpenSubdiv/blob/release/tutorials/far/tutorial_2_2/far_tutorial_2_2.cpp

System Message: WARNING/2 (`/build/opensubdiv/src/OpenSubdiv-3_6_1/build/documentation/far_tutorial_2_2.rst`, line 9)

Cannot analyze code. Pygments package not found.

    .. code:: c++

        //------------------------------------------------------------------------------
        // Tutorial description:
        //
        // Building on tutorial 0, this example shows how to instantiate a simple mesh,
        // refine it uniformly and then interpolate both 'vertex' and 'face-varying'
        // primvar data.
        // The resulting interpolated data is output as an 'obj' file, with the
        // 'face-varying' data recorded in the uv texture layout.
        //

        #include <opensubdiv/far/topologyDescriptor.h>
        #include <opensubdiv/far/primvarRefiner.h>

        #include <cstdio>

        //------------------------------------------------------------------------------
        // Face-varying 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];
        };

        //------------------------------------------------------------------------------
        // Face-varying container implementation.
        //
        // We are using a uv texture layout as a 'face-varying' primitive variable
        // attribute. Because face-varying data is specified 'per-face-per-vertex',
        // we cannot use the same container that we use for 'vertex' or 'varying'
        // data. We specify a new container, which only carries (u,v) coordinates.
        // Similarly to our 'Vertex' container, we add a minimalistic interpolation
        // interface with a 'Clear()' and 'AddWithWeight()' methods.
        //
        struct FVarVertexUV {

            // Minimal required interface ----------------------
            void Clear() {
                u=v=0.0f;
            }

            void AddWithWeight(FVarVertexUV const & src, float weight) {
                u += weight * src.u;
                v += weight * src.v;
            }

            // Basic 'uv' layout channel
            float u,v;
        };

        struct FVarVertexColor {

            // Minimal required interface ----------------------
            void Clear() {
                r=g=b=a=0.0f;
            }

            void AddWithWeight(FVarVertexColor const & src, float weight) {
                r += weight * src.r;
                g += weight * src.g;
                b += weight * src.b;
                a += weight * src.a;
            }

            // Basic 'color' layout channel
            float r,g,b,a;
        };

        //------------------------------------------------------------------------------
        // Cube geometry from catmark_cube.h

        // 'vertex' primitive variable data & topology
        static float g_verts[8][3] = {{ -0.5f, -0.5f,  0.5f },
                                      {  0.5f, -0.5f,  0.5f },
                                      { -0.5f,  0.5f,  0.5f },
                                      {  0.5f,  0.5f,  0.5f },
                                      { -0.5f,  0.5f, -0.5f },
                                      {  0.5f,  0.5f, -0.5f },
                                      { -0.5f, -0.5f, -0.5f },
                                      {  0.5f, -0.5f, -0.5f }};
        static int g_nverts = 8,
                   g_nfaces = 6;

        static int g_vertsperface[6] = { 4, 4, 4, 4, 4, 4 };

        static int g_vertIndices[24] = { 0, 1, 3, 2,
                                         2, 3, 5, 4,
                                         4, 5, 7, 6,
                                         6, 7, 1, 0,
                                         1, 7, 5, 3,
                                         6, 0, 2, 4  };

        // 'face-varying' primitive variable data & topology for UVs
        static float g_uvs[14][2] = {{ 0.375, 0.00 },
                                     { 0.625, 0.00 },
                                     { 0.375, 0.25 },
                                     { 0.625, 0.25 },
                                     { 0.375, 0.50 },
                                     { 0.625, 0.50 },
                                     { 0.375, 0.75 },
                                     { 0.625, 0.75 },
                                     { 0.375, 1.00 },
                                     { 0.625, 1.00 },
                                     { 0.875, 0.00 },
                                     { 0.875, 0.25 },
                                     { 0.125, 0.00 },
                                     { 0.125, 0.25 }};

        static int g_nuvs = 14;

        static int g_uvIndices[24] = {  0,  1,  3,  2,
                                        2,  3,  5,  4,
                                        4,  5,  7,  6,
                                        6,  7,  9,  8,
                                        1, 10, 11,  3,
                                       12,  0,  2, 13  };

        // 'face-varying' primitive variable data & topology for color
        static float g_colors[24][4] = {{1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 0.0, 0.0, 1.0},
                                        {1.0, 0.0, 0.0, 1.0},
                                        {1.0, 0.0, 0.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0},
                                        {1.0, 1.0, 1.0, 1.0}};

        static int g_ncolors = 24;

        static int g_colorIndices[24] = { 0,  3,  9,  6,
                                          7, 10, 15, 12,
                                         13, 16, 21, 18,
                                         19, 22,  4,  1,
                                          5, 23, 17, 11,
                                         20,  2,  8, 14 };

        using namespace OpenSubdiv;

        //------------------------------------------------------------------------------
        int main(int, char **) {

            int maxlevel = 3;

            typedef Far::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;

            int channelUV = 0;
            int channelColor = 1;

            // Create a face-varying channel descriptor
            Descriptor::FVarChannel channels[2];
            channels[channelUV].numValues = g_nuvs;
            channels[channelUV].valueIndices = g_uvIndices;
            channels[channelColor].numValues = g_ncolors;
            channels[channelColor].valueIndices = g_colorIndices;

            // Add the channel topology to the main descriptor
            desc.numFVarChannels = 2;
            desc.fvarChannels = channels;

            // Instantiate a Far::TopologyRefiner from the descriptor
            Far::TopologyRefiner * refiner =
                Far::TopologyRefinerFactory<Descriptor>::Create(desc,
                    Far::TopologyRefinerFactory<Descriptor>::Options(type, options));

            // Uniformly refine the topology up to 'maxlevel'
            // note: fullTopologyInLastLevel must be true to work with face-varying data
            {
                Far::TopologyRefiner::UniformOptions refineOptions(maxlevel);
                refineOptions.fullTopologyInLastLevel = true;
                refiner->RefineUniform(refineOptions);
            }

            // Allocate and initialize the 'vertex' primvar data (see tutorial 2 for
            // more details).
            std::vector<Vertex> vbuffer(refiner->GetNumVerticesTotal());
            Vertex * verts = &vbuffer[0];

            for (int i=0; i<g_nverts; ++i) {
                verts[i].SetPosition(g_verts[i][0], g_verts[i][1], g_verts[i][2]);
            }

            // Allocate and initialize the first channel of 'face-varying' primvar data (UVs)
            std::vector<FVarVertexUV> fvBufferUV(refiner->GetNumFVarValuesTotal(channelUV));
            FVarVertexUV * fvVertsUV = &fvBufferUV[0];
            for (int i=0; i<g_nuvs; ++i) {
                fvVertsUV[i].u = g_uvs[i][0];
                fvVertsUV[i].v = g_uvs[i][1];
            }

            // Allocate & interpolate the 'face-varying' primvar data (colors)
            std::vector<FVarVertexColor> fvBufferColor(refiner->GetNumFVarValuesTotal(channelColor));
            FVarVertexColor * fvVertsColor = &fvBufferColor[0];
            for (int i=0; i<g_ncolors; ++i) {
                fvVertsColor[i].r = g_colors[i][0];
                fvVertsColor[i].g = g_colors[i][1];
                fvVertsColor[i].b = g_colors[i][2];
                fvVertsColor[i].a = g_colors[i][3];
            }

            // Interpolate both vertex and face-varying primvar data
            Far::PrimvarRefiner primvarRefiner(*refiner);

            Vertex *     srcVert = verts;
            FVarVertexUV * srcFVarUV = fvVertsUV;
            FVarVertexColor * srcFVarColor = fvVertsColor;

            for (int level = 1; level <= maxlevel; ++level) {
                Vertex *     dstVert = srcVert + refiner->GetLevel(level-1).GetNumVertices();
                FVarVertexUV * dstFVarUV = srcFVarUV + refiner->GetLevel(level-1).GetNumFVarValues(channelUV);
                FVarVertexColor * dstFVarColor = srcFVarColor + refiner->GetLevel(level-1).GetNumFVarValues(channelColor);

                primvarRefiner.Interpolate(level, srcVert, dstVert);
                primvarRefiner.InterpolateFaceVarying(level, srcFVarUV, dstFVarUV, channelUV);
                primvarRefiner.InterpolateFaceVarying(level, srcFVarColor, dstFVarColor, channelColor);

                srcVert = dstVert;
                srcFVarUV = dstFVarUV;
                srcFVarColor = dstFVarColor;
            }

            { // Output OBJ of the highest level refined -----------

                Far::TopologyLevel const & refLastLevel = refiner->GetLevel(maxlevel);

                int nverts = refLastLevel.GetNumVertices();
                int nuvs   = refLastLevel.GetNumFVarValues(channelUV);
                int ncolors= refLastLevel.GetNumFVarValues(channelColor);
                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 uvs
                int firstOfLastUvs = refiner->GetNumFVarValuesTotal(channelUV) - nuvs;

                for (int fvvert = 0; fvvert < nuvs; ++fvvert) {
                    FVarVertexUV const & uv = fvVertsUV[firstOfLastUvs + fvvert];
                    printf("vt %f %f\n", uv.u, uv.v);
                }

                // Print colors
                int firstOfLastColors = refiner->GetNumFVarValuesTotal(channelColor) - ncolors;

                for (int fvvert = 0; fvvert < ncolors; ++fvvert) {
                    FVarVertexColor const & c = fvVertsColor[firstOfLastColors + fvvert];
                    printf("c %f %f %f %f\n", c.r, c.g, c.b, c.a);
                }

                // Print faces
                for (int face = 0; face < nfaces; ++face) {

                    Far::ConstIndexArray fverts = refLastLevel.GetFaceVertices(face);
                    Far::ConstIndexArray fuvs   = refLastLevel.GetFaceFVarValues(face, channelUV);

                    // all refined Catmark faces should be quads
                    assert(fverts.size()==4 && fuvs.size()==4);

                    printf("f ");
                    for (int vert=0; vert<fverts.size(); ++vert) {
                        // OBJ uses 1-based arrays...
                        printf("%d/%d ", fverts[vert]+1, fuvs[vert]+1);
                    }
                    printf("\n");
                }
            }

            delete refiner;
            return EXIT_SUCCESS;
        }
        //------------------------------------------------------------------------------

- User Docs
- API Docs
- Release Notes
- Forum

TM & © 1986 - 2017 PIXAR. ALL RIGHTS RESERVED. Terms of Use