从世界 space 骨骼矩阵计算绑定 pose/skinning 矩阵
Calculating bind pose/skinning matrix from world space bone matrices
目前我将所有骨骼存储在世界space中并直接从二进制文件加载它们。
我通过放置一个 "arrow object" 和矩阵 bone_mat 作为 "modelmatrix" 来检查这个骨架。按预期工作。
Variable explanations:
1. bone_mat = world_space bone matrix (loaded from file)
2. bind_pose_mat = relative transformation from parent bone to current bone
3. skinning_mat = final joint transformation matrix
下一步是计算绑定姿势矩阵。相对于其父级的骨矩阵。
我是这样做的:
/* bone mat * inverse(parent bone mat) */
mesh->anim_data.skeleton[i].bind_pose_mat =
urdMat4MulMat4( mesh->anim_data.skeleton[i].bone_mat, urdMat4Inverse(parent_bone->bone_mat) );
我通过像这样再次将它放入世界 space 来检查这个矩阵:
world_space_mat =
urdMat4MulMat4( mesh->anim_data.skeleton[i].bind_pose_mat, parent_bone->bone_mat);
这导致与 bone_mat.
相同的矩阵
根骨骼存储在世界 space 中,因为它们不相对于任何父级
root_bone.bind_pose_mat = bone_mat
所以现在我在本地 space,但我需要做的只是
/* interpolated vertex = base_vertex * bones[bone_index].bind_pose_mat */
mesh->interpolated[i].vertex = urdMat4MulVec3(skeleton[bone_index].bind_pose_mat , mesh->base[i].vertex);
这会导致网格变形。
编辑:经过一番思考,看起来我不在本地 space,而是在相对 space(bind_pose 当前是其父级的相对矩阵)。
但我在那里坚持理论。
好的,看起来我成功了。
数学方程式(简化):
v' = SUM { w * m * v }
其中
- w is the weight (all bones have 1.0 weight currently)
- m is the world space bone matrix (animation bone)
- v is the relative vertex position of the bind pose
inv_bone_mat = the inverted world space bone matrix
bone_mat = world space bone matrix
计算v:
vec3 v_relative = bind_bones[bone_index].inv_bone_mat * vertex_object_space
现在只需要:
vec3 skinned_vertex = frame[current_frame].anim_bones[bone_index].bone_mat * v_relative
ofc 这可以通过多个 bones/weight 影响来扩展
我希望这对未来的读者有所帮助。
目前我将所有骨骼存储在世界space中并直接从二进制文件加载它们。
我通过放置一个 "arrow object" 和矩阵 bone_mat 作为 "modelmatrix" 来检查这个骨架。按预期工作。
Variable explanations:
1. bone_mat = world_space bone matrix (loaded from file)
2. bind_pose_mat = relative transformation from parent bone to current bone
3. skinning_mat = final joint transformation matrix
下一步是计算绑定姿势矩阵。相对于其父级的骨矩阵。
我是这样做的:
/* bone mat * inverse(parent bone mat) */
mesh->anim_data.skeleton[i].bind_pose_mat =
urdMat4MulMat4( mesh->anim_data.skeleton[i].bone_mat, urdMat4Inverse(parent_bone->bone_mat) );
我通过像这样再次将它放入世界 space 来检查这个矩阵:
world_space_mat =
urdMat4MulMat4( mesh->anim_data.skeleton[i].bind_pose_mat, parent_bone->bone_mat);
这导致与 bone_mat.
相同的矩阵根骨骼存储在世界 space 中,因为它们不相对于任何父级
root_bone.bind_pose_mat = bone_mat
所以现在我在本地 space,但我需要做的只是
/* interpolated vertex = base_vertex * bones[bone_index].bind_pose_mat */
mesh->interpolated[i].vertex = urdMat4MulVec3(skeleton[bone_index].bind_pose_mat , mesh->base[i].vertex);
这会导致网格变形。
编辑:经过一番思考,看起来我不在本地 space,而是在相对 space(bind_pose 当前是其父级的相对矩阵)。
但我在那里坚持理论。
好的,看起来我成功了。
数学方程式(简化):
v' = SUM { w * m * v }
其中
- w is the weight (all bones have 1.0 weight currently)
- m is the world space bone matrix (animation bone)
- v is the relative vertex position of the bind pose
inv_bone_mat = the inverted world space bone matrix
bone_mat = world space bone matrix
计算v:
vec3 v_relative = bind_bones[bone_index].inv_bone_mat * vertex_object_space
现在只需要:
vec3 skinned_vertex = frame[current_frame].anim_bones[bone_index].bone_mat * v_relative
ofc 这可以通过多个 bones/weight 影响来扩展
我希望这对未来的读者有所帮助。