【问题标题】:GLSL uniform only being updated by unrelated callsGLSL 统一仅由不相关的调用更新
【发布时间】:2013-05-17 12:25:04
【问题描述】:

我有一个非常基本的 GLSL 程序,它在第一次绘制调用后无法正确更新统一值。没有收到来自glGetError 的错误,编译和链接着色器时信息日志中没有报告错误,并且所有统一位置都有效。

顶点着色器:

#version 120

uniform mat4 mvp;
uniform mat3 nmv;

attribute vec3 position;
attribute vec3 normal;

varying vec3 v_normal;

void main()
{
    v_normal = normalize(nmv * normal);
    gl_Position = mvp * vec4(position, 1.0);
}

片段着色器:

#version 120

uniform vec3 lightDir;
uniform vec3 lightColor;
uniform vec3 materialColor;

varying vec3 v_normal;

void main()
{
    vec3 n = normalize(v_normal);
    float nDotL = max(0.0, dot(n, lightDir));

    gl_FragColor = vec4(materialColor * lightColor * nDotL, 1.0);
}

渲染代码:

glUseProgram(program);
glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, mvp);
glUniformMatrix3fv(nmvLoc, 1, GL_FALSE, nmv);
glUniform3fv(lightDirLoc, 1, lightDir);
glUniform3fv(lightColorLoc, 1, lightColor);

for (auto mesh: meshes)
{
    glUniform3fv(materialColorLoc, 1, mesh.color);
    mesh.draw();
}

渲染的mesh都是用第一个mesh的颜色绘制的,说明在初始设置了materialColoruniform之后,后面的修改uniform的调用都被忽略了。但是,这里列出了一些特殊条件,它们可以独立地正确更新制服:

  • 在循环内调用glUseProgram(program)
  • 在循环中设置 mvpnmv 制服。
  • 在循环中设置 lightDir 统一。
  • 从着色器程序中删除uniform vec3s 之一。

请注意,在循环中设置lightColor 制服将不会更新materialColor 制服。我还在循环中检查了GL_CURRENT_PROGRAM,并且着色器始终处于绑定状态。

我已经尝试解决这个问题几个小时,但绝对找不到问题。这个着色器设置非常简单,我不相信这是一个驱动程序错误。我在带有 NVIDIA GeForce 9400M 的 Mac OS X 10.8.3 上使用 OpenGL 2.1。

这是单个帧的调用跟踪:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(1);
glUniformMatrix4fv(1, 1, 0, 0x7fff55512550); // mvp
glUniformMatrix3fv(5, 1, 0, 0x7fff55512528); // nmv
glUniform3fv(0, 1, 0x7fff55512670);          // lightDir
glUniform3fv(9, 1, 0x7fff555124e8);          // lightColor

// Mesh 0
glUniform3fv(8, 1, 0x7fab820cd7ec);          // materialColor
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 1);
glEnableVertexAttribArray(0);
glVertexAttribPointerARB(0, 3, GL_FLOAT, 0, 24, 0x00000000);
glEnableVertexAttribArray(2);
glVertexAttribPointerARB(2, 3, GL_FLOAT, 0, 24, 0x0000000c);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 21);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

// Mesh 1
glUniform3fv(8, 1, 0x7fab823000bc);          // materialColor
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 2);
glEnableVertexAttribArray(0);
glVertexAttribPointerARB(0, 3, GL_FLOAT, 0, 24, 0x00000000);
glEnableVertexAttribArray(2);
glVertexAttribPointerARB(2, 3, GL_FLOAT, 0, 24, 0x0000000c);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 24);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

// Mesh 2
glUniform3fv(8, 1, 0x7fab8231f8fc);          // materialColor
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 3);
glEnableVertexAttribArray(0);
glVertexAttribPointerARB(0, 3, GL_FLOAT, 0, 24, 0x00000000);
glEnableVertexAttribArray(2);
glVertexAttribPointerARB(2, 3, GL_FLOAT, 0, 24, 0x0000000c);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 21);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

// Mesh 3
glUniform3fv(8, 1, 0x7fab820cf41c);          // materialColor
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 4);
glEnableVertexAttribArray(0);
glVertexAttribPointerARB(0, 3, GL_FLOAT, 0, 24, 0x00000000);
glEnableVertexAttribArray(2);
glVertexAttribPointerARB(2, 3, GL_FLOAT, 0, 24, 0x0000000c);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 18);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

CGLFlushDrawable();

编辑:这是用于获取统一位置的代码。它在着色器编译和链接后执行,并且所有制服都被验证为有效。

