【问题标题】:Skeletal Animation ussing ASSIMP and GLSL: bone uniform array size使用 ASSIMP 和 GLSL 的骨骼动画:骨骼统一数组大小
【发布时间】:2014-01-15 04:59:17
【问题描述】:

我正在开发一个 ASSIMP 骨骼动画加载器和渲染器,现在所有数据都在其当前时间范围内正确加载和插值。但是,仍然有一部分不能正常工作,那就是顶点着色器阶段。

通过 VBO 我传入两个 vec4s,其中包含每个顶点的骨骼 ID 和权重(每个顶点最多 4 个骨骼/权重vertex) 并且顶点着色器有一个由 100 个骨骼变换(每帧预先计算)组成的矩阵数组,这些变换通过骨骼 ID 进行索引。

但是,骨骼制服似乎不包含正确的转换。出于调试目的,我使用权重值和骨骼 ID 值为模型着色,它们包含颜色(因此包含有效值)。然而,当我通过骨骼变换来变换我的顶点并用结果为模型着色时,整个模型都是黑色的,这意味着变换矩阵都是0.0。所以它们没有正确初始化。

我认为问题在于将矩阵传递给统一数组,或者可能是允许的统一最大尺寸(我还尝试将统一矩阵的数量设置为 32(当前的骨骼数量)模型)但没有效果)?

在将信息传递给着色器之前,转换矩阵确实是有效矩阵(不是恒等/空矩阵),因此故障可能出在 GLSL 着色器或制服的传递中。

以下代码来自顶点着色器:

#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;
}

以下 sn-p 代码将矩阵数据传递给 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));  
}

也是获取骨骼数组所有统一位置的代码:

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());
}

【问题讨论】:

  • @Katianie 是的,这是在顶点着色器的最后一行完成的 :) gl_Position = projection * view * model * newPos; newPos 变量在那里乘以 MVP 矩阵。
  • @Katianie 是的,转换确实是有效值(我应该将其添加到我的问题中),感谢您的注意。
  • @Katianie 适用于旧版本的 GLSL,主要用于旧的 OpenGL 编程(据我所知)。 Katianie 没有冒犯你,因为我感谢任何帮助,但现在看起来你正在试图帮助我,但没有任何骨骼动画(或 ASSIMP)方面的专业知识,说实话这对我没有帮助:p。
  • 我不会将此作为答案提交,因为它只是一种解决方法,但我对 OpenGL 中的大型统一数组从来没有太多运气,所以在我的引擎中,我将 N 个骨骼矩阵编码为 4N 宽float4s 的 1D 纹理并更新每一帧(我将每个矩阵的 4 列存储在相邻的纹素中)。它速度快,适用于我测试过的所有硬件;但这是一个杂牌。
  • 统一缓冲区对象将是一维纹理的更好替代方案。但更重要的是,查询数组中每个制服的位置是没有意义的。您可以使用我在此answer 中的一些代码检查数组的大小...数组中的每个统一位置都是按顺序分配的,因此您只需要知道数组中第一个统一的位置。跨度>

标签: c++ opengl glsl skeletal-animation


【解决方案1】:

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

实际上这是一个非常愚蠢的错误,因为我使用的是glUniformMatrix3f 而不是glUniformMatrix4f。改变这一点确实解决了这个问题,并且动画现在运行良好。

【讨论】:

  • 我认为在每次 GL API 调用后添加错误检查和/或通过 ARB 扩展设置错误回调是个好主意。
  • @Drop 是的,下次我一定会这样做
猜你喜欢
  • 2017-07-22
  • 2014-09-23
  • 2017-01-30
  • 1970-01-01
  • 2017-04-10
  • 2016-07-31
  • 2012-10-17
  • 2011-04-02
  • 2021-11-07
相关资源
最近更新 更多