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,


Log in to reply