Assimp анимация преобразование кости

недавно я работаю над импортом анимации кости, поэтому я сделал 3d-модель minecraft с некоторой техникой IK для тестирования импорта анимации Assimp. Формат вывода-COLLADA(*.dae), и инструмент, который я использовал, - Blender. На стороне программирования моя среда-opengl/glm / assimp. Думаю, этой информации для моей проблемы достаточно.Одна вещь, анимация модели, я просто записываю 7 unmove ключевой кадр для тестирования анимации assimp.

во-первых, я думаю, моя трансформация, кроме локальной часть transform верна, поэтому пусть функция возвращает только glm::mat4(1.0f), и результат показывает модель позы привязки (не уверен). (см. ниже изображение)

во-вторых, Поверните значение glm::mat4(1.0f) to bone->localTransform = transform * scaling * glm::mat4(1.0f);, то модель деформируется. (см. ниже изображение)

тестовое изображение и модель в blender: test and origin (bone->localTransform = glm::mat4(1.0f) * scaling * rotate; : это изображение находится под землей :( )

вот код:

void MeshModel::UpdateAnimations(float time, std::vector<Bone*>& bones)
{
    for each (Bone* bone in bones)
    {
        glm::mat4 rotate = GetInterpolateRotation(time, bone->rotationKeys);
        glm::mat4 transform = GetInterpolateTransform(time, bone->transformKeys);
        glm::mat4 scaling = GetInterpolateScaling(time, bone->scalingKeys);
        //bone->localTransform = transform * scaling * glm::mat4(1.0f);
        //bone->localTransform = glm::mat4(1.0f) * scaling * rotate;
        //bone->localTransform = glm::translate(glm::mat4(1.0f), glm::vec3(0.5f));
        bone->localTransform = glm::mat4(1.0f);
    }
}

void MeshModel::UpdateBone(Bone * bone)
{
    glm::mat4 parentTransform = bone->getParentTransform();
    bone->nodeTransform = parentTransform
        * bone->transform  // assimp_node->mTransformation
        * bone->localTransform; // T S R matrix

    bone->finalTransform = globalInverse
        * bone->nodeTransform 
        * bone->inverseBindPoseMatrix; // ai_mesh->mBones[i]->mOffsetMatrix

    for (int i = 0; i < (int)bone->children.size(); i++) {
        UpdateBone(bone->children[i]);
    }
}

glm::mat4 Bone::getParentTransform()
{
    if (this->parent != nullptr)
        return parent->nodeTransform;
    else
        return glm::mat4(1.0f);
}

glm::mat4 MeshModel::GetInterpolateRotation(float time, std::vector<BoneKey>& keys)
{
    // we need at least two values to interpolate...
    if ((int)keys.size() == 0) {
        return glm::mat4(1.0f);
    }
    if ((int)keys.size() == 1) {
        return glm::mat4_cast(keys[0].rotation);
    }

    int rotationIndex = FindBestTimeIndex(time, keys);
    int nextRotationIndex = (rotationIndex + 1);
    assert(nextRotationIndex < (int)keys.size());
    float DeltaTime = (float)(keys[nextRotationIndex].time - keys[rotationIndex].time);
    float Factor = (time - (float)keys[rotationIndex].time) / DeltaTime;
    if (Factor < 0.0f)
        Factor = 0.0f;
    if (Factor > 1.0f)
        Factor = 1.0f;
    assert(Factor >= 0.0f && Factor <= 1.0f);
    const glm::quat& startRotationQ = keys[rotationIndex].rotation;
    const glm::quat& endRotationQ = keys[nextRotationIndex].rotation;
    glm::quat interpolateQ = glm::lerp(endRotationQ, startRotationQ, Factor);
    interpolateQ = glm::normalize(interpolateQ);
    return glm::mat4_cast(interpolateQ);
}

glm::mat4 MeshModel::GetInterpolateTransform(float time, std::vector<BoneKey>& keys)
{
    // we need at least two values to interpolate...
    if ((int)keys.size() == 0) {
        return glm::mat4(1.0f);
    }
    if ((int)keys.size() == 1) {
        return glm::translate(glm::mat4(1.0f), keys[0].vector);
    }

    int translateIndex = FindBestTimeIndex(time, keys);
    int nextTranslateIndex = (translateIndex + 1);
    assert(nextTranslateIndex < (int)keys.size());
    float DeltaTime = (float)(keys[nextTranslateIndex].time - keys[translateIndex].time);
    float Factor = (time - (float)keys[translateIndex].time) / DeltaTime;
    if (Factor < 0.0f)
        Factor = 0.0f;
    if (Factor > 1.0f)
        Factor = 1.0f;
    assert(Factor >= 0.0f && Factor <= 1.0f);
    const glm::vec3& startTranslate = keys[translateIndex].vector;
    const glm::vec3& endTrabslate = keys[nextTranslateIndex].vector;
    glm::vec3 delta = endTrabslate - startTranslate;
    glm::vec3 resultVec = startTranslate + delta * Factor;
    return glm::translate(glm::mat4(1.0f), resultVec);
}

идея код ссылается матричные вычисления для gpu скиннинг и Скелетная Анимация С Assimp.

в целом, я fectch всю информацию от assimp до MeshModel и сохранить его в костной структуре, так что я думаю, что информация в порядке?

последнее, мой код шейдера вершин:

#version 330 core 
#define MAX_BONES_PER_VERTEX 4

in vec3 position;
in vec2 texCoord;
in vec3 normal;
in ivec4 boneID;
in vec4 boneWeight;

const int MAX_BONES = 100;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 boneTransform[MAX_BONES];

out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoords;
out float Visibility;

const float density = 0.007f;
const float gradient = 1.5f;

void main()
{
    mat4 boneTransformation = boneTransform[boneID[0]] * boneWeight[0];
    boneTransformation += boneTransform[boneID[1]] * boneWeight[1];
    boneTransformation += boneTransform[boneID[2]] * boneWeight[2];
    boneTransformation += boneTransform[boneID[3]] * boneWeight[3];


    vec3 usingPosition = (boneTransformation * vec4(position, 1.0)).xyz;
    vec3 usingNormal = (boneTransformation * vec4(normal, 1.0)).xyz;

    vec4 viewPos = view * model * vec4(usingPosition, 1.0);
    gl_Position =  projection * viewPos;
    FragPos = vec3(model * vec4(usingPosition, 1.0f));
    Normal = mat3(transpose(inverse(model))) * usingNormal;
    TexCoords = texCoord;
    float distance = length(viewPos.xyz);
    Visibility = exp(-pow(distance * density, gradient));
    Visibility = clamp(Visibility, 0.0f, 1.0f);
}

если мой вопрос выше, отсутствие кода или смутно опишите, пожалуйста, дайте мне знать, Спасибо!

Edit: (1)

кроме того, моя информация кости, как это (часть извлечения кода):

for (int i = 0; i < (int)nodeAnim->mNumPositionKeys; i++)
{
    BoneKey key;
    key.time = nodeAnim->mPositionKeys[i].mTime;
    aiVector3D vec = nodeAnim->mPositionKeys[i].mValue;
    key.vector = glm::vec3(vec.x, vec.y, vec.z);
    currentBone->transformKeys.push_back(key);
}

имел некоторый вектор преобразования, поэтому мой код выше glm::mat4 transform = GetInterpolateTransform(time, bone->transformKeys);, Absloutely, получить то же значение от него. Я не уверен, что сделал анимацию ключевого кадра nomove, которая предоставляет значения преобразования true или нет (конечно, у него есть 7 ключевых кадров).

содержимое ключевого кадра, подобное этому(debug on head bone): keyframe from head 7 другой ключевой кадр, то же векторное значение.

Edit: (2)

если вы хотите проверить мой файл dae, я помещаю его в jsfiddle, иди и бери :). Другое дело, в Unity мой файл работает правильно, поэтому я думаю, что, возможно, не мое локальное преобразование возникает проблема, похоже, проблема может быть какой-то другой, как parentTransform или Bone - >transform...и т. д.? Я также добавляю локальную матрицу преобразования со всей костью, но не могу понять, почему COLLADA содержит эти значения для моей анимации unmove...

