Pipeline Overview

This topic describes the 3ds Max pipeline architecture in high-level terms.

The diagrams in this topic show the relationship between scene nodes and scene objects in the pipeline. Each node (INode) in the scene has a reference to a Max object (Object). The arrows show the references between nodes, objects, modifiers, and world space modifiers.

Objects flow through the pipeline from the bottom up. The first object to enter into the pipeline is called the 'Base Object'. The result of applying a modifier to an object is represented by a 'Derived Object' (IDerivedObject). The end result of the pipeline is the Node (INode). A derived object has a reference to a base object or another derived object, and has a reference to the modifier.

The following diagram shows the pipeline of an unmodified Cylinder object in the scene. In this case the node's object reference points directly to the base object, the cylinder. The pipeline flow is against the order of the arrows.

Shared Objects in Different Pipelines

The following figure shows two pipelines. Note how the object reference of the instanced copy points to the same base object as the original. If the creation parameters of the Cylinder are changed, both nodes will change in the scene since they both point at the same Base Object.

Modifiers in a Pipeline

You can apply one or more modifiers to the objects in a pipeline. The following figure shows the pipeline resulting from applying a Bend object space modifier to a Cylinder. When a modifier is first applied, a new derived object (IDerivedObject) is inserted into the node's pipeline.

This arrangement appears in the modifier stack as shown in the following figure:

This indicates that the base object of the pipeline is the Cylinder. The horizontal line above the word "Cylinder" in the figure indicates the start of a derived object. The Bend is the modifier referenced by this derived object.

Modifier Application (ModApp)

A derived object consists of one or more applications of modifiers followed by a reference to another object. This other object may be a base object or another derived object. In the figure preceding the above screen capture, the derived object has a single application of a modifier, the Bend. This application of a modifier is referred to as a ModApp. The ModApp consists of a modification context (MC) and a reference to a modifier -- in this case the Bend. Note that the modifier is not in the pipeline, but is referenced by the ModApp that is in the pipeline.

Note:

A ModApp is not directly exposed in the 3ds Max SDK.

Modifier Context (ModContext)

The modification context (represented by the ModContext class) holds the data needed by each individual instance of the modifier. The MC stores information about the space the modifier was applied in, and allows a modifier instance to store the unique data that it needs to operate.

The MC stores three items, as shown in the diagram below, and then described following the diagram.

Multiple Modifiers

More than one modifier may be applied to an object. The following figure shows the previous bent cylinder with an additional Taper modifier applied.

The modifier stack for Cylinder01 for the above figure would appear as:

In this case a new ModApp is inserted into the existing Derived Object. The modifier reference of the new ModApp points to the Taper modifier.

Reference Copies

3ds Max also allows Reference Copies of items in the scene. When a Reference Copy is made, a new Derived Object is inserted into the item's pipeline. Modifiers applied to the Reference Copy will have their ModApps inserted into the new Derived Object. The following figure shows the result of a bent cylinder being Reference-Copied and having a Taper modifier applied. Note that the object reference of the new Derived Object points to the original Derived Object.

Note the two occurrences of the line (above Cylinder) indicating that two Derived Objects are in use. The original one points to the Bend while the new one points to the Taper.

Sharing Modifiers

A modifier object may be used by several objects. When the 3ds Max user applies a modifier to more than one object simultaneously, one instance of the modifier's class is created and shared among the objects. Each object that the modifier is applied to automatically acquires a new ModApp in its pipeline. These ModApps then reference the same modifier.

In the screen capture and diagram below, the user has selected two independent Cylinders in the scene, checked the 'Use Pivot Points' box, and applied a Bend modifier.

Note that each cylinder has its own Derived Object. The modifier reference of each ModApp points to the same instanced modifier however. The ModApp also stores the ModContext (labeled 'MC' in the diagrams). One data member of this ModContext is the bounding box of the deformation. Because the 'Use Pivot Points' button was checked at the time the bend was applied, each bounding box stored in the ModContext is the size of each cylinder alone. Additionally, the transformation matrix of each ModContext reflects that the bend is to be applied to each cylinder in its own space. The result is the bend is applied locally and independently to each cylinder.

Contrast this with the following case. In the screen capture, below, the user applied the Bend modifier to the cylinders as follows: First the independent cylinders were selected. Then the 'Use Pivot Points' button was unchecked. Then the Bend modifier was applied. This means the bend will be applied to the entire selection set as a whole. Note that the cylinders are bent about a common center.

