我正在开发一款新的视频游戏,我在骨骼动画上被封锁了大约5周。我相信我已经缩小了问题的范围,但无法弄清楚我实际上做错了什么。
我有一个简单的12顶点矩形对象,里面有四个骨头。 This image显示对象在其绑定姿势中的样子,以及顶部骨骼围绕Y轴旋转约90度时对象应该是什么样的。要在我的应用程序中测试骨骼权重,这是我正在使用的简单示例。在我的应用程序中,我以编程方式将顶部骨骼旋转~90度并使着色器渲染它。
不幸的是,我的应用程序没有产生相同的结果。绑定姿势正确显示,但是当应用顶部骨骼变换时,变换被夸大,矩形的顶部只是沿着旋转顶部骨骼的方向伸展。
我已经验证了以下内容:
所以我把我的问题减少到这个单一的健全性检查。参考上面的第一个截图,我选择一个顶点来使用我的骨骼方法进行变换。一个小顶点:-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)。数学是正确的,值匹配,但答案是错误的。
所以,这就是我提出实际问题的地方:在通过骨骼变换的影响转换网格顶点时我做错了什么?我对骨骼动画的理解在哪里不正确?
答案 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度,如果我只是将它瞄准,则给出该值。你的测试是“正确的”。此时我开始认为骨骼层次结构存在问题,或者关键帧插值存在问题。