tl;dr:为模型设置动画时,每个关节都正确移动,但不相对于其父关节。
我正在使用 Lua 中自定义构建的 IQE 加载器和渲染器开发骨骼动画系统。在这一点上几乎所有东西都在工作,除了骨骼在动画时似乎脱节。每个关节都可以正确平移、旋转和缩放,但没有考虑其父节点的位置,从而产生了一些可怕的问题。
在参考 IQM 规范和演示时,我无法终生找出问题所在。我的 Lua 代码(据我所知)与参考 C++ 相同。
计算基础联合矩阵:
local base = self.active_animation.base
local inverse_base = self.active_animation.inverse_base
for i, joint in ipairs(self.data.joint) do
local pose = joint.pq
local pos = { pose[1], pose[2], pose[3] }
local rot = matrix.quaternion(pose[4], pose[5], pose[6], pose[7])
local scale = { pose[8], pose[9], pose[10] }
local m = matrix.matrix4x4()
m = m:translate(pos)
m = m:rotate(rot)
m = m:scale(scale)
local inv = m:invert()
if joint.parent > 0 then
base[i] = base[joint.parent] * m
inverse_base[i] = inv * inverse_base[joint.parent]
else
base[i] = m
inverse_base[i] = inv
end
end
计算动画帧矩阵
local buffer = {}
local base = self.active_animation.base
local inverse_base = self.active_animation.inverse_base
for k, pq in ipairs(self.active_animation.frame[self.active_animation.current_frame].pq) do
local joint = self.data.joint[k]
local pose = pq
local pos = { pose[1], pose[2], pose[3] }
local rot = matrix.quaternion(pose[4], pose[5], pose[6], pose[7])
local scale = { pose[8], pose[9], pose[10] }
local m = matrix.matrix4x4()
m = m:translate(pos)
m = m:rotate(rot)
m = m:scale(scale)
local f = matrix.matrix4x4()
if joint.parent > 0 then
f = base[joint.parent] * m * inverse_base[k]
else
f = m * inverse_base[k]
end
table.insert(buffer, f:to_vec4s())
end
完整的代码在这里供进一步检查。相关代码在 /libs/iqe.lua 中,靠近函数 IQE:buffer() 和 IQE:send_frame() 的底部。此代码在 LOVE 游戏框架的自定义版本上运行,并包含一个 Windows 二进制文件(和批处理文件)。
最后说明:我们的矩阵代码已针对其他实现和多项测试进行了验证。