Maya API How-To #30

Back · Previous Maya

How do I query the output color for a Material?

Color In Context

The '.outColor' attribute for a material is valid only within the context of rendering. Otherwise, what color should it give you? At what UV? At what pixel?

To demonstrate, wire up a phong material that uses a ramp color as input.

string $p = `shadingNode -asShader "phong"`;
string $r = `shadingNode -asTexture "ramp"`;
connectAttr ( $r + ".outColor" ) ( $p + ".color" );

In the Hypershade you'll see the material decked out in its yuletide colors of red, green and blue. Now, try to query the output color:

getAttr ( $p + ".outColor" );
// Result: 0 0 0 //

Uh-huh. Right.

So what if there wasn't a texture, but only a static color?

disconnectAttr ( $r + ".outColor" ) ( $p + ".color" );
setAttr ( $p + ".color" ) 1.0 0.9 0.2;

getAttr ( $p + ".outColor" );
// Result: 0 0 0 //

What we can do in this case is query the input color attribute (i.e. the one set earlier):

getAttr ( $p + ".color" );
// Result: 1 0.9 0.2 //

It may appear that this works with a connection, as well:

connectAttr ( $r + ".outColor" ) ( $p + ".color" );

getAttr ( $p + ".color" );
// Result: 1 0 0 //

However, this can only represent any one color from the ramp, and there's no way to construct the whole picture (pardon the pun) for the material's behavior.

Pieces of the Puzzle

If querying the inputs for your material is enough, you may perform the following:

1. Find the MPlug from the input color for the material (phong, lambert, blinn, doesn't matter):

MObject phongMaterial;
MFnDependencyNode fnDependNode( phongMaterial ):
MPlug colorPlug = fnDependNode.findPlug( "color" );

2. Determine if it has an input connection:

MPlugArray cc;
colorPlug.connectedTo( cc, true /* asDst */, false );
if ( cc.length() > 0 )
{
  // Plug is driven by an input connection.
}

3. If it isn't driven by a plug, you can simply query its value.

else
{
  MColor phongColor;
  colorPlug.child(0).getValue( phongColor.r );
  colorPlug.child(1).getValue( phongColor.g );
  colorPlug.child(2).getValue( phongColor.b );
}

4. If it is driven by a plug, you'll need to output a texture for the incoming connection. If the input is a "file" node then you can query its '.fileTextureName' attribute and parse the image from disk. If it's not a file node you'll likely have to resort to baking the image to disk first (via "convertSolidTx").

The Whole Picture

The above method provides you with the color - or texture - which influences one of the color inputs for the material. However, the whole point of a shader is to imbue surface properties to the color values: layering textures, adding specular highlights, generating anisotropic striations, or perhaps generating a non-photorealistic effect (such as a toon shader). If you wish to sample the true output for a material, you must call upon Maya's rendering functions.

If you have a specific range of UVs at which you want to query the color values, or if you need only a limited sampling of the colors, then you can also use the MRenderUtil class to generate the output at specific UVs. You'll need to be prepared to provide a fair amount of "surface" information, however:

MRenderUtil::sampleShadingNetwork( 
    MString shadingNodeName, 
    int numSamples, 
    bool useShadowMaps, 
    bool reuseMaps,  
    MFloatMatrix& cameraMatrix,  
    MFloatPointArray* points,  
    MFloatArray* uCoords,  
    MFloatArray* vCoords,  
    MFloatVectorArray* normals,  
    MFloatPointArray* refPoints,  
    MFloatVectorArray* tangentUs,  
    MFloatVectorArray* tangentVs,  
    MFloatArray* filterSizes,  
    MFloatVectorArray& resultColors,  
    MFloatVectorArray& resultTransparencies );

Related How-To's

19 Feb 2005