Traversing the Scene

 

 

When you work within any graphics API, the obvious question is how you go about acessing any of the data. The Maya API presents you with methods, that at first seem a little quirky. With a little bit of practice, it soon makes sense.

All data within maya is contained within seperate connectable nodes (in maya terminology, dependency nodes). All of these node types, are defined by the enumeration MFn::Type. For example, a textured polygonal mesh may be constructed from

 

  • an MFn::kMesh node for the polygonal surface shape
  • an MFn::kTransform to position the mesh in the scene
  • an MFn::kLambert node for the surface material
  • an MFn::kFileTexture node for the surface texture

 

If at anytime, you need to find out how a set of nodes are connected, then you can use the hypergraph within maya, to show you a graphical representation of the scene data. It is worth remembering that the hypergraph only displays connections between attributes; It does not show the connections between a transform and the child objects underneath it. The outliner can do that for you.

 

Something to bear in mind when working with the API, is that your plugin will not have direct access to the Maya scenegraph. Instead we reference nodes in Maya by using a special handle type, MObject. The MObject really does nothing of interest except allow us to find out what type a given node type is, or if it is convertable to another node type. The MObject member functions, apiType(), apiTypeStr() and hasFn() allow you to do this.

 

 

 

 

Iterating the Maya Scene

As previously mentioned, a maya scene is simply a collection of nodes that represent our data. At some point, we will need to find out what nodes exist in the scene. To do this we must use one of the Maya iterator types.

All of the iterator types within the Maya API are prefixed with MIt. Some of these iterators are used for iterating through the scene nodes, others are used to iterate over specific data contained within a node.

Quite often, you will find that specialised iterators exist to help you step over the nastier parts of the API, in a much more generic way.

To start with we will look at the most generic of the iterators, MItDependencyNodes. This class can be used to iterate through each node in the scene, or to iterate over a specific type of node in the scene.

 

 

 

 


#include<iostream>
#include<maya/MItDependencyNodes.h>
#include<maya/MLibrary.h>
#include<maya/MFileIO.h>

int main(int argc,char** argv)
{
 

if(argc!=2) return 0;

// initialise the maya library
MLibrary::initialize(argv[0]);

// use the second arg as the filename.
if( MFileIO::open(argv[1])==MS::kSuccess ) {
 

// create an iterator to go through all nodes
MItDependencyNodes it(MFn::kInvalid);

// keep looping until done
while
(!it.isDone())
{
 

// get a handle to this node
MObject obj = it.item();

// write the node type found
cout
<< obj.apiTypeStr() << endl;

// move on to next node
it.next();

}

}

// cleanup maya
MLibrary::cleanup();

return 0;

}


 

 

Iterating Specific Node Types

When you create a dependency node iterator, if you specify the type MFn::kInvalid, then it will iterate over every single node within the Maya Scene.

If however you specify a specific MFn::Type as the construction parameter, it will iterate over nodes of that type.

This code example only walks over the mesh types. Notice that only the construction parameter has changed since the previous example.

 

 

 

 

 

 

 

 

 

 

 


#include<iostream>
#include<maya/MItDependencyNodes.h>
#include<maya/MLibrary.h>
#include<maya/MFileIO.h>

int main(int argc,char** argv)
{
 

if(argc!=2) return 0;

// initialise the maya library
MLibrary::initialize(argv[0]);

// use the second arg as the filename.
if( MFileIO::open(argv[1])==MS::kSuccess ) {
 

// create an iterator to go through all nodes
MItDependencyNodes it(MFn::kMesh);

// keep looping until done
while
(!it.isDone())
{
 

// get a handle to this node
MObject obj = it.item();

// write the node type found
cout
<< obj.apiTypeStr() << endl;

// move on to next node
it.next();

}

}

// cleanup maya
MLibrary::cleanup();

return 0;

}


 

 

Attaching Function Sets

