在 OpenGL 中渲染使用 Assimp 加载的动画模型时折叠的网格
Collapsed mesh when rendering animated model loaded with Assimp in OpenGL
所以我正在加载和渲染动画模型,我可以毫无问题地在其静态位置渲染网格,并使用调试线绘制动画骨骼。
Here is a short video illustrating the issue.
如您在视频中所见,我已正确显示动画 "stick-figure"。然而,网格 over-top 似乎只是部分正确显示。
如标题所述,我正在使用 Assimp 和 OpenGL。
在我在场景中加载的东西的模型加载端,遍历保持parent child 旋转的节点,识别是骨骼的节点并将骨骼信息添加到节点。
└───Scene
├───Camera
├───Armature
│ └───Torso : [ ROOT_BONE ]
│ ├───Chest : [ BONE ]
│ │ ├───Neck : [ BONE ]
│ │ │ └───Head : [ BONE ]
│ │ ├───Upper_Arm_L : [ BONE ]
│ │ │ └───Lower_Arm_L : [ BONE ]
│ │ │ └───Hand_L : [ BONE ]
│ │ └───Upper_Arm_R : [ BONE ]
│ │ └───Lower_Arm_R : [ BONE ]
│ │ └───Hand_R : [ BONE ]
│ ├───Upper_Leg_L : [ BONE ]
│ │ └───Lower_Leg_L : [ BONE ]
│ │ └───Foot_L : [ BONE ]
│ └───Upper_Leg_R : [ BONE ]
│ └───Lower_Leg_R : [ BONE ]
│ └───Foot_R : [ BONE ]
└───Character: [ 1 MESH(ES) ]
这是我当前模型节点结构的一个分集。
每个节点都有一个变换矩阵,旁边有[ROOT_BONE]/[BONE]的还有一个偏移矩阵。
为了渲染动画骨骼,我读入动画关键帧,根据插值位置旋转和缩放为每个"channel"(骨骼)构建矩阵值。当我将动画矩阵相乘时(基于 parent 层次结构)我在世界 space 中得到 bone/join 位置。(我似乎不需要知道任何节点变换矩阵或骨骼偏移矩阵以使其正确渲染。(只需将动画矩阵与其 parent 动画矩阵相乘)
为了渲染网格,我尝试了一些方法,仅使用动画中的矩阵得到的结果类似于上面显示的视频,但是躯干放在调试骨架的地面 in-front,但是 arms/legs 仍然显示与视频相同。视频中看到的结果是通过将动画矩阵乘以相应的骨骼来实现的,然后将结果传递给顶点着色器。
uniform mat4 uModelViewProjection;
uniform mat4 uBones[100];
in vec4 aPosition;
in vec4 aWeights;
in ivec4 aBoneIds;
void main(void) {
mat4 skinMat =
uBones[aBoneIds[0]] * aWeights[0] +
uBones[aBoneIds[1]] * aWeights[1] +
uBones[aBoneIds[2]] * aWeights[2] +
uBones[aBoneIds[3]] * aWeights[3];
gl_Position = uModelViewProjection * skinMat * aPosition;
}
这里是顶点着色器的相关代码。我在这里也尝试了几种不同的方法,结果相同(或在某些情况下更糟)。
我在看到奇怪的 "collapsed" 顶点后立即想到的一些事情可能是骨骼矩阵没有正确传递,我确实记录了它们以验证它们确实被发送了,我也检查了着色器统一位置句柄以确保正确找到它们。
我假设我在某处遗漏了一个步骤,或者只是以错误的顺序进行了一些操作。我一直在为这个主题研究一手充满不同 "tutorials" 的牌,但它们都很难跟上。 (代码到处都是,没有最好的文档,我无法 运行 任何一个,因为所有示例都需要不同的 languages/pre 现有框架,或者它只是简单地损坏。)
附加信息:
- 我当前尝试加载的模型是 Collada (.dae) 文件。
- 我正在为 Assimp 和 OpenGL 使用 LWJGL 绑定。
我终于弄明白了。在 OpenGL 着色器中使用 ivec4
(或任何其他带有 i
前缀的数据类型)作为属性时,您必须使用 glVertexAttribIPointer
而不是 glVertexAttribPointer
(注意 I
)。如果您不指定此项,缓冲区数据将作为浮点数发送到 GPU。
所以我正在加载和渲染动画模型,我可以毫无问题地在其静态位置渲染网格,并使用调试线绘制动画骨骼。
Here is a short video illustrating the issue.
如您在视频中所见,我已正确显示动画 "stick-figure"。然而,网格 over-top 似乎只是部分正确显示。
如标题所述,我正在使用 Assimp 和 OpenGL。
在我在场景中加载的东西的模型加载端,遍历保持parent child 旋转的节点,识别是骨骼的节点并将骨骼信息添加到节点。
└───Scene
├───Camera
├───Armature
│ └───Torso : [ ROOT_BONE ]
│ ├───Chest : [ BONE ]
│ │ ├───Neck : [ BONE ]
│ │ │ └───Head : [ BONE ]
│ │ ├───Upper_Arm_L : [ BONE ]
│ │ │ └───Lower_Arm_L : [ BONE ]
│ │ │ └───Hand_L : [ BONE ]
│ │ └───Upper_Arm_R : [ BONE ]
│ │ └───Lower_Arm_R : [ BONE ]
│ │ └───Hand_R : [ BONE ]
│ ├───Upper_Leg_L : [ BONE ]
│ │ └───Lower_Leg_L : [ BONE ]
│ │ └───Foot_L : [ BONE ]
│ └───Upper_Leg_R : [ BONE ]
│ └───Lower_Leg_R : [ BONE ]
│ └───Foot_R : [ BONE ]
└───Character: [ 1 MESH(ES) ]
这是我当前模型节点结构的一个分集。 每个节点都有一个变换矩阵,旁边有[ROOT_BONE]/[BONE]的还有一个偏移矩阵。
为了渲染动画骨骼,我读入动画关键帧,根据插值位置旋转和缩放为每个"channel"(骨骼)构建矩阵值。当我将动画矩阵相乘时(基于 parent 层次结构)我在世界 space 中得到 bone/join 位置。(我似乎不需要知道任何节点变换矩阵或骨骼偏移矩阵以使其正确渲染。(只需将动画矩阵与其 parent 动画矩阵相乘)
为了渲染网格,我尝试了一些方法,仅使用动画中的矩阵得到的结果类似于上面显示的视频,但是躯干放在调试骨架的地面 in-front,但是 arms/legs 仍然显示与视频相同。视频中看到的结果是通过将动画矩阵乘以相应的骨骼来实现的,然后将结果传递给顶点着色器。
uniform mat4 uModelViewProjection;
uniform mat4 uBones[100];
in vec4 aPosition;
in vec4 aWeights;
in ivec4 aBoneIds;
void main(void) {
mat4 skinMat =
uBones[aBoneIds[0]] * aWeights[0] +
uBones[aBoneIds[1]] * aWeights[1] +
uBones[aBoneIds[2]] * aWeights[2] +
uBones[aBoneIds[3]] * aWeights[3];
gl_Position = uModelViewProjection * skinMat * aPosition;
}
这里是顶点着色器的相关代码。我在这里也尝试了几种不同的方法,结果相同(或在某些情况下更糟)。
我在看到奇怪的 "collapsed" 顶点后立即想到的一些事情可能是骨骼矩阵没有正确传递,我确实记录了它们以验证它们确实被发送了,我也检查了着色器统一位置句柄以确保正确找到它们。
我假设我在某处遗漏了一个步骤,或者只是以错误的顺序进行了一些操作。我一直在为这个主题研究一手充满不同 "tutorials" 的牌,但它们都很难跟上。 (代码到处都是,没有最好的文档,我无法 运行 任何一个,因为所有示例都需要不同的 languages/pre 现有框架,或者它只是简单地损坏。)
附加信息:
- 我当前尝试加载的模型是 Collada (.dae) 文件。
- 我正在为 Assimp 和 OpenGL 使用 LWJGL 绑定。
我终于弄明白了。在 OpenGL 着色器中使用 ivec4
(或任何其他带有 i
前缀的数据类型)作为属性时,您必须使用 glVertexAttribIPointer
而不是 glVertexAttribPointer
(注意 I
)。如果您不指定此项,缓冲区数据将作为浮点数发送到 GPU。