加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 从.smd模型导入3D骨架动画

发布时间:2020-12-15 04:57:54 所属栏目:Java 来源:网络整理
导读:我正在写一个.smd导入器,我被困在骨骼动画部分.问题是我不确切知道它是如何工作的.我正在使用这个 this编写导出器,但它没有显示如何使用存储在文件中的信息. 我想所有具有相同骨骼id的顶点都应该被分组,平移和旋转,因为你无法旋转每个顶点.但我不知道我是否
我正在写一个.smd导入器,我被困在骨骼动画部分.问题是我不确切知道它是如何工作的.我正在使用这个 this编写导出器,但它没有显示如何使用存储在文件中的信息.

我想所有具有相同骨骼id的顶点都应该被分组,平移和旋转,因为你无法旋转每个顶点.但我不知道我是否正确,即使我是,我仍然不知道如何通过脚本来做到这一点……

所以问题是:我如何使用存储在文件中的骨架动画信息?

解决方法

我并不特别熟悉SMD格式,但是这里……

注意:此答案假定您知道如何为对象/节点构造复合变换.这是结合其平移,旋转和缩放的矩阵(虽然看起来在SMD中没有使用比例).此外,使用矩阵乘法,矩阵求逆和矩阵*向量乘法.

骨头和动画

模型的骨节点形成树;除了根骨(节点部分)之外,每个骨骼都有一个父骨骼.每个节点都有自己的局部变换(位置和旋转).

局部节点变换:节点的局部变换是从其位置和旋转构造的4×4矩阵,它将点从其局部空间转换到其父节点的空间:如果表示节点空间中位置的向量,则将其与矩阵相乘得到父母的空间中的那个向量.有关如何执行此操作的详细信息,请参阅this link. Google a bit更多.

在SMD中,骨骼变换仅在动画中的关键帧(骨架部分)中定义. “参考”SMD文件具有单帧动画;模型参考位置中每个骨骼节点的位置和旋转.

动画SMD文件具有包含多个帧的动画序列,每个帧指定(某些)骨骼的不同变换.在播放动画时,您可以根据帧的时间和当前场景/游戏时间在帧之间进行插值,并为每个骨骼进行变换(位置旋转).

获得静止骨骼变换

在预处理中(当加载网格时),您需要计算所谓的“静止”骨骼变换.这些是每个骨骼在参考位置时的模型到骨骼空间变换.原因如下:

所有顶点位置都在模型空间中定义,但最终,顶点变换必须从骨骼空间开始,因为您希望顶点与单个骨骼一起移动.因此,必须首先将顶点位置转换为骨骼空间.这是静止骨转换的来源.

因此,我们正在寻找的静止变换将顶点从模型空间转换为骨骼空间.将所有骨骼放在参考位置.从根节点开始遍历树,并连接变换矩阵.因此,例如,对于上臂节点,您将获得变换:

transform = root * spine * shoulderR * upperArmR

然而,这是从上臂空间到模型空间的转换.因此,只需反转矩阵即可获得静止骨骼变换.为每个骨骼执行此操作并存储这些矩阵.

请注意,静止变换不会随时间变化;它们是根据模型的参考位置修复的.

顶点/骨骼关联

每个顶点与一个或多个骨节点相关联.对于每个这样的关联,顶点具有相应的权重.通常,所有权重总和为1.在SMD中,这些关联在三角形段中定义.根据您链接的页面,格式为:

triangles
my_material
bone_id    x y z    nx ny nz    u v    bone_links

这在(x,y,z)处定义了一个顶点,并且最终将它与骨骼bone_id相关联(假设权重为1). bone_links部分可以(排序)覆盖它并指定多个关联,如下所示:

bone_links = num_links bone_id[0] weight[0] bone_id[1] weight[1] ... etc.

如果权重不等于1,则剩余权重将转换为与原始bone_id的关联.

因此,与骨骼0,1和2相关联的示例顶点将是:

0    x y z   nx ny nz   u v    3   0 0.15  1 0.35  2 0.5

顶点变换

这是我们最终根据当前骨骼变换确定顶点位置的位置.如前所述;根据当前时间和动画,您可以确定(插入)当前骨骼变换.对于每个骨骼,计算骨骼到世界的变换.示例(我们之前看到过):

boneToWorld = root * spine * shoulderR * upperArmR

现在,对于与单个骨骼相关联的顶点,下面给出了它的动画/蒙皮位置:

vertexPosAnimated = boneToWorld * boneAtRest * vertexPosModel

这首先将顶点位置从模型空间(vertexPosModel)转换为与其关联的骨骼空间(此变换不会随时间变化).然后,使用骨骼的当前位置,顶点再次从骨骼转换为模型空间.这允许它随着变换的变化随着骨骼移动.

观察到,当骨骼当前处于静止位置时,boneAtRest是boneToWorld的反转,因此boneToWorld * boneAtRest是单位矩阵,因此顶点位置保持不变,这是正确的!

最后,由于顶点可以与多个骨骼相关联,而不是上面的,我们计算每个相关骨骼的上述加权和.例如,对于与3个骨骼关联的顶点:

vertexPosAnimated =
    boneToWorld[0] * boneAtRest[0] * vertexPosModel * weight[0] +
    boneToWorld[1] * boneAtRest[1] * vertexPosModel * weight[1] +
    boneToWorld[2] * boneAtRest[2] * vertexPosModel * weight[2];

最后的想法

这些是一些广泛的笔触,我甚至没有讨论着色器实现(如果那是你要做的),但我认为我已经涵盖了所有原则,而且它已经是一个很长的答案.

我过去发现有助于3D引擎开发的一件事是M3G文档(旧的Java Mobile 3D API). SkinnedMesh上的条目基本上描述了我在这里发布的内容.

此外,尝试理解使用静止骨骼变换将顶点从模型转换为骨骼空间的概念,并使用其当前变换再次返回.这是整个事情的关键.

祝好运!

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读