As previously mentioned, you will always get access to a node within Maya via the use of a handle type, MObject. We have no way of accessing the data on the node directly, instead we have to use a specialised function set for that type.

 

In this example the hasFn method of MObject is used to determine if this node can be accessed by the function set for a transform. If it can, then we are free to attach an MFnTransform function set to the node. We are now able to access all of the transform data by calling the member functions of the function set, fn.

 

 

 

 

 

 


#include<maya/MEulerRotation.h>
#include<maya/MString.h>
#include<maya/MVector.h>
#include<maya/MFnTransform.h>

void OutputTransform(MObject& obj)
{
 

// check to see if this node is a type of transform
if
(obj.hasFn(MFn::kTransform) {

 

// attach a function set for a transform to the
// object. Rather than access data directly,
// we access it via the function set.

MFnTransform fn(obj);

// get the name of the transform node
MString
name = fn.name();

// write the node type found
cout
<< "xform: " << name.asChar() << endl;

// write the translation values
MVector T = fn.translation(MSpace::kObject);
cout <<"\t"<<T.x<<" "<<T.y<<" "<<T.z<< endl;

// write the scale values
double S[3];
fn.getScale(S);
cout <<"\t"<<S[0]<<" "<<S[1]<<" "<<S[2]<<endl;

// write the euler rotation values
MEulerRotation r;
fn.
getRotation(r);
cout <<"\t"<<r.x<<" "<<r.y<<" "<<r.z<< endl;

}

}

 

 

Generically Accessing Parenting Information

You will often hear of dependency graph (DG) and directed acyclic graph (DAG) nodes when dealing with Maya. simply put, every node in Maya is a DG node. It simply means that they can recieve input and output connections from other nodes and attributes.

 

A DAG node on the other hand, is something that physically exists within the scene. This basically breaks down into two catagories, shapes and transforms. For example, meshes, locators and cameras are all considered to be shapes, since they are transformed into position. A lambert shader node however is not a DAG node, since it is only a surface property applied to a DAG shape.

 

With any scene graph it is vital that we know how to determine the transform hierarchy. Within maya this is fairly trivial to achieve using the MFnDagNode function set.

 

In maya you can query both the number of children, and the number of parents on each node. It may seem odd that there may be multiple parents, but this is merely a way to support instancing.

 

Between this function and the previous one, you should have a pretty good idea of how to read back a basic scene hierarchy from Maya.

 

 

 

 

 

 

 


#include<maya/MObject.h>
#include<maya/MString.h>
#include<maya/MItDag.h>
#include<maya/MFnDagNode.h>

void OutputParentingInfo()
{
 

// use an iterator to walk over the DAG nodes only.
// we can use MItDag for this.....

MItDag
it(MItDag::kDepthFirst);


// loop through all nodes

while
(!it.isDone()) {

 

// attach a function set for a dag node to the
// object. Rather than access data directly,
// we access it via the function set.

MFnDagNode fn(it.item());

// get the name of the node
MString
name = fn.name();

// write the node type found
cout
<< "node: " << name.asChar() << endl;

// write the info about the children
cout <<"num_kids " << fn.childCount() << endl;

for(int i=0;i<fn.childCount();++i) {

  // get the MObject for the i'th child
MObject child = fn.child(i);

// attach a function set to it

MFnDagNode fnChild(child);

// write the child name

cout << "\t" << fnChild.name().asChar();
cout << endl;

}

// write the info about the parents
cout<<"num_adults "<< fn.parentCount() << endl;

for(int i=0;i<fn.parentCount();++i) {

  // get the MObject for the i'th parent
MObject parent = fn.parent(i);

// attach a function set to it

MFnDagNode fnParent(parent);

// write the parent name

cout << "\t" << fnParent.name().asChar();
cout << endl;

}

// move to next node
it.next();

}

}

 

 



 

 

What Next?

Accessing Attributes

How To Access Connections Between Attributes

index

Rob Bateman [2004]

[HOME] [MEL] [API]