Добрый день.Я хочу реализовать скелетную анимацию.Я создал простой пример в Blender и экспортировал его через collada.
anim будет
Поскольку это все для меня ново, поэтому я использовал collada1.4.1 спецификация и воссоздание сетки по ключевым кадрам.
ключевой кадр_0
ключевой кадр_1
ключевой кадр_2
Затем я попытался интерполировать между матрицами преобразования, чтобы получить полную анимацию.
Vector32BITF* vertices = (Vector32BITF*)calloc(CubeDAE::verticesCount, sizeof(Vector32BITF));
SceUShort16* indices = (SceUShort16*)calloc(CubeDAE::indicesCount, sizeof(SceUShort16));
for (unsigned int i = 0; i < CubeDAE::indicesCount; i++) { indices[i] = CubeDAE::indices[i][0]; }
float timer = 2.1f;
ScePspFMatrix4 bones_transform[3];
int keyframeA_i = 0;
int keyframeB_i = 0;
float lerpFact = 0.0f;
while(!done){
fps->PreUpdate();
keyframeA_i = ((int)timer) % CubeDAE::keyframesCount;
keyframeB_i = (((int)timer) + 1) % CubeDAE::keyframesCount;
lerpFact = pspFpuFrac(timer);
// keyframeA_i = 0;
// keyframeB_i = 1;
// lerpFact = 0.8;
for (unsigned int bone_i = 0; bone_i < CubeDAE::bonesCount; bone_i++) {
ScePspFMatrix4* local_matrixA = &CubeDAE::bones[bone_i][keyframeA_i];
ScePspFMatrix4* local_matrixB = &CubeDAE::bones[bone_i][keyframeB_i];
ScePspFVector3 positionA;
ScePspFVector3 positionB;
Mathf::Matrix::GetPosition(&positionA, local_matrixA);
Mathf::Matrix::GetPosition(&positionB, local_matrixB);
ScePspFMatrix3 rotationA;
ScePspFMatrix3 rotationB;
Mathf::Matrix::GetRotation(&rotationA, local_matrixA);
Mathf::Matrix::GetRotation(&rotationB, local_matrixB);
ScePspFVector4 q_rotationA;
ScePspFVector4 q_rotationB;
Mathf::Matrix::ConvertToQuaternion(&q_rotationA, &rotationA);
Mathf::Matrix::ConvertToQuaternion(&q_rotationB, &rotationB);
ScePspFVector3 translation;
ScePspFVector4 quaternion;
Mathf::Vector::Lerp(&translation, &positionA, &positionB, lerpFact);
Mathf::Quaternion::Slerp(&quaternion, &q_rotationA, &q_rotationB, lerpFact);
ScePspFMatrix4 offsetMatrix;
Mathf::Matrix::fromRotationTranslation(&offsetMatrix, &quaternion, &translation);
if (bone_i == 0) {
std::memcpy(&bones_transform[bone_i], &offsetMatrix, sizeof(ScePspFMatrix4));
} else if (bone_i == 1) {
Mathf::Matrix::Multiply(&bones_transform[bone_i], &offsetMatrix, &bones_transform[bone_i - 1]);
} else if (bone_i == 2) {
Mathf::Matrix::Multiply(&bones_transform[bone_i], &offsetMatrix, &bones_transform[bone_i - 2]);
}
}
unsigned int v_i = 0;
for (unsigned int vertices_i = 0; vertices_i < CubeDAE::verticesCount; vertices_i++) {
vertices[vertices_i].color = (0xff<<24)|((int)(pspFpuAbs(pspFpuCos(vertices_i)) * 255.0f) << 16)|((int)(pspFpuAbs(pspFpuSin(vertices_i)) * 255.0f) << 8)|((int)(pspFpuAbs(vertices_i) * 255.0f));
vertices[vertices_i].x = 0;
vertices[vertices_i].y = 0;
vertices[vertices_i].z = 0;
for (unsigned int vcount_i = 0; vcount_i < CubeDAE::vcount[vertices_i]; vcount_i++, v_i += 2) {
/*
SUM += ((v * BSM) * IBMi * JMi) *JM
• n: number of joints that influence vertex v
• BSM: bind shape matrix
• IBMi: inverse bind matrix of joint i
• JMi: joint matrix of joint i
• JW: joint weight/influence of joint i on vertex v
*/
// (v * BSM)
//ScePspFVector3 out = {0,0,0};
//Mathf::Vector::Transform(&out, &CubeDAE::shapeMatrix, &CubeDAE::vertices[vertices_i]);
// IBMi * JMi
ScePspFMatrix4 skinning_matrix = {{1,0,0,0}, {0,1,0,0}, {0,0,1,0}, {0,0,0,1}};
Mathf::Matrix::Multiply(&skinning_matrix, &CubeDAE::poses[CubeDAE::v[v_i]], &bones_transform[CubeDAE::v[v_i]]);
// ((v * BSM) * IBMi * JMi)
ScePspFVector3 skin = {0,0,0};
Mathf::Vector::Transform(&skin, &skinning_matrix, &CubeDAE::vertices[vertices_i]);
// ((v * BSM) * IBMi * JMi) *JM
Mathf::Vector::Scale(&skin, CubeDAE::weights[CubeDAE::v[v_i + 1]]);
vertices[vertices_i].x += skin.x;
vertices[vertices_i].y += skin.y;
vertices[vertices_i].z += skin.z;
}
}
// TODO: render here
}
Но я где-то допустил ошибку, поэтому получил неправильную анимацию.
anim got
Где я был не прав?
PS: приложение написано под платформу PSP, но смысл ничем не отличается от того, что делается везде.Полный простой пример вы можете найти здесь .