March 2019: ewertb.soundlinker.com is getting relocated to ewertb.mayasound.com, please update your bookmarks.

Maya API How-To #15

Back · Previous · Next Maya

How do I create a Shading Group / Material / File texture network?

You will need to create a Shading Group, Material and File texture node, assign the ‘.fileTextureName’ attribute of the File texture node to your path/filename, and then string the DG graph for the three together to make a valid shading network.

For H2O Entertainment I created a C++ Class for convenient "create and assign Shading Groups" using static member functions. Here's a snippet from the header file:

// MShadingGroup.h

  static MStatus    CreateShadingGroup(
                      const char * fileTextureName,
                      MShadingGroup::MaterialType materialType,
                      MObject & shadingGroup );

  static MStatus    AssignToDefaultShadingGroup(
                      const MDagPath & dagPath,
                      const MObject & object );

  static MStatus    AssignToShadingGroup(
                      const MObject & obShadingGroup,
                      const MDagPath & obDagPath,
                      const MObject & obComponent = MObject::kNullObj );

  static MStatus    RegisterMaterial( MObject & obMaterial );
  static MStatus    RegisterTexture( MObject & obTexture );

// END MShadingGroup.h

(Awaiting permission to post MShadingGroup source code. No guarantees, tho', sorry.)


Registering the Render Nodes

You will also need to "register" the Material and Texture node so it appears in the MultiLister (and possibly Hypershade) in the UI. This is not at all obvious when you first start creating shading networks via the API (nor is it documented):

Create a Material in Maya's UI and take a look at its DG in the Hypergraph (use Rendering->Show Materials). You will see a connection to a "defaultShaderList" node from the ‘.message’ attribute of the Material. Now create a Texture and use Rendering->Show Textures. In this case a connection exists from the Texture's ‘.message’ attribute to a ‘.textures’ array attribute of a defaultTextureList node. These are the connections you need to make to "register" the node to the UI.

I cannot provide the source code for all of MShadingGroup, but I will offer the member function that "registers" a Shading Node to get you started:

// ***********************************************************************
//     Created: Tuesday, February 27, 2001   By: Bryan Ewert
//              ©2001 H2O Entertainment Corporation
//
//    Function: MShadingGroup::RegisterRenderNode
//
// Description: Registers a Material or Texture node with Maya's UI by
//              creating a connection to the "defaultShaderList" or
//              "defaultTextureList", as appropriate.
//
//       Input: MObject & obRenderNode: The node to register.
//              MFn::Type type: The nodeType of the destination plug.
//                              Specify MFn::kShaderList to register a Material.
//                              Specify MFn::kTextureList to register a Texture.
//              MString & attr: The name of the source plug.
//                              Specify "shaders" to register a Material.
//                              Specify "textures" to register a Texture.
//
//      Output: (MStatus)
//
**************************************************************************
MStatus MShadingGroup::RegisterRenderNode( MObject & obRenderNode, MFn::Type type, MString & attr )
{
  MStatus                     status;
  MDGModifier                 dgModifier;

  // Find defaultShaderList or defaultTextureList.
  MItDependencyNodes          itDependNode( type );
  MObject                     obShaderList;
  obShaderList = itDependNode.item( &status );

  MFnDependencyNode           fnDependNode( obShaderList );
  MPlug                       plugAttr, plugAttrElement;
  MPlug                       plugMessage;
  int                         nextAvailable;

  plugAttr = fnDependNode.findPlug( attr, &status );

  nextAvailable = 0;

  // Loop until an available connection is found
  while( true )
  {
    plugAttrElement = plugAttr.elementByLogicalIndex( nextAvailable, &status );

    // If this plug isn't connected, break and use it below.
    if ( !plugAttrElement.isConnected() )
      break;

    nextAvailable++;
  }

  fnDependNode.setObject( obRenderNode );
  plugMessage = fnDependNode.findPlug( "message" );

  // Connect '.message' plug of render node to "shaders"/"textures" plug of default*List
  dgModifier.connect( plugMessage, plugAttrElement );

  status = dgModifier.doIt();

  return status;
}

It's also a good idea when you are prompted to create a shading network that you query for the existence of a network that already uses the specified File texture. That way you don't end up with multitudes of Shading Groups that describe exactly the same image.


Related How-To's

Wednesday, October 10, 2001