Example #1
0
static MStatus
convertToMayaMeshData(OpenSubdiv::Far::TopologyRefiner const & refiner,
    std::vector<Vertex> const & refinedVerts,
    bool hasUVs, std::vector<FVarVertexUV> const & refinedUVs,
    bool hasColors, std::vector<FVarVertexColor> const & refinedColors,
    MFnMesh & inMeshFn, MObject newMeshDataObj) {

    MStatus status;

    typedef OpenSubdiv::Far::ConstIndexArray IndexArray;

    int maxlevel = refiner.GetMaxLevel();

    OpenSubdiv::Far::TopologyLevel const & refLastLevel 
                                                = refiner.GetLevel(maxlevel);

    int nfaces = refLastLevel.GetNumFaces();

    // Init Maya Data

    // Face Counts
    MIntArray faceCounts(nfaces);
    for (int face=0; face < nfaces; ++face) {
        faceCounts[face] = 4;
    }

    // Face Connects
    MIntArray faceConnects(nfaces*4);
    for (int face=0, idx=0; face < nfaces; ++face) {
        IndexArray fverts = refLastLevel.GetFaceVertices(face);
        for (int vert=0; vert < fverts.size(); ++vert) {
            faceConnects[idx++] = fverts[vert];
        }
    }

    // Points
    int nverts = refLastLevel.GetNumVertices();
    int firstOfLastVert = refiner.GetNumVerticesTotal() 
                        - nverts 
                        - refiner.GetLevel(0).GetNumVertices();

    MFloatPointArray points(nverts);
    for (int vIt = 0; vIt < nverts; ++vIt) {
        Vertex const & v = refinedVerts[firstOfLastVert + vIt];
        points.set(vIt, v.position[0], v.position[1], v.position[2]);
    }

    // Create New Mesh from MFnMesh
    MFnMesh newMeshFn;
    MObject newMeshObj = newMeshFn.create(points.length(), faceCounts.length(),
        points, faceCounts, faceConnects, newMeshDataObj, &status);
    MCHECKERR(status, "Cannot create new mesh");

    // Get face-varying set names and other info from the inMesh
    MStringArray uvSetNames;
    MStringArray colorSetNames;
    std::vector<int> colorSetChannels;
    std::vector<MFnMesh::MColorRepresentation> colorSetReps;
    int totalColorSetChannels = 0;
    status = getMayaFvarFieldParams(inMeshFn, uvSetNames, colorSetNames,
        colorSetChannels, colorSetReps, totalColorSetChannels);

    // Add new UVs back to the mesh if needed
    if (hasUVs) {

        MIntArray fvarConnects(faceConnects.length());
        int count = 0;
        for (int f = 0; f < refLastLevel.GetNumFaces(); ++f) {
            IndexArray faceIndices = refLastLevel.GetFaceFVarValues(f, CHANNELUV);
            for (int index = 0 ; index < faceIndices.size() ; ++index) {
                fvarConnects[count++] = faceIndices[index];
            }
        }

        int nuvs = refLastLevel.GetNumFVarValues(CHANNELUV);
        int firstOfLastUvs = refiner.GetNumFVarValuesTotal(CHANNELUV) 
                             - nuvs
                             - refiner.GetLevel(0).GetNumFVarValues(CHANNELUV);

        MFloatArray uCoord(nuvs), vCoord(nuvs);
        for (int uvIt = 0; uvIt < nuvs; ++uvIt) {
            FVarVertexUV const & uv = refinedUVs[firstOfLastUvs + uvIt];
            uCoord[uvIt] = uv.u;
            vCoord[uvIt] = uv.v;
        }

        // Currently, the plugin only supports one UV set
        int uvSetIndex = 0;
        if (uvSetIndex > 0) {
            status = newMeshFn.createUVSetDataMesh( uvSetNames[uvSetIndex] );
            MCHECKERR(status, "Cannot create UVSet");
        }
        static MString defaultUVName("map1");
        MString const * uvname = uvSetIndex==0 ? 
            &defaultUVName : &uvSetNames[uvSetIndex];
        status = newMeshFn.setUVs(uCoord, vCoord, uvname);                  
        MCHECKERR(status, "Cannot set UVs for set : "+*uvname);

        status = newMeshFn.assignUVs(faceCounts, fvarConnects, uvname);     
        MCHECKERR(status, "Cannot assign UVs");
    }

    // Add new colors back to the mesh if needed
    if (hasColors) {

        int count = 0;
        MIntArray fvarConnects2(faceConnects.length());
        for (int f = 0 ; f < refLastLevel.GetNumFaces(); ++f) {
            IndexArray faceIndices = refLastLevel.GetFaceFVarValues(f, CHANNELCOLOR);
            for (int index = 0 ; index < faceIndices.size() ; ++index) {
                fvarConnects2[count++] = faceIndices[index];
            }
        }
  
        int ncols = refLastLevel.GetNumFVarValues(CHANNELCOLOR);
        int firstOfLastCols = refiner.GetNumFVarValuesTotal(CHANNELCOLOR) 
                              - ncols
                              - refiner.GetLevel(0).GetNumFVarValues(CHANNELCOLOR);

        MColorArray colorArray(ncols);
        for (int colIt = 0; colIt < ncols; ++colIt) {
            FVarVertexColor const & c = refinedColors[firstOfLastCols + colIt];
            colorArray.set(colIt, c.r, c.g, c.b, c.a);
        }

        // Currently, the plugin only supports one color sets
        int colorSetIndex = 0;

        // Assign color buffer and map the ids for each face-vertex
        // API Limitation: Cannot set MColorRepresentation here
        status = newMeshFn.createColorSetDataMesh(
            colorSetNames[colorSetIndex]);                                
        MCHECKERR(status, "Cannot create ColorSet");

        bool isColorClamped = inMeshFn.isColorClamped(
            colorSetNames[colorSetIndex], &status);                   
        MCHECKERR(status, "Can not get Color Clamped ");

        status = newMeshFn.setIsColorClamped(
            colorSetNames[colorSetIndex], isColorClamped);                     
        MCHECKERR(status, "Can not set Color Clamped : " + isColorClamped);

        status = newMeshFn.setColors(
            colorArray, &colorSetNames[colorSetIndex], 
            colorSetReps[colorSetIndex]);   
        MCHECKERR(status, "Can not set Colors");

        status = newMeshFn.assignColors(
            fvarConnects2, &colorSetNames[colorSetIndex]);                          
        MCHECKERR(status, "Can not assign Colors");
    }

    return MS::kSuccess;
}
/* static */
bool
UsdMayaTranslatorMesh::_AssignColorSetPrimvarToMesh(
        const UsdGeomMesh& primSchema,
        const UsdGeomPrimvar& primvar,
        MFnMesh& meshFn)
{
    const TfToken& primvarName = primvar.GetPrimvarName();
    const SdfValueTypeName& typeName = primvar.GetTypeName();

    MString colorSetName(primvarName.GetText());

    // If the primvar is displayOpacity and it is a FloatArray, check if
    // displayColor is authored. If not, we'll import this 'displayOpacity'
    // primvar as a 'displayColor' color set. This supports cases where the
    // user created a single channel value for displayColor.
    // Note that if BOTH displayColor and displayOpacity are authored, they will
    // be imported as separate color sets. We do not attempt to combine them
    // into a single color set.
    if (primvarName == UsdMayaMeshColorSetTokens->DisplayOpacityColorSetName &&
            typeName == SdfValueTypeNames->FloatArray) {
        if (!UsdMayaRoundTripUtil::IsAttributeUserAuthored(primSchema.GetDisplayColorPrimvar())) {
            colorSetName = UsdMayaMeshColorSetTokens->DisplayColorColorSetName.GetText();
        }
    }

    // We'll need to convert colors from linear to display if this color set is
    // for display colors.
    const bool isDisplayColor =
        (colorSetName == UsdMayaMeshColorSetTokens->DisplayColorColorSetName.GetText());

    // Get the raw data before applying any indexing. We'll only populate one
    // of these arrays based on the primvar's typeName, and we'll also set the
    // color representation so we know which array to use later.
    VtFloatArray alphaArray;
    VtVec3fArray rgbArray;
    VtVec4fArray rgbaArray;
    MFnMesh::MColorRepresentation colorRep;
    size_t numValues = 0;

    MStatus status = MS::kSuccess;

    if (typeName == SdfValueTypeNames->FloatArray) {
        colorRep = MFnMesh::kAlpha;
        if (!primvar.Get(&alphaArray) || alphaArray.empty()) {
            status = MS::kFailure;
        } else {
            numValues = alphaArray.size();
        }
    } else if (typeName == SdfValueTypeNames->Float3Array ||
               typeName == SdfValueTypeNames->Color3fArray) {
        colorRep = MFnMesh::kRGB;
        if (!primvar.Get(&rgbArray) || rgbArray.empty()) {
            status = MS::kFailure;
        } else {
            numValues = rgbArray.size();
        }
    } else if (typeName == SdfValueTypeNames->Float4Array ||
               typeName == SdfValueTypeNames->Color4fArray) {
        colorRep = MFnMesh::kRGBA;
        if (!primvar.Get(&rgbaArray) || rgbaArray.empty()) {
            status = MS::kFailure;
        } else {
            numValues = rgbaArray.size();
        }
    } else {
        TF_WARN("Unsupported color set primvar type '%s' for primvar '%s' on "
                "mesh: %s",
                typeName.GetAsToken().GetText(),
                primvarName.GetText(),
                primvar.GetAttr().GetPrimPath().GetText());
        return false;
    }

    if (status != MS::kSuccess || numValues == 0) {
        TF_WARN("Could not read color set values from primvar '%s' on mesh: %s",
                primvarName.GetText(),
                primvar.GetAttr().GetPrimPath().GetText());
        return false;
    }

    VtIntArray assignmentIndices;
    int unauthoredValuesIndex = -1;
    if (primvar.GetIndices(&assignmentIndices)) {
        // The primvar IS indexed, so the indices array is what determines the
        // number of color values.
        numValues = assignmentIndices.size();
        unauthoredValuesIndex = primvar.GetUnauthoredValuesIndex();
    }

    // Go through the color data and translate the values into MColors in the
    // colorArray, taking into consideration that indexed data may have been
    // authored sparsely. If the assignmentIndices array is empty then the data
    // is NOT indexed.
    // Note that with indexed data, the data is added to the arrays in ascending
    // component ID order according to the primvar's interpolation (ascending
    // face ID for uniform interpolation, ascending vertex ID for vertex
    // interpolation, etc.). This ordering may be different from the way the
    // values are ordered in the primvar. Because of this, we recycle the
    // assignmentIndices array as we go to store the new mapping from component
    // index to color index.
    MColorArray colorArray;
    for (size_t i = 0; i < numValues; ++i) {
        int valueIndex = i;

        if (i < assignmentIndices.size()) {
            // The data is indexed, so consult the indices array for the
            // correct index into the data.
            valueIndex = assignmentIndices[i];

            if (valueIndex == unauthoredValuesIndex) {
                // This component is unauthored, so just update the
                // mapping in assignmentIndices and then skip the value.
                // We don't actually use the value at the unassigned index.
                assignmentIndices[i] = -1;
                continue;
            }

            // We'll be appending a new value, so the current length of the
            // array gives us the new value's index.
            assignmentIndices[i] = colorArray.length();
        }

        GfVec4f colorValue(1.0);

        switch(colorRep) {
            case MFnMesh::kAlpha:
                colorValue[3] = alphaArray[valueIndex];
                break;
            case MFnMesh::kRGB:
                colorValue[0] = rgbArray[valueIndex][0];
                colorValue[1] = rgbArray[valueIndex][1];
                colorValue[2] = rgbArray[valueIndex][2];
                break;
            case MFnMesh::kRGBA:
                colorValue[0] = rgbaArray[valueIndex][0];
                colorValue[1] = rgbaArray[valueIndex][1];
                colorValue[2] = rgbaArray[valueIndex][2];
                colorValue[3] = rgbaArray[valueIndex][3];
                break;
            default:
                break;
        }

        if (isDisplayColor) {
            colorValue = UsdMayaColorSpace::ConvertLinearToMaya(colorValue);
        }

        MColor mColor(colorValue[0], colorValue[1], colorValue[2], colorValue[3]);
        colorArray.append(mColor);
    }

    // colorArray now stores all of the values and any unassigned components
    // have had their indices set to -1, so update the unauthored values index.
    unauthoredValuesIndex = -1;

    const bool clamped = UsdMayaRoundTripUtil::IsPrimvarClamped(primvar);

    status = meshFn.createColorSet(colorSetName, nullptr, clamped, colorRep);
    if (status != MS::kSuccess) {
        TF_WARN("Unable to create color set '%s' for mesh: %s",
                colorSetName.asChar(),
                meshFn.fullPathName().asChar());
        return false;
    }

    // Create colors on the mesh from the values we collected out of the
    // primvar. We'll assign mesh components to these values below.
    status = meshFn.setColors(colorArray, &colorSetName, colorRep);
    if (status != MS::kSuccess) {
        TF_WARN("Unable to set color data on color set '%s' for mesh: %s",
                colorSetName.asChar(),
                meshFn.fullPathName().asChar());
        return false;
    }

    const TfToken& interpolation = primvar.GetInterpolation();

    // Build an array of value assignments for each face vertex in the mesh.
    // Any assignments left as -1 will not be assigned a value.
    MIntArray colorIds = _GetMayaFaceVertexAssignmentIds(meshFn,
                                                         interpolation,
                                                         assignmentIndices,
                                                         unauthoredValuesIndex);

    status = meshFn.assignColors(colorIds, &colorSetName);
    if (status != MS::kSuccess) {
        TF_WARN("Could not assign color values to color set '%s' on mesh: %s",
                colorSetName.asChar(),
                meshFn.fullPathName().asChar());
        return false;
    }

    return true;
}
Example #3
0
MStatus convertOsdFarToMayaMeshData(
     FMesh const * farMesh,
     OpenSubdiv::OsdCpuVertexBuffer * vertexBuffer,
     int subdivisionLevel,
     MFnMesh const & inMeshFn,
     MObject newMeshDataObj ) {

    MStatus returnStatus;

    // Get sizing data from OSD
    const OpenSubdiv::FarPatchTables *farPatchTables = farMesh->GetPatchTables();
    int numPolygons = farPatchTables->GetNumFaces(); // use the highest level stored in the patch tables
    const unsigned int *polygonConnects_orig = farPatchTables->GetFaceVertices(); // use the highest level stored in the patch tables

    const OpenSubdiv::FarSubdivisionTables<OpenSubdiv::OsdVertex> *farSubdivTables = farMesh->GetSubdivisionTables();
    unsigned int numVertices  = farSubdivTables->GetNumVertices(subdivisionLevel);
    unsigned int vertexOffset = farSubdivTables->GetFirstVertexOffset(subdivisionLevel);

    // Init Maya Data
    MFloatPointArray points(numVertices);
    MIntArray faceCounts(numPolygons); // number of edges for each polygon.  Assume quads (4-edges per face)
    MIntArray faceConnects(numPolygons*4); // array of vertex ids for all edges. assuming quads

    // -- Face Counts
    for (int i=0; i < numPolygons; ++i) {
        faceCounts[i] = 4;
    }

    // -- Face Connects
    for (unsigned int i=0; i < faceConnects.length(); i++) {
        faceConnects[i] = polygonConnects_orig[i] - vertexOffset; // adjust vertex indices so that v0 is at index 0
    }

    // -- Points
    // Number of floats in each vertex.  (positions, normals, etc)
    int numFloatsPerVertex = vertexBuffer->GetNumElements();
    assert(numFloatsPerVertex == 3); // assuming only xyz stored for each vertex
    const float *vertexData = vertexBuffer->BindCpuBuffer();
    float *ptrVertexData;

    for (unsigned int i=0; i < numVertices; i++) {

        // make sure to offset to the first osd vertex for that subd level
        unsigned int osdRawVertexIndex = i + vertexOffset;

        // Lookup the data in the vertexData
        ptrVertexData = (float *) vertexData + ((osdRawVertexIndex) * numFloatsPerVertex);
        points.set(i, ptrVertexData[0], ptrVertexData[1], ptrVertexData[2]);
    }

    // Create New Mesh from MFnMesh
    MFnMesh newMeshFn;
    MObject newMeshObj = newMeshFn.create(points.length(), faceCounts.length(),
        points, faceCounts, faceConnects, newMeshDataObj, &returnStatus);
    MCHECKERR(returnStatus, "Cannot create new mesh");

    // Attach UVs (if present)
    // ASSUMPTION: Only tracking UVs as FVar data.  Will need to change this
    // ASSUMPTION: OSD has a unique UV for each face-vertex
    int fvarTotalWidth = farMesh->GetTotalFVarWidth();

    if (fvarTotalWidth > 0) {

        // Get face-varying set names and other info from the inMesh
        MStringArray uvSetNames;
        MStringArray colorSetNames;
        std::vector<int> colorSetChannels;
        std::vector<MFnMesh::MColorRepresentation> colorSetReps;
        int totalColorSetChannels = 0;
        returnStatus = getMayaFvarFieldParams(inMeshFn, uvSetNames, colorSetNames, colorSetChannels, colorSetReps, totalColorSetChannels);

        int numUVSets = uvSetNames.length();
        int expectedFvarTotalWidth = numUVSets*2 + totalColorSetChannels;
        assert(fvarTotalWidth == expectedFvarTotalWidth);

        const OpenSubdiv::FarPatchTables::FVarDataTable &fvarDataTable =  farPatchTables->GetFVarDataTable();
        assert(fvarDataTable.size() == expectedFvarTotalWidth*faceConnects.length());

        // Create an array of indices to map each face-vert to the UV and ColorSet Data
        MIntArray fvarConnects(faceConnects.length());
        for (unsigned int i=0; i < faceConnects.length(); i++) {
            fvarConnects[i] = i;
        }

        MFloatArray uCoord(faceConnects.length());
        MFloatArray vCoord(faceConnects.length());

        for (int uvSetIndex=0; uvSetIndex < numUVSets; uvSetIndex++) {

            for(unsigned int vertid=0; vertid < faceConnects.length(); vertid++) {
                int fvarItem = vertid*fvarTotalWidth + uvSetIndex*2; // stride per vertex is the fvarTotalWidth
                uCoord[vertid] = fvarDataTable[fvarItem];
                vCoord[vertid] = fvarDataTable[fvarItem+1];
            }
            // Assign UV buffer and map the uvids for each face-vertex
            if (uvSetIndex != 0) { // assume uvset index 0 is the default UVset, so do not create
                returnStatus = newMeshFn.createUVSetDataMesh( uvSetNames[uvSetIndex] );
            }
            MCHECKERR(returnStatus, "Cannot create UVSet");
            newMeshFn.setUVs(uCoord,vCoord, &uvSetNames[uvSetIndex]);
            newMeshFn.assignUVs(faceCounts, fvarConnects, &uvSetNames[uvSetIndex]);
        }

        MColorArray colorArray(faceConnects.length());
        int colorSetRelativeStartIndex = numUVSets*2;

        for (unsigned int colorSetIndex=0; colorSetIndex < colorSetNames.length(); colorSetIndex++) {

            for(unsigned int vertid=0; vertid < faceConnects.length(); vertid++) {

                int fvarItem = vertid*fvarTotalWidth + colorSetRelativeStartIndex;
                if (colorSetChannels[colorSetIndex] == 1) {
                    colorArray[vertid].r = fvarDataTable[fvarItem];
                    colorArray[vertid].g = fvarDataTable[fvarItem];
                    colorArray[vertid].b = fvarDataTable[fvarItem];
                    colorArray[vertid].a = 1.0f;
                } else if (colorSetChannels[colorSetIndex] == 3) {
                    colorArray[vertid].r = fvarDataTable[fvarItem];
                    colorArray[vertid].g = fvarDataTable[fvarItem+1];
                    colorArray[vertid].b = fvarDataTable[fvarItem+2];
                    colorArray[vertid].a = 1.0f;
                } else {
                    colorArray[vertid].r = fvarDataTable[fvarItem];
                    colorArray[vertid].g = fvarDataTable[fvarItem+1];
                    colorArray[vertid].b = fvarDataTable[fvarItem+2];
                    colorArray[vertid].a = fvarDataTable[fvarItem+3];
                }
            }

            // Assign UV buffer and map the uvids for each face-vertex
            // API Limitation: Cannot set MColorRepresentation here
            returnStatus = newMeshFn.createColorSetDataMesh(colorSetNames[colorSetIndex]);
            MCHECKERR(returnStatus, "Cannot create ColorSet");

            bool isColorClamped = inMeshFn.isColorClamped(colorSetNames[colorSetIndex], &returnStatus);
            newMeshFn.setIsColorClamped(colorSetNames[colorSetIndex], isColorClamped);
            newMeshFn.setColors(colorArray, &colorSetNames[colorSetIndex], colorSetReps[colorSetIndex]);
            newMeshFn.assignColors(fvarConnects, &colorSetNames[colorSetIndex]);

            // Increment colorSet start location in fvar buffer
            colorSetRelativeStartIndex += colorSetChannels[colorSetIndex];
        }
    }
    return MS::kSuccess;
}