Understanding the skinning part of a GLTF2.0 file for OpenGL engine
我有一个简单的混合器模型,该模型由三个网格和三个控制每个网格的骨骼组成。动画只是骨骼绕y轴旋转一点,然后向后旋转。中心骨骼是两个外部骨骼的父对象。
然后,我使用GLTF2.0(文本版本)导出插件导出该场景,现在正尝试将其导入到我新制作的opengl引擎(C#xamarin android)中。
由于我想完全了解OpenGL中的GLTF2.0格式和骨骼动画,因此我尝试实现自己读取GLTF2.0。
我读:
- 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://kcoley.github.io/glTF/specification/2.0/figures/gltfOverview-2.0.0a.png
显示网格物体很容易,但是现在我仍然无法制作动画。
在我的gltf文件中,我看到了三种外观:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | "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引用,但是作为属性传递给着色器的weights / jointId-Arrays与这些骨骼ID不匹配:jointIds-Array包含即骨骼的0,1,2 id,但骨骼位于节点4,5,6中-如何为传递给着色器的每个jointId找到正确的骨骼?
我希望你能帮助我。亲切的问候!!
如果需要,我可以提供更多代码,但是我认为,如果我整体上理解该主题,那么我自己可以做到。
编辑
GLTF示例模型下载
编辑#2
好吧,我想我慢慢地掌握了它。
-
对于每个受电枢控制的网格,文件中都有一个蒙皮。我认为每个网格都需要有一个反向绑定矩阵,以便能够将网格转换为骨骼空间(如果需要,还可以转换为骨骼空间)。
-
我仍然不知道如何正确地将最终转换传递给着色器。
-
这一点仍然使我难以理解。
-
由于每个蒙皮都有三个(或最多4个)关节的列表,因此这些关节需要将最终的变换传递到顶点着色器。如果您有8个关节,但是当前要绘制的网格仅受到其中4个的影响,那么为什么要传递所有8个矩阵而不是只传递所需的4个矩阵。
这一切仍然令人怀疑。也许这可以帮助其他人。
我正在尝试一个接一个地解决您的问题
- Why are there three skins? Why is the inverseBindMatrices bound to a skin and not to a joint?
您已经发现,每个网格只有一个蒙皮。在您的特定情况下,您可以将所有三个网格合并为一个,这实际上并没有限制此一般原理。然而
I think there needs to be an inverse bind matrix for each mesh in order to be able to transform the mesh to bone space (and - if need be - back).
每个网格的每个关节都有一个反向绑定矩阵。由于某种原因,该属性的名称为
在这里更改问题的顺序,因为这样更有意义:
Every bone node in the file has its own rotation, translation, scale values but no matrix. Why is that? Isn't there something missing?
你还需要什么?每个仿射变换都可以分解为平移,旋转和缩放,因此数据是完整的。 glTF规范定义了所得矩阵应按
- When I have the right rotation, scaling, translation from a key frame (per bone), how do I calculate the matrices for each bone that I need to pass to my vertex shader?
对于每个骨骼节点
- The gltf file referse to a bone (joint) as a node id, but the weights/jointId-Arrays that get passed as attributes to the shader do not match these bone ids: jointIds-Array contains i.e. 0,1,2 for the bone ids, but the bones are in nodes 4,5,6 - how do I find the right bone for each jointId passed to the shader?
- Since every Skin has a list of three (or max. 4) Joints, these are the Joints of which the final transformations need to be passed to the vertex shader.
为什么将
If you have 8 Joints but the current to-be-drawn Mesh only gets affected by 4 of them, why should you pass all 8 matrices instead of only the 4 you need.
为什么要为只需要四个的网格定义8个骨骼的外观? glTF数据格式不会阻止您存储无关信息或以低效方式存储信息。
这里要注意的一点是,关节之间的层次仍然由