HDK
|
In the simplest form, the world transform of an object is given by
where L
is the object local transform built from its transform parameters, and W0
is the world transform of the object's input node.
Unfortunately, this simple transform formula is not sufficient to capture various transformation possibilities offered by object nodes. For example, an object node can specify a "look at" point that determines the rotation of the object, and L
denotes only the transform parameters, so there is no matrix in that formula that captures the "look at" option.
The "look at" is not the only type of transform that occurs in object nodes. The node may also specify the path object on which it sits, or it may wish to blend several parents together, as is the case for OBJ_Blend node. Another complicating factor is that the blend object requires the idea of an pre-transform that depends on its inputs. The Follow Path object parameter, on the other hand, requires the idea of a pre-transform which does not depend on its inputs (i.e., is input-independent).
One final requirement to take into account is a clean animation of transform parameters. It is often desirable to set a natural orientation of the object for animation. For example, we may wish to animate the x rotation parameter so that a value of 0 corresponds to 45 degrees in reality. This allows animators to work with much more meaningful channel data.
The solution to this is to add an additional pre-transform matrix to the transform model just before the local transformation. This also has the added advantage that now we can perform transform operations on objects without affecting their animation channels by modifying the pre-transform matrix instead. It is a big bonus for things like mirroring and transforming bone objects while preserving existing animation. The disadvantage to this however is that all expressions in objects that tried to maintain a sort of relative position or orientation to an input object must now take into account the pre-transform. For orthogonality, we also provide an output transform for manipulating the transform intended for child objects only.
Taking all these matrices together, the final formula for the world transform is:
where:
W
is the world transform of the object (used for its SOPs and output objects)K
is the look-at rotation matrixP
is the pre-transform matrix (modified by the items in the Pre-Transform menu of the object parameters).Ii
is the input-independent pre-transform matrix.Id
is the input-dependent pre-transform matrix.T0
is the output transform of its connected input object.W0
is the world transform of its connected input object.To use the model described above, we have the following overridable virtual methods in OBJ_Node:
K
, the transform needed to aim the object towards the look-at target. By default it builds a rotation matrix and returns true
to indicate that the look-at matrix needs to be taken into consideration.L
, the local transform formed from the object's transform parameters.Id
to the the given matrix. This transform is defined as semantically dependent on the object's inputs. The OBJ_Blend object overrides this to do special processing. Also, the OBJ_Bone object overrides this to move its origin to the tip of the parent bone. By default, this method does not modify the given matrix, which is equivalent to identity Id
matrix.Ii
to the the given matrix. This transform is defined as semantically independent of the object's inputs. The default implementation applies a follow path object transform if available.P
to the the given matrix. The default implementation checks to see if it should use the pre-transform before actually pre-multiplying.T0
matrix.flags()
.setTimeDep(true) in these method overrides if you compute a value based on the evaluation time explicitly. This is because objects break down the computations into smaller pieces than the entire cookMyObj()
process.There are also a few non-virtual convenience methods that return some combination or accumulation of the object transform model matrices.
K*L*P*Ii
, the effective local transform which does not depend on its inputs. This function cooks the object first and then returns the member variable OBJ_Node::myXform (ie, myXform=K*L*P*Ii
).Id*T0*W0
, the effective world transform of the parent. In terms of methods this is calculated by getParentObject()
is NULL
, then it simply returns applyInputDependentTransform(identity_matrix)
. Use this function to convert co-ordinates that have not been transformed by the follow path or pre-transform. Typically, this function is only used internally for manipulating the pre-transform. If the object is in a subnet, then this will include the subnet's world transform.P*Ii*Id*T0*W0
, which is the transform that is only missing the local and look-at components. In terms of methods this is calculated by W
, which is the full world transform of the object including all the component sub-matrices. This is equivalent to myWorldTransform
. Typically, this function is used to place child SOPs of the object in world space.T0*W0
, which are the transforms provided by the object's parent. This is equivalent to getParentToWorldTransform()
. applyInputDependentTransform()
has no effect: P*Id
which is the portion of the local transform that does not depend on the parameters (transform or look-at). It is not widely used and only relevant for the handles to orient themselves in parent space.The generic OP_Node::cook() method checks if the node has been dirtied by a modified parameter or any other change within dependency chains, and if the node needs to cook it invokes OP_Node::cookMe(). This method is overloaded in OBJ_Node::cookMe() and it checks if there is already a computed and cached matrix available in the global cache. If the matrix is available, it is returned, and if it is not, then OBJ_Node::cookMyObj() method is invoked to perform the calculation of the protected members OBJ_Node::myXform and OBJ_Node::myWorldXform. These member data are later used in calls that query the local and world transforms. In addition, if caching of the node's matrix is enabled (via a node parameter, "caching") then OBJ_Node::cookMe() stores the calculated matrices in the cache. Below is a simplified skeleton of the OBJ_Node::cookMyObj() method.
The primary purpose of the cookMyObj()
method is to compute the OBJ_Node::myXform and OBJ_Node::myWorldXform members. However, when implementing a new object, instead of explicitly calculating these matrices in own version of cookMyObj()
method, it may suffice to override some of the following virtual methods:
Note, that during cooking, the inverse, myIWorldXform
, is not computed, but rather it is dirtied. The method OBJ_Node::getInverseXform() will compute and return the inverse of the OBJ_Node::myWorldXform when it is called the next time.
To support the use of the pre-transform (P
) matrix, there are several utility methods that manipulate that transformation.
L
) to the pre-transform (P
). This does not modify the effective world transform.Note that it is crucial that L
and P
is always next together in the transformation model (i.e., L*P
) without any intervening transformations in order for the above functions to work.