GLSL制服仅由不相关的呼叫更新

时间:2013-05-17 12:25:05

标签: opengl glsl

我有一个非常基本的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();
}

渲染的网格物体全部以第一个网格物体的颜色绘制,表示在最初设置materialColor制服之后,将忽略后续调整更改制服的调用。但是,这里有一个特殊条件列表,它们可以独立地正确地更新制服:

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

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

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

以下是单帧的呼叫追踪:

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");

3 个答案:

答案 0 :(得分:0)

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

  2. 尝试使用不同的个人资料版本。在某些情况下,较新的驱动程序无法正确模拟旧版本。你试过核心档案吗? (我知道使用旧代码实现它非常棘手)

  3. 您可以尝试使用nvemulate来测试不同的驱动程序设置

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

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

    如果这有助于你忘记调用glEnd();在某处或有glEnd;而不是glEnd();

    <强> [EDIT1]

    添加 CPU 侧网格绘制相关代码后,清楚地表明您对所有 VBO uniform位置进行了硬编码,但您的片段和顶点着色器已经不是任何地方的静态位置

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

    layout(location = 0) in vec3 pos;
    

    但是对于旧版本中较新的 GLSL ,它可能会有点不同,而且懒得搜索语法和关键字......

答案 1 :(得分:0)

还没有解决?

mesh.color

的类型是什么 看看传入调用跟踪的地址它们看起来相当高,也许你应该将地址传递给数据而不是实际数据,0x7fab823000bc

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

答案 2 :(得分:0)

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

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

可悲的是,你无法在链接之前测试像glBindUniformLocation这样的东西,因为它不是OpenGL的一部分。

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