[Maya C++ API] Per vertex color update in MPxDeformerNode

Code snippet in C++ to be able to update the color of a mesh with Maya API on a per vertex basis.

Enable  color in Maya

To display per vertex color in Maya's viewport, select the mesh and enable "Color""Toggle Per Vertex Colors Attribute" in Maya's menu or call the MEL equivalent: toggleShadeMode();.

You can check wether or not the shade mode is enabled/disabled by checking the mesh attribute displayColors with the MEL command: getAttr "mesh_name.displayColors";

Set per vertex color within a command

Outside a node it's quite simple to update the mesh colors through the class MFnMesh of the Maya API: 

#define mayaCheck(code) do{ const g_status_(code); const int l = __LINE__;\
    if(g_status_ != MS::kSuccess) \
        throw My_exception(g_status_, __TO_STR(__FILE__), l); \
    }while(false)

    //--------------------
{  
    MObject mesh_shape;
    MFnMesh mesh_fn( mesh_shape, &status);
    mayaCheck(status);
    int num_verts = mesh_fn.numVertices(&status);
    mayaCheck(status);
    MColorArray colors;
    MIntArray vertex_idx_list;
    if( colors.length() != num_verts){
        mayaCheck(colors.setLength(num_verts));
        mayaCheck(vertex_idx_list.setLength(num_verts));
    }

    MGlobal::displayInfo(MString("num verts: ") + num_verts);
    for(int i = 0; i < num_verts; ++i)
    {
        colors.set(MColor(1.0f, 0.0f, 0.0f), i); // Set to red
        vertex_idx_list[i] = i;
    }

    mayaCheck( mesh_fn.setVertexColors(colors, vertex_idx_list) );
}

Set per vertex color within MPxDeformerNode

Next I show how to change vertex color with Maya API inside a MPxDeformerNode deformer node. The main trick is to not forget to call MPxDeformerNode::setDeformationDetails() note that setVertexColor() sometimes won't work for some strange reasons... Instead use setVertexColors() it's faster anyway.

MStatus Inherits_mpxdeformer::deform(MDataBlock& block,
                                     MItGeometry& geom_it,
                                     const MMatrix& object_matrix,
                                     unsigned int multi_index)
{
    
    try
    {
        MStatus status;
        MArrayDataHandle out_array = block.outputArrayValue(MPxDeformerNode::outputGeom, &status);
        mayaCheck(status);
        MDataHandle houtput = out_array.inputValue(&status);
        mayaCheck(status);
        MFnMesh mesh_fn ( houtput.asMesh(), &status);
        mayaCheck(status);
        MColorArray colors;
        MIntArray vertex_idx;
        for (geom_it.reset(); !geom_it.isDone(); geom_it.next()) {
            colors.append(1, 0, 0, 1);
            vertex_idx.append(geom_it.index());
        }

        mesh_fn.setVertexColors(colors, vertex_idx);
        houtput.setClean();
    }
    catch (std::exception& e)
    {
        maya_print_error( e );
        return MS::kFailure;
    }
    return MStatus::kSuccess;
    
}

// -----------------------------------------------------------------------------

void Inherits_mpxdeformer::postConstructor()
{
    mayaCheck( MPxDeformerNode::setDeformationDetails(MPxDeformerNode::kDeformsColors) );
}

Set per vertex color within a MPxNode

This one is a little more tricky, you need to create your own input and output mesh attribute, connect your node in between the source and destination mesh. Then copy the data and modify the color using MFnMesh:

MColorArray Node_color::_current_colors;
MIntArray Node_color::_vertex_idx_list;
MObject Node_color::_s_in_mesh;
MObject Node_color::_s_out_mesh;

// -----------------------------------------------------------------------------  

MStatus Node_color::initialize()
{
    try
    {
        MStatus status;
        MFnTypedAttribute typed_attr;
        _s_in_mesh = typed_attr.create("in_mesh", "im", MFnMeshData::kMesh, MObject::kNullObj, &status);
        mayaCheck( status );
        mayaCheck( typed_attr.setStorable(false) );
        mayaCheck( typed_attr.setConnectable(true) );
        mayaCheck( addAttribute(_s_in_mesh) );

        _s_out_mesh = typed_attr.create("out_mesh", "om", MFnMeshData::kMesh, MObject::kNullObj, &status);
        mayaCheck( status );
        mayaCheck( typed_attr.setStorable(false) );
        mayaCheck( typed_attr.setConnectable(true) );
        mayaCheck( addAttribute(_s_out_mesh) );
        attributeAffects( _s_in_mesh, _s_out_mesh );
        
        return MS::kSuccess;
    }
    catch (std::exception& e)
    {
        maya_print_error( e );
        return MS::kFailure;
    }
    return MStatus::kSuccess;
}

// -----------------------------------------------------------------------------        

MStatus Node_color::compute(const MPlug& plug, MDataBlock& data_block)
{
    try
    {
        MStatus status;

        if (plug.attribute() != _s_out_mesh) {
            return MS::kSuccess;
        }

        // Copy in mesh as is in the out mesh
        mayaCheck(status);
        MDataHandle in_mesh_data  = data_block.inputValue(_s_in_mesh, &status);
        mayaCheck(status);
        MDataHandle out_mesh_data = data_block.outputValue(_s_out_mesh, &status);
        mayaCheck(status);
        mayaCheck(out_mesh_data.copy(in_mesh_data));
        mayaCheck(out_mesh_data.set(in_mesh_data.asMesh()));

        bool display_color = true;
        if(display_color)
        {
            MObject mesh = out_mesh_data.asMesh();
            MFnMesh mesh_fn( mesh, &status);
            mayaCheck(status);

            int num_verts = mesh_fn.numVertices(&status);
            mayaCheck(status);
            if( _current_colors.length() != num_verts)
            {                               
                mayaCheck(_current_colors.setLength(num_verts));
                mayaCheck(_vertex_idx_list.setLength(num_verts));
                for(int i = 0; i < num_verts; ++i) {
                    _current_colors.set(MColor(0.5f, 0.5f, 0.5f), i);
                    _vertex_idx_list[i] = i;
                }
            }
            
            mayaAssert(_vertex_idx_list.length() == num_verts);
            mayaAssert(_current_colors.length() == num_verts);
            
            for(int i = 0; i < num_verts; ++i) {                
                MColor c = compute_color(i);
                _current_colors.set(c, i);
            }
            
            mayaCheck( mesh_fn.setVertexColors(_current_colors, _vertex_idx_list) );
        }
        data_block.setClean(plug);

    }
    catch (std::exception& e)
    {
        maya_print_error( e );
        return MS::kFailure;
    }
    return MStatus::kSuccess;
}

Original post here

No comments

All html tags except <b> and <i> will be removed from your comment. You can make links by just typing the url or mail-address.
Spam bot question: