Настраиваю импорт\экспорт
.smd файлов в 3д редактор. Удалось импортировать reference файл, и получить верные координаты костей в глобальном мире. Фрагмент кода:
fscanf(pFile, "%i %f %f %f %f %f %f",
&iBoneIndex, &vecBonePos.x, &vecBonePos.z, &vecBonePos.y,
&vAngles.x, &vAngles.z, &vAngles.y);
vecBonePos.z = -vecBonePos.z;
vAngles.z = -vAngles.z;
vAngles = vec3(DEGREES(vAngles.x), DEGREES(vAngles.y), DEGREES(vAngles.z));
vec3 vBonePos = vec3(vecBonePos.x, vecBonePos.y, vecBonePos.z);
matrix mX, mY, mZ;
mX.setAngles(vec3(vAngles.x, 0, 0));
mY.setAngles(vec3(0, vAngles.y, 0));
mZ.setAngles(vec3(0, 0, vAngles.z));
matrix mRot; // local matrix
mRot = mY * mZ * mX; //YZX rotation order
mRot.setPos(vBonePos);
aLocalMatrices.add(mRot);
if (GetBoneAt(i)->m_iParent == -1)
aGlobalMatrices[i] = mRot;
else
aGlobalMatrices[i] = aGlobalMatrices[GetBoneAt(i)->m_iParent] * mRot;
//set position
GetBoneAt(i)->m_vPos = Vector(aGlobalMatrices[i].getPos().x, aGlobalMatrices[i].getPos().y, aGlobalMatrices[i].getPos().z);
В .smd дается локальная позиция кости относительно родительской кости, а так же углы Эйлера, чтобы создать локальную матрицу поворота.
у-ось и z-ось поменяны местами, поэтому такой порядок умножения матриц поворота.
Анимация у меня происходит следующим образом:
matrix m = getBoneMatrix(aBones[i], g_pAnimationEditor->m_flAnimPos ); // тут происходит интерполяция
vec3 vRootOffset = getRootOffset(g_pAnimationEditor->m_flAnimPos); // root bone offset
if (aBones[i]->m_iParent != -1)
{
vec3 vPos = g_pAnimationEditor->m_aRefPoses[i]; //bone pos in global space
vec3 vParentPos = vec3(aBones[aBones[i]->m_iParent]->m_vPos.x, aBones[aBones[i]->m_iParent]->m_vPos.y, aBones[aBones[i]->m_iParent]->m_vPos.z); //parent bone pos in global space
vec3 vLocalPos = g_pAnimationEditor->m_aRefPoses[i] - g_pAnimationEditor->m_aRefParentPoses[i]; // local bone pos in parent space
matrix mParent = m_aCurrentState[aBones[i]->m_iParent]; // parent rotation matrix
mParent.setPos(vec3()); //remove pos
m = mParent * m;
vPos = m * vPos;
vec3 vNewBonePos = vParentPos + mParent * vLocalPos; // new bone location
aBones[i]->m_vPos = Vector(vNewBonePos.x, vNewBonePos.y, vNewBonePos.z); //adding root offset here because it resends data to gpu
m.setPos(vNewBonePos - vPos); //offset
}
m.setPos(m.getPos() + vRootOffset); //add root offset
И при рендере конечная позиция кости расчитывается так:
m = m_aCurrentState[i];
glVertex3fv(m * m_aRefPoses[i]); // RefPos -> initial bone pos in global space
Проблема в том, что мне не удается получить нужный кватернион из углов Эйлера. Мне для моей анимации нужны всего лишь reference bone pos и кватернион для поворота в local space.
P.S.
Редактирование кадра производится следующим образом:
vec3 vFrontAxis = (vEnd - vStart).getNormalized();
matrix mBoneMatrix = m_aCurrentState[pSelectedBone->m_iParent];
mBoneMatrix.setPos(vec3());
mBoneMatrix.invert();
vFrontAxis = mBoneMatrix * vFrontAxis;
int iCurFrame = m_iCurrentFrame;
m_aFrames[iCurFrame].Get(pSelectedBone)->m_quat = m_aFrames[iCurFrame].Get(pSelectedBone)->m_quat * quat().fromAxisAngle(vFrontAxis, flDeltaX); // flDeltaX = mouse.x - lastmouse.x