骨骼动画中的父子关系问题
tl;dr: 当模型进行动画时,每个关节的移动都正确,但是不相对于其父关节。
我正在使用自定义的 IQE 加载程序和 Lua 渲染器开发一个骨骼动画系统。现在几乎一切都运行正常,但是在动画时,骨架似乎是分离的。每个关节都可以正确地移动、旋转和缩放,但是没有考虑其父关节的位置,从而导致一些可怕的问题。
就 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 二进制文件(和批处理文件)。
最后说明:我们的矩阵代码已经通过其他实现和多个测试进行了验证。
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
父骨骼的变换应影响其子骨骼的变换。实现这一点的方法是,在其父的框架中指定特定骨骼的变换。因此,通常骨骼的变换指定在其本地坐标系中,该坐标系取决于其父级。如果任何一个父级被转换,这个变换会影响所有的子级,即使它们的本地变换没有改变。
在您的情况下,您曾经缓存每个节点的绝对(精确到根节点)变换。然后您使用缓存更新每个节点的本地变换,并且不更新您的缓存。那么,如果在更新孩子时使用缓存而不是实际的父变换,节点的本地变换如何影响它的子级?
还有一个问题。为什么您要这样做?
f = base[joint.parent] * m * inverse_base[k]我的意思是,通常只是:
f = base[joint.parent] * m我猜测,在动画中记录的变换是绝对的(精确到根节点)。这很奇怪。通常每个变换都是本地的。检查此问题,因为这会增加您的许多问题。
此外,在您的情况下,我没有看到任何需要缓存的东西(除了通常不需要的_inverse_base_)。
将您的_IQE:send_frame()_函数更改如下:
local buffer = {} local transforms = {} 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 transforms[k] = transforms[joint.parent] * m f = transforms[k] * inverse_base[k] else f = m * inverse_base[k] transforms[k] = m end table.insert(buffer, f:to_vec4s()) end这适用于我。试着摆脱_inverse_base_,您就可以从_IQE:buffer()_函数中删除所有动画相关的代码了。
P.S.通常,所有节点都通过遍历树来更新。但是,您通过列表更新节点。您应该意识到,您必须以某种方式保证对于任何节点,它的子级会在它之后。