//------------------------------------------------------------------------------
static Far::TopologyRefiner const *
createTopologyRefiner(int maxlevel) {

    // Populate a topology descriptor with our raw data

    typedef Far::TopologyRefinerFactoryBase::TopologyDescriptor Descriptor;

    Sdc::Type type = OpenSubdiv::Sdc::TYPE_CATMARK;

    Sdc::Options options;
    options.SetVVarBoundaryInterpolation(Sdc::Options::VVAR_BOUNDARY_EDGE_ONLY);

    Descriptor desc;
    desc.numVertices  = g_nverts;
    desc.numFaces     = g_nfaces;
    desc.vertsPerFace = g_vertsperface;
    desc.vertIndices  = g_vertIndices;

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

    // Uniformly refine the topolgy up to 'maxlevel'
    refiner->RefineUniform( maxlevel );

    return refiner;
}
Пример #2
0
//------------------------------------------------------------------------------
static Far::TopologyRefiner *
createTopologyRefiner() {

    // Populate a topology descriptor with our raw data.

    typedef Far::TopologyDescriptor Descriptor;

    Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;

    Sdc::Options options;
    options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);

    Descriptor desc;
    desc.numVertices = g_nverts;
    desc.numFaces = g_nfaces;
    desc.numVertsPerFace = g_vertsperface;
    desc.vertIndicesPerFace = g_vertIndices;

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

    return refiner;
}
bool
TopologyRefinerFactoryBase::prepareComponentTagsAndSharpness(TopologyRefiner& refiner) {

    //
    //  This method combines the initialization of internal component tags with the sharpening
    //  of edges and vertices according to the given boundary interpolation rule in the Options.
    //  Since both involve traversing the edge and vertex lists and noting the presence of
    //  boundaries -- best to do both at once...
    //
    Vtr::internal::Level&  baseLevel = refiner.getLevel(0);

    Sdc::Options options = refiner.GetSchemeOptions();
    Sdc::Crease  creasing(options);

    bool makeBoundaryFacesHoles = (options.GetVtxBoundaryInterpolation() == Sdc::Options::VTX_BOUNDARY_NONE);
    bool sharpenCornerVerts     = (options.GetVtxBoundaryInterpolation() == Sdc::Options::VTX_BOUNDARY_EDGE_AND_CORNER);
    bool sharpenNonManFeatures  = true; //(options.GetNonManifoldInterpolation() == Sdc::Options::NON_MANIFOLD_SHARP);

    //
    //  Process the Edge tags first, as Vertex tags (notably the Rule) are dependent on
    //  properties of their incident edges.
    //
    for (Vtr::Index eIndex = 0; eIndex < baseLevel.getNumEdges(); ++eIndex) {
        Vtr::internal::Level::ETag& eTag       = baseLevel.getEdgeTag(eIndex);
        float&                      eSharpness = baseLevel.getEdgeSharpness(eIndex);

        eTag._boundary = (baseLevel.getNumEdgeFaces(eIndex) < 2);
        if (eTag._boundary || (eTag._nonManifold && sharpenNonManFeatures)) {
            eSharpness = Sdc::Crease::SHARPNESS_INFINITE;
        }
        eTag._infSharp  = Sdc::Crease::IsInfinite(eSharpness);
        eTag._semiSharp = Sdc::Crease::IsSharp(eSharpness) && !eTag._infSharp;
    }

    //
    //  Process the Vertex tags now -- for some tags (semi-sharp and its rule) we need
    //  to inspect all incident edges:
    //
    int schemeRegularInteriorValence = Sdc::SchemeTypeTraits::GetRegularVertexValence(refiner.GetSchemeType());
    int schemeRegularBoundaryValence = schemeRegularInteriorValence / 2;

    for (Vtr::Index vIndex = 0; vIndex < baseLevel.getNumVertices(); ++vIndex) {
        Vtr::internal::Level::VTag& vTag       = baseLevel.getVertexTag(vIndex);
        float&                      vSharpness = baseLevel.getVertexSharpness(vIndex);

        Vtr::ConstIndexArray vEdges = baseLevel.getVertexEdges(vIndex);
        Vtr::ConstIndexArray vFaces = baseLevel.getVertexFaces(vIndex);

        //
        //  Take inventory of properties of incident edges that affect this vertex:
        //
        int boundaryEdgeCount    = 0;
        int infSharpEdgeCount    = 0;
        int semiSharpEdgeCount   = 0;
        int nonManifoldEdgeCount = 0;
        for (int i = 0; i < vEdges.size(); ++i) {
            Vtr::internal::Level::ETag const& eTag = baseLevel.getEdgeTag(vEdges[i]);

            boundaryEdgeCount    += eTag._boundary;
            infSharpEdgeCount    += eTag._infSharp;
            semiSharpEdgeCount   += eTag._semiSharp;
            nonManifoldEdgeCount += eTag._nonManifold;
        }
        int sharpEdgeCount = infSharpEdgeCount + semiSharpEdgeCount;

        //
        //  Sharpen the vertex before using it in conjunction with incident edge
        //  properties to determine the semi-sharp tag and rule:
        //
        bool isTopologicalCorner = (vFaces.size() == 1) && (vEdges.size() == 2);
        bool isSharpenedCorner =  isTopologicalCorner && sharpenCornerVerts;
        if (isSharpenedCorner) {
            vSharpness = Sdc::Crease::SHARPNESS_INFINITE;
        } else if (vTag._nonManifold && sharpenNonManFeatures) {
            //
            //  We avoid sharpening non-manifold vertices when they occur on interior
            //  non-manifold creases, i.e. a pair of opposing non-manifold edges with
            //  more than two incident faces.  In these cases there are more incident
            //  faces than edges (1 more for each additional "fin") and no boundaries.
            //
            if (not ((nonManifoldEdgeCount == 2) && (boundaryEdgeCount == 0) && (vFaces.size() > vEdges.size()))) {
                vSharpness = Sdc::Crease::SHARPNESS_INFINITE;
            }
        }

        vTag._infSharp       = Sdc::Crease::IsInfinite(vSharpness);
        vTag._semiSharp      = Sdc::Crease::IsSemiSharp(vSharpness);
        vTag._semiSharpEdges = (semiSharpEdgeCount > 0);

        vTag._rule = (Vtr::internal::Level::VTag::VTagSize)creasing.DetermineVertexVertexRule(vSharpness, sharpEdgeCount);

        //
        //  Assign topological tags -- note that the "xordinary" tag is not strictly
        //  correct (or relevant) if non-manifold:
        //
        vTag._boundary = (boundaryEdgeCount > 0);
        vTag._corner = isSharpenedCorner;
        if (vTag._corner) {
            vTag._xordinary = false;
        } else if (vTag._boundary) {
            vTag._xordinary = (vFaces.size() != schemeRegularBoundaryValence);
        } else {
            vTag._xordinary = (vFaces.size() != schemeRegularInteriorValence);
        }
        vTag._incomplete = 0;

        //
        //  Having just decided if a vertex is on a boundary, and with its incident faces
        //  available, mark incident faces as holes.
        //
        if (makeBoundaryFacesHoles && vTag._boundary) {
            for (int i = 0; i < vFaces.size(); ++i) {
                baseLevel.getFaceTag(vFaces[i])._hole = true;

                //  Don't forget this -- but it will eventually move to the Level
                refiner._hasHoles = true;
            }
        }
    }
    return true;
}
Пример #4
0
//------------------------------------------------------------------------------
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;
}
Пример #5
0
//------------------------------------------------------------------------------
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");
        }
    }
}