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,