使用ASSIMP和GLSL进行骨骼动画:骨骼统一数组大小

3
我正在开发一个ASSIMP骨骼动画的加载器和渲染器,现在所有数据都已经正确加载并在当前时间帧内进行了插值。然而,仍有一个部分没有正常工作,那就是顶点着色器阶段。
通过一个VBO,我传递了包含每个顶点的骨骼ID和权重的两个vec4(每个顶点最多有4个骨头/权重),并且顶点着色器有一个包含100个骨骼变换的矩阵数组(每帧预先计算),可以通过骨骼ID进行索引。
然而,似乎骨骼Uniform不包含正确的变换。出于调试目的,我用权重值和骨骼ID值为模型着色,它们包含颜色(因此有效值)。但是,当我通过骨骼变换来转换我的顶点并将结果着色到模型中时,整个模型都呈黑色,这意味着变换矩阵全部为0.0,所以它们没有得到正确的初始化。
我认为问题在于将矩阵传递给Uniform数组,或者可能是允许的Uniform的最大大小(我还尝试将Uniform矩阵的数量设置为32(当前模型的骨骼数),但没有效果)?
在将信息传递到着色器之前,变换矩阵确实是有效的矩阵(不是单位/空矩阵),因此错误可能出现在GLSL着色器或Uniform传递中。
以下代码来自顶点着色器:
#version 330
layout (location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec3 tangent;
layout(location = 3) in vec3 color;
layout(location = 4) in vec2 texCoord;
layout(location = 5) in ivec4 boneIDs;
layout(location = 6) in vec4 weights;

uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform mat4 bones[100];

out vec2 TexCoord;
out vec4 colorz;

void main()
{
    vec4 newPos = vec4(position, 1.0);
    colorz = vec4(0.0, 1.0, 0.0, 1.0);
    if (weights != vec4(0.0, 0.0, 0.0, 0.0))
    {
        mat4 boneTransform = bones[boneIDs[0]] * weights[0];
        boneTransform += bones[boneIDs[1]] * weights[1];
        boneTransform += bones[boneIDs[2]] * weights[2];
        boneTransform += bones[boneIDs[3]] * weights[3];

        // newPos = boneTransform * vec4(position, 1.0);
        vec4 test = vec4(1.0);
        colorz = boneTransform * test;
        // newPos = boneTransform * newPos;
    }

    TexCoord = texCoord;
    gl_Position = projection * view * model * newPos;
}

以下代码片段将矩阵数据传递给GLSL着色器:
// Sets bone transformation matrices
void Shader::SetBoneMatrix(GLint index, aiMatrix4x4 matrix)
{
    glm::mat4 mat = glm::transpose(glm::make_mat4(&matrix.a1));
    glUniformMatrix3fv(boneLocations[index], 1, GL_FALSE, glm::value_ptr(mat));  
}

此外,获取骨骼数组中所有uniform位置的代码:

for(unsigned int i = 0; i < 100; i++)
{
    string name = "bones[";
    string number;
    stringstream ss;
    ss << i;
    ss >> number;
    name += number;
    name += ']';
    boneLocations[i] = glGetUniformLocation(this->program, name.c_str());
}

1
@Katianie,是在顶点着色器的最后一行完成的 :) gl_Position = projection * view * model * newPos; newPos 变量乘以 MVP 矩阵。 - Joey Dewd
1
@Katianie 是的,转换确实是有效值(我应该把这一点添加到我的问题中),感谢你的注意。 - Joey Dewd
1
@Katianie这是针对旧版本的GLSL,主要用于旧版OpenGL编程(据我所知)。没有冒犯您Katianie,因为我很感激任何帮助,但现在看起来您似乎在试图帮助我,却没有对骨骼动画(或ASSIMP)有任何专业知识,这实际上没有帮到我 :p。 - Joey Dewd
1
我并不打算将这个作为答案提交,因为它只是一个临时解决方案,但我在OpenGL中使用大型统一数组时从未取得过多少成功,因此在我的引擎中,我将N个骨骼矩阵编码为由float4s组成的4N宽的一维纹理,并在每一帧更新(我将每个矩阵的4列存储在相邻的像素中)。这样做快速且适用于我测试的所有硬件;但它是一个权宜之计。 - MikeMx7f
1
一个统一缓冲对象会比1D纹理更好。但更重要的是,查询数组中每个uniform的位置没有意义。您可以使用类似于我在此答案中的代码检查数组的大小...数组中每个uniform位置都是顺序分配的,因此您只需要知道数组中第一个uniform的位置即可。 - Andon M. Coleman
显示剩余12条评论
1个回答

1

好的,通过glslDevil,我遇到了一个连续的GL_INVALID_OPERATION错误,当通过glUniformMatrix将骨矩阵设置到着色器时。问题的根源确实在程序将信息传递给着色器的阶段。

这其实是一个很愚蠢的错误,因为我使用的是glUniformMatrix3f而不是glUniformMatrix4f。更改后,问题确实得到解决,动画现在完美地工作。


1
我认为在每个GL API调用之后添加错误检查和/或通过ARB扩展设置错误回调是一个好主意。 - Ivan Aksamentov - Drop
@Drop 是的,下次我一定会这样做。 - Joey Dewd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接