如何转换顶点以进行骨架动画?

时间:2017-02-06 01:00:07

标签: c++ opengl

我正在开发一款新的视频游戏,我在骨骼动画上被封锁了大约5周。我相信我已经缩小了问题的范围,但无法弄清楚我实际上做错了什么。

我有一个简单的12顶点矩形对象,里面有四个骨头。 This image显示对象在其绑定姿势中的样子,以及顶部骨骼围绕Y轴旋转约90度时对象应该是什么样的。要在我的应用程序中测试骨骼权重,这是我正在使用的简单示例。在我的应用程序中,我以编程方式将顶部骨骼旋转~90度并使着色器渲染它。

不幸的是,我的应用程序没有产生相同的结果。绑定姿势正确显示,但是当应用顶部骨骼变换时,变换被夸大,矩形的顶部只是沿着旋转顶部骨骼的方向伸展。

我已经验证了以下内容:

  • 将骨骼作为相对变换发送到着色器制服。这意味着当我将顶部骨骼旋转90°时,骨骼1-3都是同一性,而骨骼4是仅沿Y轴旋转~90度的矩阵。
  • 对于任何给定的顶点,骨骼都被正确加权(或者至少,在我的应用程序中,它们的加权与Blender报告的相同)。

所以我把我的问题减少到这个单一的健全性检查。参考上面的第一个截图,我选择一个顶点来使用我的骨骼方法进行变换。一个小顶点:-0.5,-0.5,4.0。假设我正确应用了所有内容,骨骼应该将此顶点转换为-0.95638,-0.5,2.63086。为了使调试更容易,我采用了顶点着色器......

#version 330 core
layout (location = 0) in vec3 position; // The position variable has attribute position 0
layout (location = 1) in vec3 normal; // This is currently unused
layout (location = 2) in vec2 texture;
layout (location = 3) in ivec4 boneIDs;
layout (location = 4) in vec4 boneWeights;

out vec2 fragTexture;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

uniform mat4 bones[ 16 ];

void main()
{
  mat4 boneTransform =
    ( bones[ boneIDs[ 0 ] ] * boneWeights[ 0 ] ) +
    ( bones[ boneIDs[ 1 ] ] * boneWeights[ 1 ] ) +
    ( bones[ boneIDs[ 2 ] ] * boneWeights[ 2 ] ) +
    ( bones[ boneIDs[ 3 ] ] * boneWeights[ 3 ] );

  mat4 mvp = projection * view * model;
  gl_Position = mvp * boneTransform * vec4( position, 1.0f );

  fragTexture = texture;
}

...并将其放入下面这个简单的单元测试样式函数中,只是为了转换我的测试顶点。

glm::mat4 id( 1.0f ); // ID 0
glm::mat4 bone( 1.0f ); // ID 1
glm::mat4 bone002( 1.0f ); // ID 2
glm::mat4 bone003( 1.0f ); // ID 3

// Keyframe is set to rotate bone003 -89.113 degrees along Y
bone003 *= glm::toMat4( glm::angleAxis( (float)glm::radians( -89.113 ), glm::vec3( 0.0f, 1.0f, 0.0f ) ) );

glm::mat4 xform =
    ( bone002 * 0.087f ) +
    ( bone003 * 0.911f ) +
    ( id * 0 ) +
    ( id * 0 );

glm::vec4 point = xform * glm::vec4( glm::vec3( -0.5f, -0.5f, 4.0f ), 1.0f );

此代码模拟我的顶点着色器的状态,其中上面的四个mat4是骨骼[0]到骨骼[3]。 bone003是在转换Bone.003并删除其反向绑定后发送到我的着色器的内容。尽管完全符合我目前对骨骼动画的理解,并且匹配Blender的所有相关权重/值,但顶点(-0.5,-0.5,4.0)被转换为无意义值( - 3.694115,-0.499000,-0.051035)。数学是正确的,值匹配,但答案是错误的。

所以,这就是我提出实际问题的地方:在通过骨骼变换的影响转换网格顶点时我做错了什么?我对骨骼动画的理解在哪里不正确?

1 个答案:

答案 0 :(得分:2)

这对我来说似乎不对:

  mat4 boneTransform =
    ( bones[ boneIDs[ 0 ] ] * boneWeights[ 0 ] ) +
    ( bones[ boneIDs[ 1 ] ] * boneWeights[ 1 ] ) +
    ( bones[ boneIDs[ 2 ] ] * boneWeights[ 2 ] ) +
    ( bones[ boneIDs[ 3 ] ] * boneWeights[ 3 ] );

你应该将顶点(在骨骼空间中)与每个骨骼矩阵相乘,然后将得到的矢量加在一起处理权重,如下所示:

vec4 temp = vec4(0.0f, 0.0f, 0.0f, 0.0f);
vec4 v = vec4(position, 1.0f);
temp += (bones[boneIDs[0]] * v) * boneWeights[0];
temp += (bones[boneIDs[1]] * v) * boneWeights[1];
temp += (bones[boneIDs[2]] * v) * boneWeights[2];
temp += (bones[boneIDs[3]] * v) * boneWeights[3];

// temp is now the vector in local space that you
// transform with MVP to clip space, or whatever

让我知道这是否有效!

编辑:我想不是。好的:

  

顶点(-0.5,-0.5,4.0)转换为无意义值(-3.694115,-0.499000,-0.051035)

真的是胡说八道吗?围绕Y轴顺时针旋转约90度,如果我只是将它瞄准,则给出该值。你的测试是“正确的”。此时我开始认为骨骼层次结构存在问题,或者关键帧插值存在问题。