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