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); }