Lesson 2: The Scene Graph and Nodes
 
 
 

In a 3ds Max scene the objects that a user can create and manipulate in the viewports are called scene objects. Scene objects derive from the Object class. Examples of scene objects are geometric objects (GeomObject), lights (LightObject), cameras (CameraObject), particles, and world space modifiers (not to be confused with regular modifiers). Scene objects can have parent-child relation to form a hierarchy and let user create compund objects. Transforms applied to the parent are also transmitted to child objects. You can refer to Animation > Hierarchies and Kinematics > Hierarchies in the 3ds Max online reference to review the parent-child relation among the scene objects from the user's perspective.

3ds Max stores the information about the scene objects as well as their relation to each other in a data structure named the Scene Graph. Each node of this graph is an object of the class INode that corresponds to one scene object. Each INode object has information about its corresponding scene object including (but not limited to) a pointer to the object, number of the child nodes, address of the parent and the child nodes, the position, rotation and scale (PRS) transform controllers for that object and the material applied to the object. Note that the nodes in the scene graph are not the real scene objects but have a pointer to their corresponding scene objects. The scene objects themselves do not have any information about their PRS controllers, their materials, their relation to the other objects, etc.

The edges of the scene graph are directed edges that are called links in 3ds Max. There is a link from node A to node B if the state of node A (e.g. position, rotation, scale, material, etc) depends on that of node B. Each object can be followed or linked by many objects but can link to only one object. No loop is allowed in the links of the nodes. These together make the scene graph a tree data structure. The root of this tree is a virtual node that is not linked to to any other node (the only exception). The nodes corresponding to the independent scene objects that do not have a parent object in the scene are the first level nodes in this tree. Even if their object is instantiated from their classes, the scene objects do not get displayed in the viewport unless theye have a corresponding node in the scene graph.

The INode class is an important class of the 3ds Max SDK and has a large number of member functions. In this lesson we review a small set of INode's member functions to get familiar with the basics of the scene graph and nodes. You can refer to the programmers' guide topic Scenes and Nodes or the INode reference guide for detailed information about the INode class.

You can access the root node of the scene graph using the function Interface::GetRootNode(). Once you get a pointer to a node, there are many functions to get the information on its scene object. Few examples of these functions are:

In the example plug-in of this lesson, we create a scene export plug-in that writes the information about all the nodes in the scene graph. In the plug-in wizard we select the 'File Export' plug-in type, and choose the 'Scene Export' for the base class. This class has a number of simple functions that return basic information about the scene exporter plug-in such as the type of the file to be generated, descriptions of what the exporter does, number of file types supported, etc. The most important function that we need to implement is SceneExport::DoExport(). 3ds Max calls this function to do the main export job.

The project in the compressed file Lesson2.zip shows the plug-in implementation. We use three helper functions named SampleExp::BeginWriting(), SampleExp::Write() and SampleExp::EndWriting() to open the file to be written to, write a message to the file and to close it. When our plug-in is selected to be used for export, 3ds Max takes care of the file selection UI and gives us the file name in its call to SceneExport::DoExport(). We implement a recursive private member function named SampleExp::Export() to help us exporting the scene graph information. This function inputs a pointer to a node in the scene graph, writes its name and the number of its child notes in the text file, and then calls itself on each of the child nodes of the input node. This way all the nodes will have their name and the number of children written in the text file if we call this function for the root node. It will be a depth-first search since the recursive function is called on the children of the node right away after writing the node's info and before writing the inormation of the sibling nodes. The following code shows the implementation of this function:

void SampleExp::Export(INode* pNode, int iTreeDepth)
{
    MCHAR* pNodeName = pNode->GetName();
    int nChildren = pNode->NumberOfChildren();

    Write(iTreeDepth, "[%s] : %i children", pNodeName, nChildren);

    iTreeDepth++;
    for (int i = 0; i < nChildren; i++)
    {
        Export(pNode->GetChildNode(i), iTreeDepth);
    }
}

The variable iTreeDepth in the above code stores the level of the current node and is used to format the output. The number of tabs printed at the start of each node info is the same as the node level. The lower in the scene graph a node is, more indented its info in the output file will be. Also the SampleExp::Export() is called on the root node in its first call in the SampleExp::DoExport() function:

int SampleExp::DoExport(const TCHAR *name,ExpInterface *ei,
    Interface *i, BOOL suppressPrompts, DWORD options)
{
    ...
    INode* pRootNode = i->GetRootNode();
    Export(pRootNode);
    ...
}