Example #1
0
void
InterpolateFVarData(OpenSubdiv::Far::TopologyRefiner & refiner,
    Shape const & shape, std::vector<float> & fvarData) {

    int channel = 0,    // shapes only have 1 UV channel
        fvarWidth = 2;

    int maxlevel = refiner.GetMaxLevel(),
        numValuesM = refiner.GetLevel(maxlevel).GetNumFVarValues(channel),
        numValuesTotal = refiner.GetNumFVarValuesTotal(channel);

    if (shape.uvs.empty() || numValuesTotal<=0) {
        return;
    }

    OpenSubdiv::Far::PrimvarRefiner primvarRefiner(refiner);

    if (refiner.IsUniform()) {

        // For uniform we only keep the highest level of refinement:
        fvarData.resize(numValuesM * fvarWidth);

        std::vector<FVarVertex> buffer(numValuesTotal - numValuesM);

        FVarVertex * src = &buffer[0];
        memcpy(src, &shape.uvs[0], shape.uvs.size()*sizeof(float));

        //  Defer the last level to treat separately with its alternate destination:
        for (int level = 1; level < maxlevel; ++level) {
            FVarVertex * dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel);

            primvarRefiner.InterpolateFaceVarying(level, src, dst, channel);

            src = dst;
        }

        FVarVertex * dst = reinterpret_cast<FVarVertex *>(&fvarData[0]);
        primvarRefiner.InterpolateFaceVarying(maxlevel, src, dst, channel);

    } else {

        // For adaptive we keep all levels:
        fvarData.resize(numValuesTotal * fvarWidth);

        FVarVertex * src = reinterpret_cast<FVarVertex *>(&fvarData[0]);
        memcpy(src, &shape.uvs[0], shape.uvs.size()*sizeof(float));

        for (int level = 1; level <= maxlevel; ++level) {
            FVarVertex * dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel);

            primvarRefiner.InterpolateFaceVarying(level, src, dst, channel);

            src = dst;
        }
    }
}
Example #2
0
MStatus
MayaPolySmooth::compute( const MPlug& plug, MDataBlock& data ) {

    MStatus status;

    // Check which output attribute we have been asked to compute.  If this
    // node doesn't know how to compute it, we must return
    // MS::kUnknownParameter.
    //

    if( plug == a_output ) {

        bool createdSubdMesh = false;

        int subdivisionLevel = data.inputValue(a_subdivisionLevels).asInt();
        short stateH = data.inputValue(state).asShort();

        if ((subdivisionLevel > 0) and (stateH !=1)) {

            // == Retrieve input mesh ====================================
            // Get attr values
            MObject inMeshObj        = data.inputValue(a_inputPolymesh).asMesh();
            short vertBoundaryMethod = data.inputValue(a_vertBoundaryMethod).asShort();
            short fvarBoundaryMethod = data.inputValue(a_fvarBoundaryMethod).asShort();
            bool  fvarPropCorners    = data.inputValue(a_fvarPropagateCorners).asBool();
            bool  smoothTriangles    = data.inputValue(a_smoothTriangles).asBool();
            short creaseMethodVal    = data.inputValue(a_creaseMethod).asShort();

            // == Get Mesh Functions and Iterators ==========================
            MFnMeshData inMeshDat(inMeshObj);
            MFnMesh inMeshFn(inMeshObj, &status);
            MCHECKERR(status, "ERROR getting inMeshFn\n");
            MItMeshPolygon inMeshItPolygon(inMeshObj, &status);
            MCHECKERR(status, "ERROR getting inMeshItPolygon\n");

            // Convert attr values to OSD enums
            OpenSubdiv::Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;

            // == Create Far topology ==========================
            OpenSubdiv::Sdc::Options options;
            options.SetVtxBoundaryInterpolation(ConvertMayaVtxBoundary(vertBoundaryMethod));
            options.SetFVarLinearInterpolation(ConvertMayaFVarBoundary(fvarBoundaryMethod, fvarPropCorners));
            options.SetCreasingMethod(creaseMethodVal ?
                 OpenSubdiv::Sdc::Options::CREASE_CHAIKIN : OpenSubdiv::Sdc::Options::CREASE_UNIFORM);
            options.SetTriangleSubdivision(smoothTriangles ?
                 OpenSubdiv::Sdc::Options::TRI_SUB_SMOOTH : OpenSubdiv::Sdc::Options::TRI_SUB_CATMARK);

            // Storage for face-varying values (UV sets, vertex colors...)
            std::vector<MFloatArray> uvSet_uCoords;
            std::vector<MFloatArray> uvSet_vCoords;
            std::vector<MColorArray> colorSet_colors;

            bool hasUVs = false, hasColors = false;
            float maxCreaseSharpness=0.0f;
            OpenSubdiv::Far::TopologyRefiner * refiner = gatherTopology(
                inMeshFn, inMeshItPolygon, type, options, &hasUVs, &hasColors,
                uvSet_uCoords, uvSet_vCoords, colorSet_colors, &maxCreaseSharpness);

            assert(refiner);

            // == Refine & Interpolate ==========================
            refiner->RefineUniform(OpenSubdiv::Far::TopologyRefiner::UniformOptions(subdivisionLevel));

            // Prepare vertex information
            Vertex const * initialVerts = 
                reinterpret_cast<Vertex const *>(inMeshFn.getRawPoints(&status));
            std::vector<Vertex> refinedVerts(
                refiner->GetNumVerticesTotal() - refiner->GetLevel(0).GetNumVertices());
            Vertex const * srcVerts = &initialVerts[0];
            Vertex * dstVerts = &refinedVerts[0];
           
            // Verify the refiner has the correct number of values 
            // needed to interpolate the different channels
            int numInitialUVs = refiner->GetLevel(0).GetNumFVarValues(CHANNELUV);
            int numInitialColors = refiner->GetLevel(0).GetNumFVarValues(CHANNELCOLOR);

            if (hasUVs && numInitialUVs <= 0) {
                hasUVs = false;
                MGlobal::displayError("Model with incorrect data, the UV channel will not be interpolated.");
            }

            if (hasColors && numInitialColors <= 0) {
                hasColors = false;  
                MGlobal::displayError("Model with incorrect data, the color channel will not be interpolated.");
            } 

            // Prepare UV information if needed
            std::vector<FVarVertexUV> initialUVs, refinedUVs;
            FVarVertexUV const * srcUV = NULL;
            FVarVertexUV * dstUV = NULL;
            if(hasUVs) {
                initialUVs.resize(numInitialUVs);
                refinedUVs.resize(refiner->GetNumFVarValuesTotal(CHANNELUV));
                for (int i=0; i<numInitialUVs; ++i) {
                    initialUVs[i].u = uvSet_uCoords[0][i];
                    initialUVs[i].v = uvSet_vCoords[0][i];
                }
                srcUV = &initialUVs[0];
                dstUV = &refinedUVs[0];
            }

            // Prepare color information if needed
            std::vector<FVarVertexColor> initialColors, refinedColors;
            FVarVertexColor const * srcColor = NULL;
            FVarVertexColor * dstColor = NULL;
            if(hasColors) {
                initialColors.resize(numInitialColors);
                refinedColors.resize(refiner->GetNumFVarValuesTotal(CHANNELCOLOR));
                for (int i=0; i<numInitialColors; ++i) {
                    initialColors[i].r = colorSet_colors[0][i].r;
                    initialColors[i].g = colorSet_colors[0][i].g;
                    initialColors[i].b = colorSet_colors[0][i].b;
                    initialColors[i].a = colorSet_colors[0][i].a;
                }
                srcColor = &initialColors[0];
                dstColor = &refinedColors[0];
            }

            // Interpolate the vertices and the different channels
            OpenSubdiv::Far::PrimvarRefiner primvarRefiner(*refiner); 
            
            for (int level = 1; level <= subdivisionLevel; ++level) {
                
                // Interpolate vertices
                primvarRefiner.Interpolate(level, srcVerts, dstVerts);
                srcVerts = dstVerts;
                dstVerts += refiner->GetLevel(level).GetNumVertices();

                // Interpolate the uv set
                if(hasUVs) {
                    primvarRefiner.InterpolateFaceVarying(level, srcUV, dstUV, CHANNELUV);
                    srcUV = dstUV;
                    dstUV += refiner->GetLevel(level).GetNumFVarValues(CHANNELUV);
                }

                // Interpolate any color set
                if(hasColors) {
                    primvarRefiner.InterpolateFaceVarying(level, srcColor, dstColor, CHANNELCOLOR);
                    srcColor = dstColor;
                    dstColor += refiner->GetLevel(level).GetNumFVarValues(CHANNELCOLOR);
                }
            }

            // == Convert subdivided OpenSubdiv mesh to MFnMesh Data outputMesh =============

            // Create New Mesh Data Object
            MFnMeshData newMeshData;
            MObject     newMeshDataObj = newMeshData.create(&status);
            MCHECKERR(status, "ERROR creating outputData");

            // Create out mesh
            status = convertToMayaMeshData(*refiner, refinedVerts, hasUVs, 
                refinedUVs, hasColors, refinedColors, inMeshFn, newMeshDataObj);
            MCHECKERR(status, "ERROR convertOsdFarToMayaMesh");

            // Propagate objectGroups from inMesh to outMesh (for per-facet shading, etc)
            status = createSmoothMesh_objectGroups(inMeshFn, inMeshDat,
                newMeshData, subdivisionLevel, refiner->GetLevel(subdivisionLevel).GetNumFaces());

            // Write to output plug
            MDataHandle outMeshH = data.outputValue(a_output, &status);
            MCHECKERR(status, "ERROR getting polygon data handle\n");
            outMeshH.set(newMeshDataObj);

            int isolation = std::min(10,(int)ceil(maxCreaseSharpness)+1);
            data.outputValue(a_recommendedIsolation).set(isolation);

            // == Cleanup OSD ============================================

            // REVISIT: Re-add these deletes
            delete refiner;

            // note that the subd mesh was created (see the section below if !createdSubdMesh)
            createdSubdMesh = true;
        }

        // Pass-through inMesh to outMesh if not created the subd mesh
        if (!createdSubdMesh) {
            MDataHandle outMeshH = data.outputValue(a_output, &status);
            status = outMeshH.copy(data.outputValue(a_inputPolymesh, &status));
            MCHECKERR(status, "ERROR getting polygon data handle\n");
        }

        // Clean up Maya Plugs
        data.setClean(plug);

    } else {
        // Unhandled parameter in this compute function, so return MS::kUnknownParameter
        // so it is handled in a parent compute() function.
        return MS::kUnknownParameter;
    }
    return MS::kSuccess;
}
Example #3
0
//
// StencilTable factory
//
StencilTable const *
StencilTableFactory::Create(TopologyRefiner const & refiner,
    Options options) {

    int maxlevel = std::min(int(options.maxLevel), refiner.GetMaxLevel());
    if (maxlevel==0 && (! options.generateControlVerts)) {
        StencilTable * result = new StencilTable;
        result->_numControlVertices = refiner.GetLevel(0).GetNumVertices();
        return result;
    }

    bool interpolateVarying = options.interpolationMode==INTERPOLATE_VARYING;
    internal::StencilBuilder builder(refiner.GetLevel(0).GetNumVertices(),
                                /*genControlVerts*/ true,
                                /*compactWeights*/  true);

    //
    // Interpolate stencils for each refinement level using
    // PrimvarRefiner::InterpolateLevel<>() for vertex or varying
    //
    PrimvarRefiner primvarRefiner(refiner);

    internal::StencilBuilder::Index srcIndex(&builder, 0);
    internal::StencilBuilder::Index dstIndex(&builder, 
                                    refiner.GetLevel(0).GetNumVertices());

    for (int level=1; level<=maxlevel; ++level) {
        if (! interpolateVarying) {
            primvarRefiner.Interpolate(level, srcIndex, dstIndex);
        } else {
            primvarRefiner.InterpolateVarying(level, srcIndex, dstIndex);
        }

        if (options.factorizeIntermediateLevels) {
            srcIndex = dstIndex;
        }

        dstIndex = dstIndex[refiner.GetLevel(level).GetNumVertices()];

        if (! options.factorizeIntermediateLevels) {
            // All previous verts are considered as coarse verts, as a
            // result, we don't update the srcIndex and update the coarse
            // vertex count.
            builder.SetCoarseVertCount(dstIndex.GetOffset());
        }
    }

    size_t firstOffset = refiner.GetLevel(0).GetNumVertices();
    if (! options.generateIntermediateLevels)
        firstOffset = srcIndex.GetOffset();
 
    // Copy stencils from the StencilBuilder into the StencilTable.
    // Always initialize numControlVertices (useful for torus case)
    StencilTable * result = 
                        new StencilTable(refiner.GetLevel(0).GetNumVertices(),
                                          builder.GetStencilOffsets(),
                                          builder.GetStencilSizes(),
                                          builder.GetStencilSources(),
                                          builder.GetStencilWeights(),
                                          options.generateControlVerts,
                                          firstOffset);
    return result;
}