THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 17/08/2004 at 11:58, xxxxxxxx wrote:
Here's the code problematic code (three methods). To the point, this is a conversion from Poser JPs to C4D bones.
The first method, SetupBone(), creates the bones in their default position/rotation based on the Origin/Endpoint for each JP'd body part (that's all we get, folks).
The second method, TransformBone() attempts to rotate the bones from the default position into Pose/Base positions, but hasn't worked consistently yet.
The third method, Align() determines a rotation value to put the C4D bone into a known World axis alignment. It also correlates the red, green, blue axes (since they are not identical to x,y,z) to the correct channel sub type (or Poser axis) wrt the C4D bone.
Background: Poser bones (JPs) ALL start with axes coinciding with the World axes (a bone pointing down the +X axis is rotated along its length by changing the X rotation value). All rotations are in degrees and Euler angles. Each axis gets a JP 'function', as above, X would be the 'twist' axis and is thusly denoted twistX in the file. Also, rotation order is significant in Poser - usually twist/joint/joint - and denoted solely by order in the file.
What do I need to know to get this to work? There seems to be an unreconcilable difference between what I see and how I think (since there is nothing whatsoever detailing C4D bones) they should be rotating.
If noone can explain why the bones rotate contrary to weeks of observation, checking, coding, and calculating, then I will be forced to go higher than this forum and contact Maxon directly for information. This is the third time (and I've heard the same from David Mathews) requesting some sort of information on how C4D bones (PROGRAMMATICALLY! - I don't care a twat about how they work in the GUI - the control is completely different) work in order to obtain predictable results without any responses. The complexity that you see below is a result of all attempts to try to resolve this over the past three weeks. I know where the Poser bones are (and they are created/positioned/rotated properly) and I know where the C4D bones are (including exact rotation) before applying deltas.
// Setup Bone
void PoserBase::SetupBone(void)
{
Vector r, p;
Matrix m;
Vector* aPts;
PolygonObject* aObj;
// Create axis markers
if ((aObj = PolygonObject::Alloc(3,1)) == NULL) throw ErrorException(ERROR_MEMORY, NULL);
baseDocument->InsertObject(aObj, boneObject, NULL, FALSE);
aPts = aObj->GetPoint();
aPts[0] = Vector(1,0,0);
aPts[1] = Vector(0,1,0);
aPts[2] = Vector(0,0,1);
// Rotate bone
r = VectorToHPB(endPoint - origin);
boneObject->SetMg(HPBToMatrix(r), FALSE);
// Align Bone axes with World axes (X/Y/-Z)
r = boneObject->GetRot();
r.z = 0.0;
boneObject->SetRot(r);
m = boneObject->GetMg();
Vector a0 = aPts[0] * m;
Vector a1 = aPts[1] * m;
Vector a2 = aPts[2] * m;
r = MatrixToHPB(m);
r.z += AlignBone(a0, a1, a2);
// Remove and delete aObj
aObj->Remove();
PolygonObject::Free(aObj);
// Position bone
boneObject->SetMg(MatrixMove(origin) * HPBToMatrix(r) * MatrixScale(Vector(1.0)), FALSE);
SetWeights();
boneObject->Message(MSG_UPDATE);
}
// Transform FIXED bone
void PoserBase::TransformBone(void)
{
Bool ik = FALSE;
UCHAR type, subType, i,j,k;
Real scaling = tpLoader->GetSettings()->GetObjScaling();
Vector vpos, vrot, vscale, drot, tpos, trot, tscale;
Matrix mg, m[3];
KeyFrame* key;
Channel* chan;
mg = boneObject->GetMg();
vpos = Vector(mg.off.x, mg.off.y, mg.off.z);
vrot = MatrixToHPB(mg);
vscale = Vector(Len(mg.v1), Len(mg.v2), Len(mg.v3));
//vrot = boneObject->GetRot();
if (ikChain) ik = ikChain->GetState() & ((ikTarget)?TRUE:FALSE);
if (ik)
{
mg = ikTarget->GetMg();
tpos = Vector(mg.off.x, mg.off.y, mg.off.z);
trot = MatrixToHPB(mg);
tscale = Vector(Len(mg.v1), Len(mg.v2), Len(mg.v3));
}
// Extract values from Channel keys
for (chan = channel; chan != NULL; chan = (Channel* )chan->GetNext())
{
type = chan->GetType();
subType = chan->GetSubType();
// rotation
if (type == CHAN_TYPE_ROTATE)
{
if (key = chan->GetKeyFrame0())
{
if (subType == raxis) drot.y = (Rad(key->GetValue()) * rsign);
else if (subType == gaxis) drot.x = (Rad(key->GetValue()) * gsign);
else if (subType == baxis) drot.z = (Rad(key->GetValue()) * bsign);
/*
if (subType == raxis) vrot.y += (Rad(key->GetValue()) * rsign);
else if (subType == gaxis) vrot.x += (Rad(key->GetValue()) * gsign);
else if (subType == baxis) vrot.z -= (Rad(key->GetValue()) * bsign);
*/
}
}
// scale
else if ((type == CHAN_TYPE_SCALE) || (type == CHAN_TYPE_PROPAGATINGSCALE))
{
if (key = chan->GetKeyFrame0())
{
if (subType == CHAN_SUB_NONE) vscale *= key->GetValue();
else if (subType == raxis) vscale.y *= key->GetValue();
else if (subType == gaxis) vscale.x *= key->GetValue();
else if (subType == baxis) vscale.z *= key->GetValue();
}
}
// translation
else if ((type == CHAN_TYPE_TRANSLATE) && ik)
{
if (key = chan->GetKeyFrame0())
{
if (subType == CHAN_SUB_X) tpos.x += (key->GetValue() * scaling);
else if (subType == CHAN_SUB_Y) tpos.y += (key->GetValue() * scaling);
else if (subType == CHAN_SUB_Z) tpos.z += (key->GetValue() * scaling);
}
}
}
// BoneObject: Apply Channels to Global Matrix
if (axis[0])
{
subType = (axis[0])->GetSubType();
if (subType == CHAN_SUB_Z) i = 0;
else if (subType == CHAN_SUB_Y) j = 0;
else k = 0;
subType = (axis[1])->GetSubType();
if (subType == CHAN_SUB_Z) i = 1;
else if (subType == CHAN_SUB_Y) j = 1;
else k = 1;
subType = (axis[2])->GetSubType();
if (subType == CHAN_SUB_Z) i = 2;
else if (subType == CHAN_SUB_Y) j = 2;
else k = 2;
}
else
{
i = 0; j = 1; k = 2;
}
m _= MatrixRotZ((baxis == CHAN_SUB_Z)?drot.z:((gaxis == CHAN_SUB_Z)?drot.x:drot.y));
m[j] = MatrixRotY((baxis == CHAN_SUB_Y)?drot.z:((gaxis == CHAN_SUB_Y)?drot.x:drot.y));
m[k] = MatrixRotX((baxis == CHAN_SUB_X)?drot.z:((gaxis == CHAN_SUB_X)?drot.x:drot.y));
boneObject->SetMg(MatrixMove(vpos) * m[2] * m[1] * m[0] * HPBToMatrix(vrot) * MatrixScale(vscale));
//boneObject->SetRot(vrot);
boneObject->Message(MSG_UPDATE);
if (ik)
{
ikTarget->SetMg(MatrixMove(tpos)*HPBToMatrix(trot)*MatrixScale(tscale));
ikTarget->Message(MSG_UPDATE);
}
}
// Determine correction Bank rotation by aPts
// - Returns Real correction angle
Real PoserBase::AlignBone(Vector a0, Vector a1, Vector a2)
{
Real comp;
CHAR d0, d1;
// Determine raxis and gaxis world axis and directions
if ((Abs(a0.x) > Abs(a0.y)) && (Abs(a0.x) > Abs(a0.z)))
{
if (a0.x > 0) d0 = 1;
else d0 = -1;
}
else if ((Abs(a0.y) > Abs(a0.x)) && (Abs(a0.y) > Abs(a0.z)))
{
if (a0.y > 0) d0 = 2;
else d0 = -2;
}
else if ((Abs(a0.z) > Abs(a0.x)) && (Abs(a0.z) > Abs(a0.y)))
{
if (a0.z > 0) d0 = 3;
else d0 = -3;
}
if ((Abs(a1.x) > Abs(a1.y)) && (Abs(a1.x) > Abs(a1.z)))
{
if (a1.x > 0) d1 = 1;
else d1 = -1;
}
else if ((Abs(a1.y) > Abs(a1.x)) && (Abs(a1.y) > Abs(a1.z)))
{
if (a1.y > 0) d1 = 2;
else d1 = -2;
}
else if ((Abs(a1.z) > Abs(a1.x)) && (Abs(a1.z) > Abs(a1.y)))
{
if (a1.z > 0) d1 = 3;
else d1 = -3;
}
if ((Abs(a2.x) > Abs(a2.y)) && (Abs(a2.x) > Abs(a2.z)))
{
if (a2.x >= 0) bsign = 1.0;
else bsign = -1.0;
}
else if ((Abs(a2.y) > Abs(a2.x)) && (Abs(a2.y) > Abs(a2.z)))
{
if (a2.y >= 0) bsign = 1.0;
else bsign = -1.0;
}
else if ((Abs(a2.z) > Abs(a2.x)) && (Abs(a2.z) > Abs(a2.y)))
{
if (a2.z >= 0) bsign = 1.0;
else bsign = -1.0;
}
if (d0 > 0) rsign = 1.0;
else rsign = -1.0;
if (d1 > 0) gsign = 1.0;
else gsign = -1.0;
/*
Red Green (RG:B) Red Green (RG:B)
aPt[0] aPt[1] (XY:Z) (JtJt:Twist) aPt[0] aPt[1] (XY:Z) (JtJt:Twist)
========================== ==========================
1,0,0 0,1,0 0 (XY:Z) 0,-1,0 1,0,0 -90 (XY:Z)
1,0,0 0,0,1 90 (ZX:Y) 0,-1,0 0,0,1 180 (YZ:X)
1,0,0 0,-1,0 90 (YX:Z) 0,-1,0 -1,0,0 180 (YX:Z)
1,0,0 0,0,-1 0 (XZ:Y) 0,-1,0 0,0,-1 -90 (ZY:X)
-1,0,0 0,1,0 -90 (YX:Z) 0,0,1 1,0,0 -90 (XZ:Y)
-1,0,0 0,0,1 180 (XZ:Y) 0,0,1 0,1,0 -90 (YZ:X)
-1,0,0 0,-1,0 180 (XY:Z) 0,0,1 -1,0,0 180 (ZX:Y)
-1,0,0 0,0,-1 -90 (ZX:Y) 0,0,1 0,-1,0 180 (ZY:X)
0,1,0 1,0,0 0 (YX:Z) 0,0,-1 1,0,0 0 (ZX:Y)
0,1,0 0,0,1 90 (ZY:X) 0,0,-1 0,1,0 0 (ZY:X)
0,1,0 -1,0,0 90 (XY:Z) 0,0,-1 -1,0,0 90 (XZ:Y)
0,1,0 0,0,-1 0 (YZ:X) 0,0,-1 0,-1,0 90 (YZ:X)
*/
// Handle compensation
// R = +X
if (d0 == 1)
{
// G = +Y
if (d1 == 2)
{
comp = 0.0;
raxis = CHAN_SUB_X; gaxis = CHAN_SUB_Y; baxis = CHAN_SUB_Z;
}
// G = +Z
else if (d1 == 3) {
comp = RAD_90;
raxis = CHAN_SUB_Z; gaxis = CHAN_SUB_X; baxis = CHAN_SUB_Y;
}
// G = -Y
else if (d1 == -2) {
comp = RAD_90;
raxis = CHAN_SUB_Y; gaxis = CHAN_SUB_X; baxis = CHAN_SUB_Z;
}
// G = -Z
else if (d1 == -3) {
comp = 0.0;
raxis = CHAN_SUB_X; gaxis = CHAN_SUB_Z; baxis = CHAN_SUB_Y;
}
}
// R = -X
else if (d0 == -1)
{
// G = +Y
if (d1 == 2) {
comp = -RAD_90;
raxis = CHAN_SUB_Y; gaxis = CHAN_SUB_X; baxis = CHAN_SUB_Z;
}
// G = +Z
else if (d1 == 3) {
comp = RAD_180;
raxis = CHAN_SUB_X; gaxis = CHAN_SUB_Z; baxis = CHAN_SUB_Y;
}
// G = -Y
else if (d1 == -2) {
comp = RAD_180;
raxis = CHAN_SUB_X; gaxis = CHAN_SUB_Y; baxis = CHAN_SUB_Z;
}
// G = -Z
else if (d1 == -3) {
comp = -RAD_90;
raxis = CHAN_SUB_Z; gaxis = CHAN_SUB_X; baxis = CHAN_SUB_Y;
}
}
// R = +Y
else if (d0 == 2)
{
// G = +X
if (d1 == 1) {
comp = 0.0;
raxis = CHAN_SUB_Y; gaxis = CHAN_SUB_X; baxis = CHAN_SUB_Z;
}
// G = +Z
else if (d1 == 3) {
comp = RAD_90;
raxis = CHAN_SUB_Z; gaxis = CHAN_SUB_Y; baxis = CHAN_SUB_X;
}
// G = -X
else if (d1 == -1) {
comp = RAD_90;
raxis = CHAN_SUB_X; gaxis = CHAN_SUB_Y; baxis = CHAN_SUB_Z;
}
// G = -Z
else if (d1 == -3) {
comp = 0.0;
raxis = CHAN_SUB_Y; gaxis = CHAN_SUB_Z; baxis = CHAN_SUB_X;
}
}
// R = -Y
else if (d0 == -2)
{
// G = +X
if (d1 == 1) {
comp = -RAD_90;
raxis = CHAN_SUB_X; gaxis = CHAN_SUB_Y; baxis = CHAN_SUB_Z;
}
// G = +Z
else if (d1 == 3) {
comp = RAD_180;
raxis = CHAN_SUB_Y; gaxis = CHAN_SUB_Z; baxis = CHAN_SUB_X;
}
// G = -X
else if (d1 == -1) {
comp = RAD_180;
raxis = CHAN_SUB_Y; gaxis = CHAN_SUB_X; baxis = CHAN_SUB_Z;
}
// G = -Z
else if (d1 == -3) {
comp = -RAD_90;
raxis = CHAN_SUB_Z; gaxis = CHAN_SUB_Y; baxis = CHAN_SUB_X;
}
}
// R = +Z
else if (d0 == 3)
{
// G = +X
if (d1 == 1) {
comp = -RAD_90;
raxis = CHAN_SUB_X; gaxis = CHAN_SUB_Z; baxis = CHAN_SUB_Y;
}
// G = +Y
else if (d1 == 2) {
comp = -RAD_90;
raxis = CHAN_SUB_Y; gaxis = CHAN_SUB_Z; baxis = CHAN_SUB_X;
}
// G = -X
else if (d1 == -1) {
comp = RAD_180;
raxis = CHAN_SUB_Z; gaxis = CHAN_SUB_X; baxis = CHAN_SUB_Y;
}
// G = -Y
else if (d1 == -2) {
comp = RAD_180;
raxis = CHAN_SUB_Z; gaxis = CHAN_SUB_Y; baxis = CHAN_SUB_X;
}
}
// R = -Z
else if (d0 == -3)
{
// G = +X
if (d1 == 1) {
comp = 0.0;
raxis = CHAN_SUB_Z; gaxis = CHAN_SUB_X; baxis = CHAN_SUB_Y;
}
// G = +Y
else if (d1 == 2) {
comp = 0.0;
raxis = CHAN_SUB_Z; gaxis = CHAN_SUB_Y; baxis = CHAN_SUB_X;
}
// G = -X
else if (d1 == -1) {
comp = RAD_90;
raxis = CHAN_SUB_X; gaxis = CHAN_SUB_Z; baxis = CHAN_SUB_Y;
}
// G = -Y
else if (d1 == -2) {
comp = RAD_90;
raxis = CHAN_SUB_Y; gaxis = CHAN_SUB_Z; baxis = CHAN_SUB_X;
}
}
return comp;
}
Thanks for any help in resolving this,
Robert