我有一个简单的混合器模型,它由三个网格组成,三个网格各控制一个网格。动画只是骨骼围绕 y 轴稍微旋转立方体并返回。中心骨骼是两个外部骨骼的父骨骼。
然后,我使用 GLTF2.0(文本版本)导出插件导出此场景,现在尝试将其导入到我新制作的 opengl 引擎(c# xamarin android)中。
由于我想完全理解GLTF2.0格式和OpenGL中的骨骼动画,所以我尝试自己实现GLTF2.0读取。
I read:
- https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_020_Skins.md https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_020_Skins.md
- https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/README.md https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/README.md
- https://kcoley.github.io/glTF/specification/2.0/figures/gltfOverview-2.0.0a.png https://kcoley.github.io/glTF/specification/2.0/figures/gltfOverview-2.0.0a.png
显示网格很容易,但现在我被困在动画工作中。
在我的 gltf 文件中,我看到三种皮肤:
"skins" : [
{
"inverseBindMatrices" : 21,
"joints" : [
4,
5,
6
],
"skeleton" : 0
},
{
"inverseBindMatrices" : 22,
"joints" : [
4,
5,
6
],
"skeleton" : 0
},
{
"inverseBindMatrices" : 23,
"joints" : [
4,
5,
6
],
"skeleton" : 0
}
]
这让我很困惑,因为所有网格体都有一个骨骼结构,而不是每个网格体有三个骨骼。
我想我会收集类实例(例如 Bone.cs)中的所有骨骼,每个骨骼都有一个子骨骼列表及其父骨骼字段。然后我会在实例(Animation.cs 类)中收集动画,每个动画实例都会有一个关键帧列表,其中包含给定时间戳的旋转、缩放和平移。
当动画时间戳设置为 2.5 秒时,我会查找该时间戳最近的两个关键帧,并为这些关键帧插入旋转、缩放和平移。
实际问题
- 为什么会有三款皮肤?为什么 inverseBindMatrices 绑定到皮肤而不是关节?
- 当我从关键帧(每个骨骼)进行正确的旋转、缩放、平移时,如何计算需要传递给顶点着色器的每个骨骼的矩阵?
- 文件中的每个骨骼节点都有自己的旋转、平移、缩放值,但没有矩阵。这是为什么?是不是少了点什么?
- gltf 文件将骨骼(关节)引用为节点 id,但作为属性传递给着色器的权重/jointId 数组与这些骨骼 id 不匹配:jointIds 数组包含骨骼,即 0,1,2 ids,但骨骼位于节点 4、5、6 中 - 如何为传递给着色器的每个 jointId 找到正确的骨骼?
我希望你可以帮助我。亲切的问候!!
如果需要,我可以提供更多代码,但我认为如果我从整体上理解了该主题,我就可以自己完成。
Edit
GLTF 示例模型下载 https://www.dropbox.com/s/u8j8cf8u0qobk7u/cube_animation_test.gltf?dl=0
Edit #2
好吧,我想我正在慢慢掌握它的窍门。
对于由骨架控制的每个网格,文件中都有一个皮肤。我认为每个网格体都需要有一个逆绑定矩阵,以便能够将网格体转换为骨骼空间(以及 - 如果需要的话 - 返回)。
我仍然不知道如何在将最终变换传递给着色器之前正确计算它们。
这一点我仍然不明白。
由于每个外观都有一个包含三个(或最多 4 个)关节的列表,因此这些关节的最终变换需要传递给顶点着色器。如果您有 8 个关节,但当前要绘制的网格仅受其中 4 个关节的影响,为什么要传递所有 8 个矩阵,而不是只传递您需要的 4 个矩阵。
这一切仍然笼罩着疑问。也许这对其他人有帮助。