Using the Node and Object Offset Transformations
 
 
 

The following code is from the Reset Transform utility (\MAXSDK\SAMPLES\MODIFIERS\RESETTM.CPP). This utility is used to push object rotation and scale values onto the Modifier Stack and align object pivot points and bounding boxes with the world coordinate system. Reset Transform removes all rotation and scale values from selected objects and places those transforms in an XForm modifier. The code below demonstrates the use of the node transformation and object offset transformations discussed above.

As previously noted, there are two transforms that affect an object: the node transform which is the result of the transform controller plus inheritance, and the object offset transform which positions the geometry relative to the pivot point.

The Reset Transform utility takes the node transform (minus inheritance), and the offset transform, and combines them into a matrix which is given to an XForm modifier which is then placed at the top of the modifier stack.

The node and offset transforms can then be set back to the identity (actually, the position component of the node TM is left unchanged). Here is the code -- it operates on all the selected nodes.

for (int i=0; i<ip->GetSelNodeCount(); i++)
{
   INode *node = pi->GetSelNode(i);
   Matrix3 ntm, ptm, rtm(1), piv(1), tm;
 
   // Get Parent and Node TMs
   ntm = node->GetNodeTM(ip->GetTime());
   ptm = node->GetParentTM(ip->GetTime());
 
   // Compute the relative TM
   ntm = ntm * Inverse(ptm);
 
   // The reset TM only inherits position
   rtm.SetTrans(ntm.GetTrans());
 
   // Set the node TM to the reset TM 
   tm = rtm*ptm;
   node->SetNodeTM(ip->GetTime(), tm);
 
   // Compute the pivot TM
   piv.SetTrans(node->GetObjOffsetPos());
   PreRotateMatrix(piv,node->GetObjOffsetRot());
   ApplyScaling(piv,node->GetObjOffsetScale());
 
   // Reset the offset to 0
   node->SetObjOffsetPos(Point3(0,0,0));
   node->SetObjOffsetRot(IdentQuat());
   node->SetObjOffsetScale(ScaleValue(Point3(1,1,1)));
 
   // Take the position out of the matrix since
   // we don't reset position
   ntm.NoTrans();
 
   // Apply the offset to the TM
   ntm = piv * ntm;
 
   // Apply a derived object to the node's object
   Object *obj = node->GetObjectRef();
    IDerivedObject *dobj = CreateDerivedObject(obj);
 
   // Create an XForm mod
   SimpleMod *mod = (SimpleMod*)ip->CreateInstance(
   OSM_CLASS_ID,
   Class_ID(CLUSTOSM_CLASS_ID,0));
 
   // Apply the transformation to the mod.
    SetXFormPacket pckt(ntm);
   mod->tmControl->SetValue(ip->GetTime(),&pckt);
 
   // Add the modifier to the derived object.
   ModContext* mc = new ModContext(new Matrix3(1), NULL, NULL);
   dobj->AddModifier(mod, mc);
 
   // Replace the node's object
   node->SetObjectRef(dobj);
}