1 ответов


для количества тестирования и, наконец, обнаружил, что проблема заключается в UpdateBone() часть.

прежде чем я укажу на свою проблему, мне нужно сказать, что серия матричного умножения позволяет мне путать, но когда я нашел решение, это просто заставило меня полностью (может быть, только 90%) реализовать все матрицу.

проблема исходит из статьиматричные вычисления для GPU skinning. Я предположил, что код ответа абсолютно правильный и больше не думаю о следует использовать матрицу. Таким образом, неправильное использование матрицы ужасно переносит мой взгляд на локальную матрицу преобразования. Назад к изображению результата в моем разделе вопроса-поза привязки, когда я изменяю локальную матрицу преобразования на return glm::mat4(1.0f).

Итак, вопрос в том, почему измененные делают позу привязки? Я предположил, что проблема должна быть локальной трансформацией в костном пространстве, но я ошибаюсь. Прежде чем я дам ответ, посмотрите на код ниже:

void MeshModel::UpdateBone(Bone * bone)
{
    glm::mat4 parentTransform = bone->getParentTransform();
    bone->nodeTransform = parentTransform
        * bone->transform  // assimp_node->mTransformation
        * bone->localTransform; // T S R matrix

    bone->finalTransform = globalInverse
        * bone->nodeTransform 
        * bone->inverseBindPoseMatrix; // ai_mesh->mBones[i]->mOffsetMatrix

    for (int i = 0; i < (int)bone->children.size(); i++) {
        UpdateBone(bone->children[i]);
    }
}