In this case the bend is applied relative to the bounding box of both cylinders. Thus the bounding box of the ModContexts are the same for each cylinder. Note what happens if one cylinder is moved away from the other in the scene. The Modifer is selected so the gizmo shows the bounding box graphically. The bounding box remains the size of both even when the objects no longer share the same world space relationship.

The separation of the ModApps from the Modifier allows this flexibility. The bounding box stored with the ModContext of the ModApp represents the scale of the application of the modifier. The transformation matrix of the ModContext represents the space the modifier was applied in. The instanced modifier just uses this information to properly modify each input object.

World Space Modifiers

Below is a diagram of a Cylinder and a Ripple Space Warp before the Cylinder has been bound to the space warp. Note that world space modifiers have their own nodes in the scene graph and have a gizmo representation in the viewport but are not part of the rendered scene.

The following diagram shows the pipeline of the Cylinder after it has been bound to the Ripple Space Warp.

The modifier stack for this condition would appear as follows:

Ripple Binding
----------
Cylinder

The Cylinder is the Base Object. The line (----------) represents the beginning of a world space modifier derived object. The Ripple Binding is the actual application of the world space modifier.

When the Cylinder is bound to the Ripple a new world space modifier derived object is inserted into the Cylinder's pipeline. The world space modifier derived object is similar to the derived objects that hold object space modifier ModApps except that these are contained in a specific node (world space modifier object is in fact the exact same class as derived object except for the ClassID()). Since they are associated with a specific node, they cannot be instanced.

The modifier reference of the ModApp points to a newly-created world space modifier. This world space modifier usually has a reference to the node in the scene. In this case it is to the Ripple01 node. This reference is used to retrieve the position of the node (from the node's world space transformation matrix). It uses this matrix to transform the points of the object it is deforming into the space of the WSM object where it actually performs the deformation.

Example of Pipeline Data Flow

This following presents a detailed look at the flow of the pipeline from the Base Object to the resulting World Space Cache. This includes the derived objects of the object space portion of the pipeline, the application of the node's transform controller, and through the world space portion of the pipeline.

The diagram below shows a procedural Cylinder with a Bend modifier applied, and bound to a Ripple space warp.

The data flow in the pipeline follows the object references. In the example above, the Cylinder01 Node has an object reference pointing to the world space modifier object. Its object reference points to the Derived Object. Its object reference points to the Cylinder Base Object. This is the path the data follows as it moves along the pipeline.

The actual object that flows between these references is an ObjectState. The ObjectState is the result of the Object::Eval() method being called on the object reference.

This pipeline starts at the Base Object -- the Cylinder. The system asks the cylinder to evaluate itself. In the cylinder's implementation of Object::Eval(), it simply returns itself ( returnObjectState(this); ). It returns this ObjectState to the next object reference in the pipeline. This is the object reference of the derived object.

The Derived Object sends this ObjectState through each of its ModApps. In this example, the only ModApp is for the Bend Modifier. The Bend requires Deformable objects (it indicates this in its implementation of Modifier::InputType()). The ModApp handles converting the object to the appropriate type for the Modifier. The cylinder is asked to convert itself to a Deformable object. It does this in its implementation of Object::ConvertToType() by creating a new TriObject and setting the TriObject's mesh pointer to point at the cylinder's triangle mesh.

This Deformable TriObject is then sent through the Bend Modifier. The Bend is passed the ModApp's ModContext as an argument to its Modifier::ModifyObject() method. The Bend first modifies the points of the TriObject using the transformation matrix of the ModContext. This puts the object into the space the modifier was applied in. Next the Bend applies its deformation to the points (it bends them). Then the Bend modifies the points of the TriObject by the inverse of the ModContext transformation matrix. This restores the object, excepting it now has the bend effect applied.

At this point, the Derived Object returns the result to the next Object Reference in the pipeline. In this case the result is a TriObject that has been bent. It is returned to the Object Reference of a World Space Derived Object.

This juncture between the Derived Object and the World Space Modifier Derived Object is where the pipeline crosses from object space to world space. At this point the result of the node's transform controller, and the object offset transformation are put into the pipeline. For more details on these various transformation matrices see the Advanced Topics section on Node Transformations.