GLint mvpLoc = glGetUniformLocation(program, "mvp");
GLint nmvLoc = glGetUniformLocation(program, "nmv");
GLint lightDirLoc = glGetUniformLocation(program, "lightDir");
GLint lightColorLoc = glGetUniformLocation(program, "lightColor");
GLint materialColorLoc = glGetUniformLocation(program, "materialColor");

【问题讨论】:

  • 在我看来,lightColor 和 lightDir 制服之间的唯一区别是它们在着色器中的位置。您是否尝试过切换他们的位置并查看 lightColor 是否确实触发了更改?我还会尝试查看 ATI 或 Intel GPU 是否会产生相同的行为。
  • 我刚刚尝试切换它们的顺序,但行为仍然完全相同。 lightColor 仍然不会触发更改。很遗憾,我目前无法使用其他 GPU。
  • 我注意到交换声明顺序或它们在操作中的位置导致它们的统一位置保持不变。
  • 好奇者和好奇者。 :) 您是否可以发布一个完整的工作示例,我可以在不同的硬件/驱动程序平台上编译/运行?还是从您当前的应用程序中提取工作量太大?
  • 从这个应用程序中提取并提供一个工作样本是相当困难的。但是,如果您想尝试复制该行为,您应该能够使用呼叫跟踪数据来执行完全相同的操作。

标签: opengl glsl


【解决方案1】:

还没解决?

mesh.color 的类型是什么

查看传递到调用跟踪中的地址,它们似乎相当高,也许您应该将地址传递给数据而不是实际数据,0x7fab823000bc

glUniform3fv(materialColorLoc, 1, &mesh.color); 也许尝试硬编码和使用 glUniform3f()

【讨论】:

    【解决方案2】:

    从跟踪中的所有地址中,我猜您发送给 GL 的任何 vec3 都是 float name[3] 类型的,不是吗?假设这一点,我无法在您的代码中发现错误。正如您所说,glGetError 没有返回错误状态,它必须是驱动程序错误。

    我在跟踪中看到您开始每个网格都执行 glBindBuffer(GL_ARRAY_BUFFER, 0) - 这并不是真正必要的。但无论如何,我也无法想象这是源头。

    遗憾的是,您无法在链接之前测试 glBindUniformLocation 之类的东西,因为这不是 OpenGL 的一部分。

    我的经验表明:如果您发出 glUniform3fv 并且所有参数都正确,那么制服就会更新并且该更改立即可见。由于情况并非如此,在这里,它必须是一个驱动程序错误,所以您唯一可能做的事情是:向您的渲染循环添加其他不必要的调用以使更改可见(如果我正确阅读,您已经这样做了) .

    【讨论】:

      【解决方案3】:
      1. 有时司机会优化你的一些制服(即使它不应该特别是老司机)。测试尝试在顶点着色器中使用您的材质颜色(将其复制到一些可变变量并在片段着色器中使用该可变变量而不是统一,这有时对我有用,...当然它会降低性能)

      2. 尝试使用不同的配置文件版本。在某些情况下,较新的驱动程序无法正确模拟旧版本。您是否尝试过核心配置文件? (我知道用旧代码实现它非常棘手)

      3. 你可以尝试 nvemulate 来测试不同的驱动设置

      有时会忘记 glEnd();尝试在帧渲染代码之前添加此代码会带来很多麻烦:

      glEnd();
      glEnd();
      glEnd();
      glEnd();
      glEnd();
      glEnd();
      glEnd();
      glEnd();
      glEnd();
      glEnd();
      glEnd();
      ... here comes your rendering code
      

      如果这比您忘记调用 glEnd() 有帮助的话;某处或有 glEnd;而不是 glEnd();

      [编辑1]

      在您添加 CPU 侧网格绘制相关代码后,很明显您硬编码了所有 VBOuniform 位置,但您的片段和顶点着色器不是静态的随处可见的地点

      并查找glGetUniformLocation 的用法。同样在着色器中,您可以这样声明:

      layout(location = 0) in vec3 pos;
      

      但这是旧版本中较新的 GLSL 可能有点不同并且懒得搜索语法和关键字...

      【讨论】:

      • glEnd 问题会触发 GL 错误,OP 声明该错误已检查。
      • OP 使用现代 GL,glEnd 已弃用
      • @mackycheese21 很好,现在已经指定了,但在回答这个问题的时候没有回来,......并且由于 OP 作者没有通知我没有办法知道这一点......仍然@ 987654327@ 只是答案的一部分......在查看呼叫跟踪后,很可能是位置问题,因为所有 VBO 和制服都在 CPU 端代码中硬编码,但在 GLSL 部分中没有......
      • 对不起!我没有看到发布日期。
      猜你喜欢
      • 2011-01-31
      • 1970-01-01
      • 1970-01-01
      • 2014-08-14
      • 1970-01-01
      • 2017-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多