One of the most basic tasks performed in the viewport is that of duplicating, or cloning, scene objects. Most of the tasks users can perform in the viewports can also be done via MAXScript.
It should be noted that copy and instance are supported by multiple data types and not just scene objects as they are
represented in MAXScript. For instance, you can copy strings, colors, bitarrays, angleaxis values, and so on. This section will deal with copying primitive scene objects. You should consult the MAXScript Reference documentation for details on what other data types can be duplicated.
It is assumed that you know how to use copy, instance, and reference 3ds Max manually.
Copy
The syntax for the copy command is as follows:
copy <node>
To copy an object:
1. For this first example, reset 3ds Max, and open up the MAXScript Listener. In the Listener, type the following:
b = box heightsegs: 8
This will create a standard box with 8 height segments. The height segments will be used later in the tutorial.
2. Type the following:
c = copy b
This creates a copy of the box. It is located in the same position as the original box b.
3. Type the following:
move c [25,0,0]
Now, by inspecting the new box (variable c) you can see that the box is separate from the original. Any changes to box c have no effect on box b. The copied box has all of its own properties, modifiers, and so forth, and they can be changed without affecting the original or other copies.
In this example, you called the move function separately so you could visually see the different boxes. However it is possible to combine the two lines of code into one line with the following code:
d = copy c pos: [50,0,0]
This creates a copy of box c in a different location.
Copy, Instance, and Reference ■
71 Instance
The syntax for the instance command is as follows:
instance <node>
Continue with the previous example. However, this time you create an instance of the box b.
To instance an object:
1. In the Listener, type the following:
i = instance b pos: [0,25,0]
This creates an instance of the original box (box i), which is located at the origin. The instance is located at the position you set in the Listener.
2. Type the following:
addmodifier i (bend())
3. Select the instanced box and switch to the Modify Command Panel. Change the parameters of the bend modifier and observe the results in the viewport.
The changes you make to box i also update box b. Conversely, the changes you make to box b also update box i. This is classic behavior for an instanced scene object. Instances share properties, modifiers, materials and maps, and animation controllers with the original object, but not transforms, space warps, or pathnames.
4. To proceed to the next example, you must remove the bend modifier. In the Listener, type the following:
deletemodifier i 1
The deletemodifier function took the instanced value as the first argument. The second argument is the index of the modifier you want to delete. The index of the top modifier on the stack is the number one and increases towards the bottom of the modifier stack.
Reference
The syntax for the reference command is as follows:
reference <node>
Continue with the previous example.
To reference an object:
1. In the Listener, type the following:
r = reference b pos: [0,-25,0]
This creates an reference of the box, located apart from the original box at the origin.
2. Type the following:
addmodifier r (bend())
Notice that box r now has a bend modifier, but box b does not. You can think of the referenced box r as a child object and the original box b as a parent object. Changes made to the parent object will affect the child object, but any change to the child object will not affect the parent object.
3. Select the referenced box, and switch to the Modify Command Panel. Change the parameters of the bend modifier and observe the results in the viewport.
Changes to the modifier on box r do not affect box b in any way (because box b has no modifier).
4. Type the following:
b.height = 40.0
Notice that the change is propagated to both boxes. That is classic behavior for a referenced object.
Cloning Nodes Using MaxOps.CloneNodes
There is another, more complete method to clone nodes in MAXScript. The methods shown above are useful for simple objects, but you can get unexpected results when cloning objects with hierarchies, such as a light with a target. You can use the MaxOps.CloneNodes method to maintain interdependencies such as parent child links between objects in the scene. The syntax for this method is:
maxOps.CloneNodes <array of nodes> clonetype: <enum> newNodes: <&array of nodes>
actualNodeList: <&array of nodes> offset: <point3> ...
This function will return true if successful or false if unsuccessful.
Note: There are more optional parameters than listed here. To keep things simple, only a few are covered.
Some of the MaxOps.CloneNodes parameters are:
• <array of nodes>—The array of nodes that you want to clone. However, if you pass in a single object, the function will detect this and automatically wrap it in an array.
• clonetype: <enum>—This parameter expects one of three values: #copy, #instance, or #reference. The default is #copy.
• newNodes: <array of nodes>—This node array will be filled with the new cloned nodes.
• actualNodeList: <array of nodes>—You will pass in an empty array for this optional parameter, which will be filled with the actual nodes that are cloned. The reason is that there can be dependencies between nodes that cause other nodes to be added to the list, for example, between light and camera targets, nodes parts of systems, part of groups, or expanded hierarchies.
• offset: <point3>—This moves the new node by the supplied point3 vector. This could be used to differentiate the new cloned nodes from the old nodes.
To demonstrate the difference between using the normal copy method versus the maxOps.CloneNodes method:
1. Reset the 3ds Max scene, and open the MAXScript Listener.
2. Create one targeted spot light in the 3ds Max scene.
3. Select the light. Do not select the target of the light.
4. In the Listener, type the following:
a = $ c = copy a move c [0,25,0]
A duplicate light is created, but it shares the original target. MaxOps.CloneNodes must be used to clone the target too.
5. Type the following:
maxops.cloneNodes a actualNodeList: &ANL clonetype: #copy \ offset: [-25,-25, 0] newNodes: &NN
A new light is created, with its own target.
6. Type the following:
print ANL
This prints two objects—the light and its target. In this example, you passed in one light object as the first argument. You passed in the address of an uninitialized array “&ANL” as the actualNodeList parameter. The function filled the array with the old light and the old light target. This ANL array is generally useful for inspection.
7. Type the following:
select NN
Copy, Instance, and Reference ■
73
The new light and its target are selected in the scene. You also passed in the address of an uninitialized array “&NN” as the newNodes parameter. The function filled the array with the new light and the new light target. After calling this function, you can manipulate your new node in the array as usual.
For more information, see the following section in the MAXScript Reference Help:
MAXScript Language Reference > 3ds Max Objects > Interfaces > Core Interfaces > Core Interfaces Pages > Interface:
MaxOps.