Nonuniform scaling - dilemma

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 08/05/2006 at 17:02, xxxxxxxx wrote:

User Information:
Cinema 4D Version:   9.102 
Platform:   Windows  ; Mac  ;  Mac OSX  ; 
Language(s) :     C++  ;

---------
I've found probably the best solution available for handling shear in nonuniform scaling - SoftImage 'SI transformation' as it's called. It works by sort of rearranging the concatenation of transformation matrices - from classical (in C4D concatenation order) :

A(global) = B(global) x A(local)

to 'SI':

A(global) = AB(pos) x B(rot) x A(rot) x B(scale) x A(scale)

where AB(pos) = MatrixMove(A(pos) * B(global))

This works for the most part, but scaling gets wonky as the hierarchy gets deeper. And I can't seem to understand why this occurs, so here is an example of my code which sets the 'bone' rotation:

// IPPDial.UpdateRotation  
//*---------------------------------------------------------------------------*  
void IPPDial::UpdateRotation(BaseObject* obj, UCHAR sub, Real value)  
//*---------------------------------------------------------------------------*  
{  
// Get the changed rotation component  
     BaseContainer*     bc =     obj->GetDataInstance();  
     Vector               rotV =     bc->GetVector(IPP_ROTATION);  
     if          (sub == CHAN_SUB_X)     rotV.x =     Rad(value);  
     else if (sub == CHAN_SUB_Y)     rotV.y =     Rad(value);  
     else if (sub == CHAN_SUB_Z)     rotV.z =     Rad(-value);  
     bc->SetVector(IPP_ROTATION, rotV);  
  
// Create an axis-ordered rotation matrix with the updated rotation component  
     Matrix               rot;  
     UCHAR               order =          bc->GetBool(IPP_RORDER);  
     if          (order == ROTORDER_XYZ)     rot = bc->GetMatrix(IPP_ORIENTMATRIX) * MatrixRotZ(rotV.z) * MatrixRotY(rotV.y) * MatrixRotX(rotV.x);  
     else if (order == ROTORDER_XZY)     rot = bc->GetMatrix(IPP_ORIENTMATRIX) * MatrixRotY(rotV.y) * MatrixRotZ(rotV.z) * MatrixRotX(rotV.x);  
     else if (order == ROTORDER_YXZ)     rot = bc->GetMatrix(IPP_ORIENTMATRIX) * MatrixRotZ(rotV.z) * MatrixRotX(rotV.x) * MatrixRotY(rotV.y);  
     else if (order == ROTORDER_YZX)     rot = bc->GetMatrix(IPP_ORIENTMATRIX) * MatrixRotX(rotV.x) * MatrixRotZ(rotV.z) * MatrixRotY(rotV.y);  
     else if (order == ROTORDER_ZXY)     rot = bc->GetMatrix(IPP_ORIENTMATRIX) * MatrixRotY(rotV.y) * MatrixRotX(rotV.x) * MatrixRotZ(rotV.z);  
     else if (order == ROTORDER_ZYX)     rot = bc->GetMatrix(IPP_ORIENTMATRIX) * MatrixRotX(rotV.x) * MatrixRotY(rotV.y) * MatrixRotZ(rotV.z);  
// SI transformation  
     Matrix               mg =          obj->GetUpMg();  
     mg =               MatrixMove(obj->GetPos()*mg) * HPBToMatrix(MatrixToHPB(mg)) * rot * MatrixScale(Vector(Len(mg.v1),Len(mg.v2),Len(mg.v3))) * MatrixScale(obj->GetScale());  
     obj->SetMg(mg, FALSE);  
     obj->Message(MSG_UPDATE);  
}

For position and scale, the same basic format applies for the SI transformation. If anyone can spot an error or has a better algorithmic approach, love to hear about it.

Thanks,