首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Assimp动画骨转换

Assimp动画骨转换
EN

Stack Overflow用户
提问于 2016-09-22 07:12:33
回答 1查看 2.4K关注 0票数 8

最近我在做骨动画导入,所以我用一些IK技术制作了一个3d的类似于我的模型来测试Assimp动画导入。输出格式是COLLADA(*.dae),我使用的工具是Blender。在编程方面,我的环境是opengl/glm/assimp。我认为这些信息是为了我的问题是enough.One的东西,动画的模型,我只是记录7未移动关键帧测试assimp动画。

首先,我认为除了局部变换部分外,我的转换是正确的,所以让函数只返回glm::mat4(1.0f),结果显示绑定姿态(不确定)模型。(见下图)

其次,将值glm::mat4(1.0f)返回到bone->localTransform = transform * scaling * glm::mat4(1.0f);,然后将模型变形。(见下图)

在搅拌机中测试图像和模型:

(bone->localTransform = glm::mat4(1.0f) * scaling * rotate;:这张图片在地下:( )

这里的代码:

代码语言:javascript
复制
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制作骨骼动画引用的。

总的来说,我收集了从assimp到MeshModel的所有信息,并将其保存到骨结构中,所以我认为这些信息还可以吗?

最后一件事,我的顶点着色代码:

代码语言:javascript
复制
#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);
}

如果我上面的问题,缺乏代码或描述含糊不清,请告诉我,谢谢!

编辑:(1)

此外,我的骨头信息如下(代码获取部分):

代码语言:javascript
复制
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,从它得到相同的值。我不确定我做了一个普通的关键帧动画,它提供的转换值是否为真(当然,它有7个关键帧)。

这样的关键帧内容(在头骨上调试):

7种不同的关键帧,相同的向量值。

编辑:(2)

如果您想测试我的dae文件,我把它放在小提琴中,来拿:)。另外,在统一我的文件工作正确,所以我认为可能不是我的本地转换发生的问题,似乎问题可能是一些其他的,如parentTransform或骨->转换……等等?我也添加了局部变换矩阵的所有骨头,但不知道为什么COLLADA包含这些价值为我的动画.

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-09-23 17:59:13

对于大量的测试,最终发现问题是UpdateBone()部分。

在我指出我的问题之前,我需要说矩阵乘法的级数让我感到困惑,但当我找到解时,它只会使我完全(可能只有90%)实现所有的矩阵。

问题来自于文章gpu剥皮的矩阵计算。我假设答案代码是完全正确的,不要再使用矩阵了。因此,误用矩阵极大地转移了我对局部变换矩阵的看法。回到我的问题部分中的结果图像,当我改变局部变换矩阵以返回glm::mat4(1.0f)时,就是绑定姿态。

所以问题是,为什么变化使绑定的姿态?我以为问题一定是骨空间的局部变换,但我错了。在我给出答案之前,请看下面的代码:

代码语言:javascript
复制
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]);
    }
}

我所做的改变如下:

代码语言:javascript
复制
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是绑定位姿矩阵,当我在骨节点上使用这些时,当前节点相对于父节点。让我给出一张照片,捕捉到骨头上的基质。

左边的部分是从transform中提取的assimp_node->mTransformation,.The右边的部分是my unmove动画的localTransform,它是由nodeAnim->mPositionKeysnodeAnim->mRotationKeysnodeAnim->mScalingKeys的键计算的。

回顾我所做的,我做了一个绑定的姿态转换两次,所以我的问题部分中的图像看起来只是分开的,而不是意大利面:)

最后,让我展示一下我在未动动画测试之前所做的工作以及正确的动画结果。

(对每个人来说,如果我的概念是错误的,请指出我!( Thx.)

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39632517

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档