We will continue adding to the scene of the last tutorial by adding
a box to the scene, moving the original sphere so that it sits on top of the box, then
rotating and moving the box. The sphere will be hierarchically linked (or 'glued') to the
box so that the sphere moves in unison when the box is moved.
First, a unit-sized box object is added to the scene and an instance
derived from it:
Next we will show how to hierarchically attach the original sphere
to this new box instance. In terms of a parent/child relationship, the sphere instance
will be the 'child' and the box will be the 'parent'. By doing so the sphere will move in
lock-step unison as the box is moved.
NuGraf imposes a strict rule that no instance can be directly
attached to any other instance. Rather, instances must be attached together to form a tree
structure (a directed acyclic graph) using 'empty instances'. These 'empty
instances' can be thought of as normal instances but without any corresponding geometry;
they are used as building blocks to connect parts of a hierarchy tree together.
To create a hierarchy in which the sphere instance is a child of the
box instance we must build a hierarchy tree that looks like Figure 1.1.
Figure 1.1:
This tree is created by adding two empty instances to the scene
using the command, creating instances of the box and sphere objects with the command, then
attaching the new instances together in a tree structure using the command. This may seem
overly complicated just to attach two instances together but it provides unlimited freedom
when applying transformations to this hierarchy later on (among other important reasons).
The C code to create the tree structure follows below:
{
/* Create the empty instance nodes that will be used to connect the */
/* various parts of the tree together */
Ni_Add_Empty_Node(Nt_INSTANCE, "Empty Instance #1", Nt_CMDEND);
Ni_Add_Empty_Node(Nt_INSTANCE, "Empty Instance #2", Nt_CMDEND);
/* Create the branch of the tree by connecting the empty (null) */
/* instances together in a hierarchy. */
Ni_Attach(Nt_INSTANCE, "Empty Instance #1",
Nt_INSTANCE, "world", Nt_CMDEND);
Ni_Attach(Nt_INSTANCE, "Empty Instance #2",
Nt_INSTANCE, "Empty Instance #1", Nt_CMDEND);
/* These statements create instances of the geometry */
Ni_Add_Instance(Nt_INSTANCE, "sphere inst",
Nt_OBJECT, "sphere object", Nt_CMDEND);
Ni_Add_Instance(Nt_INSTANCE, "box inst",
Nt_OBJECT, "box obj", Nt_CMDEND);
/* Now attach the non-empty instances to the branches so that they */
/* become leaves of the tree. */
Ni_Attach(Nt_INSTANCE, "box inst",
Nt_INSTANCE, "Empty Instance #1", Nt_CMDEND);
Ni_Attach(Nt_INSTANCE, "sphere inst",
Nt_INSTANCE, "Empty Instance #2", Nt_CMDEND);
}
Now the sphere instance is indirectly attached to the box instance,
and the box instance is indirectly attached to the 'world' instance. The only problem now
is that the sphere is sitting inside the box. What we would like to do is translate the
sphere upwards in the Y direction so that its bottom is flush with the top of the cube.
Objects and instances can be transformed using the Ni_Transform
command. This command appends a 4x4 modeling transformation to the object's or instance's
current transformation matrix. Note that objects and their derived instances do not share
the same transformation matrix, but rather they have their own copy (however, when an
instance is first derived from an object its transformation matrix is copied from the
master object).
Note that we have a choice of either applying the translation to the
sphere instance itself or to its parent 'Empty Instance # 2'. As a general rule, if an
instance is contained within a hierarchy tree then any transformations should be applied
to its parent empty instance. The reason for this is simple: if another instance were
to be attached to 'Empty Instance # 2' in the future then it will inherit this
translation; this would not happen if the translation was applied to the sphere instance
itself.
In the following example we will translate the parent instance of
the sphere instance upwards 1.5 units in the Y direction.
{
Nd_Vector translate_amount;
/* Translate the sphere upwards in Y */
translate_amount[0] = 0.0; /* X translation amount */
translate_amount[1] = 1.5; /* Y = Box height + Sphere radius */
translate_amount[2] = 0.0; /* Z translation amount */
Ni_Transform(Nt_INSTANCE, "Empty Instance #2", Nt_POSTMULTIPLY,
Nt_TRANSLATE, translate_amount, Nt_CMDEND);
}
As another example of the command, we will rotate the box and sphere
instances 10 degrees clockwise about the Z axis. Note that the rotation is being applied
to the parent empty instance of the box instance so that the rotation gets inherited by
both the box and sphere instances.