и я делаю изменение как ниже:

void MeshModel::UpdateBone(Bone * bone)
{
    glm::mat4 parentTransform = bone->getParentTransform();
    if (boneName == "Scene" || boneName == "Armature")
    {
        bone->nodeTransform = parentTransform
            * bone->transform // when isn't bone node, using assimp_node->mTransformation
            * bone->localTransform;  //this is your T * R matrix
    }
    else
    {
        bone->nodeTransform = parentTransform // This retrieve the transformation one level above in the tree
            * bone->localTransform;  //this is your T * R matrix
    }

    bone->finalTransform = globalInverse // scene->mRootNode->mTransformation 
        * bone->nodeTransform  //defined above
        * bone->inverseBindPoseMatrix;  // ai_mesh->mBones[i]->mOffsetMatrix

    for (int i = 0; i < (int)bone->children.size(); i++) {
        UpdateBone(bone->children[i]);
    }
}   

я не знаю assimp_node->mTransformation дайте мне раньше, только описание "преобразование относительно родителя узла" в документации assimp. Для некоторого тестирования я обнаружил, что mTransformation является матрицей позы привязки, которая является текущим узлом относительно родителя, если я использую их на костном узле. Позвольте мне дать картину, которая запечатлела матрицу на кости головы.

Prove

левая часть -transform что за уши от assimp_node->mTransformation.Правая часть-моя unmove анимации localTransform который рассчитывается по ключам от nodeAnim->mPositionKeys, nodeAnim->mRotationKeys и nodeAnim->mScalingKeys.

оглядываясь назад, что я сделал, я сделал привязку поза Transformation два раза, поэтому изображение в моем разделе вопросов выглядит просто отдельно, но не спагетти:)

на последнем, позвольте мне показать, что я сделал перед unmove тестирования анимации и правильной анимации результат.

Result

(для всех, если моя концепция неверна , пожалуйста, покажите мне! Тнх.)