ボーンの行列は内部計算が複雑で、一般的な処理とも異なる部分があるかもしれません。SDKからアクセスすれば計算後の行列を取得できるので細かいことは気にせずに済みますが、外部で独自に計算することを想定していません。
このあたり実装したのも随分昔で、詳細はもはや覚えておりませんので、正直なところ正確な回答をするのも難しいですが、内部コードで行列計算を行っているgetBoneOrgMat()とその周辺コードを切り出してみたので、参考にしてみてください。
void Bone::setUpVector(const MQAngle& angle)
{
upVector = angle;
if(forwardAxis != AXIS_Y_PLUS)
upVectorMat = getForwardAxisMatrix();
else
upVectorMat.Identify();
if(angle != MQAngle(0,0,0))
upVectorMat *= angle.GetRotationMatrix();
}
MQMatrix Bone::getForwardAxisMatrix() const
{
MQMatrix m;
m.Identify();
Show more...
switch(forwardAxis){
case AXIS_X_PLUS: m._11 = 0; m._12 = 1; m._21 = -1; m._22 = 0; break;
case AXIS_X_MINUS: m._11 = 0; m._12 = -1; m._21 = 1; m._22 = 0; break;
case AXIS_Y_PLUS: default: break;
case AXIS_Y_MINUS: m._22 = -1; m._33 = -1; break;
case AXIS_Z_PLUS: m._22 = 0; m._23 = -1; m._32 = 1; m._33 = 0; break;
case AXIS_Z_MINUS: m._22 = 0; m._23 = 1; m._32 = -1; m._33 = 0; break;
}
return m;
}
MQMatrix Bone::getBoneOrgMat()
{
if(children.size() == 1){
Bone *child = m_boneset->getBone(children.front());
if(child != nullptr)
return upVectorMat * BoneSet::CalcJointMatrix(this->org_pos, child->org_pos);
}
if(parent != 0){
Bone *pnode = m_boneset->getBone(parent);
if(pnode != nullptr)
return upVectorMat * BoneSet::CalcJointMatrix(pnode->org_pos, this->org_pos);
}
return upVectorMat;
}
MQMatrix BoneSet::CalcJointMatrix(MQPoint root, MQPoint tip)
{
MQPoint vec = root - tip;
vec.normalize();
if(fabs(vec.y) > 1 - 1e-5f){
MQMatrix mtx;
mtx.Identify();
if(vec.y > 0){
mtx._22 *= -1;
mtx._33 *= -1;
}
return mtx;
}
MQPoint defvec(0,-1,0);
float x = GetInnerProduct(defvec, vec);
float rotationAngle = acosf(std::max(-1.0f, std::min(x, 1.0f)));
MQPoint rotationAxis = GetCrossProduct(defvec, vec);
rotationAxis.normalize();
return GetRotationMatrixWithAxis(rotationAxis, rotationAngle);
}