简单的GL片段着色器在较新的GPU上表现奇怪

时间:2016-04-03 16:44:14

标签: opengl glsl fragment-shader

我正在解决这个问题!我有一个简单的顶点和片段着色器,可以在旧的Vaio笔记本电脑上完美地工作(并且仍然可以)。它适用于粒子系统,并使用点精灵和单个纹理来渲染粒子。

当我在台式机上运行程序时,问题就出现了,它带有更新的显卡(Nvidia GTX 660)。我非常确定我已将其缩小到片段着色器,就好像我忽略了纹理并简单地再次传入inColor,一切都按预期工作。

当我在着色器计算中包含纹理时,如下所示,在使用该着色器时绘制的所有点都显示在屏幕的中央,无论相机位置如何。

Example screenshot attached

你可以使用可疑着色器看到一堆乱七八糟的粒子死角,并且无纹理粒子正确地向右渲染。

顶点着色器是安全的:

#version 150 core
in vec3 position;
in vec4 color;

out vec4 Color;

uniform mat4 view;
uniform mat4 proj;
uniform float pointSize;

void main() {
   Color = color;
   gl_Position = proj * view * vec4(position, 1.0);
   gl_PointSize = pointSize;
}

我怀疑片段着色器是个问题,但真的不明白为什么:

#version 150 core
in vec4 Color;
out vec4 outColor;
uniform sampler2D tex;

void main() {
   vec4 t = texture(tex, gl_PointCoord);

   outColor = vec4(Color.r * t.r, Color.g * t.g, Color.b * t.b, Color.a * t.a);
}

无纹理粒子使用相同的顶点着色器,但以下片段着色器:

#version 150 core
in vec4 Color;
out vec4 outColor;
void main() {
   outColor = Color;
}

主程序有一个循环处理SFML窗口事件,并调用2个函数,绘制和更新。更新不会在任何时候触摸GL,绘制如下:

void draw(sf::Window* window)
{
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    sf::Texture::bind(&particleTexture);

    for (ParticleEmitter* emitter : emitters)
    {
        emitter->useShader();
        camera.applyMatrix(shaderProgram, window);
        emitter->draw();
    }

}

emitter-> useShader()只是使用指向创建时存储在发射器对象中的着色器程序的GLuint调用glUseShader()。

camera.applyMatrix():

GLuint projUniform = glGetUniformLocation(program, "proj");
glUniformMatrix4fv(projUniform, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
...
GLint viewUniform = glGetUniformLocation(program, "view");
glUniformMatrix4fv(viewUniform, 1, GL_FALSE, glm::value_ptr(viewMatrix));

emitter-> draw()在它的整体中:

    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    // Build a new vertex buffer object
    int vboSize = particles.size() * vboEntriesPerParticle;
    std::vector<float> vertices;
    vertices.reserve(vboSize);

    for (unsigned int particleIndex = 0; particleIndex < particles.size(); particleIndex++)
    {
        Particle* particle = particles[particleIndex];
        particle->enterVertexInfo(&vertices);
    }

    // Bind this emitter's Vertex Buffer
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    // Send vertex data to GPU
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(), &vertices[0], GL_STREAM_DRAW);

    GLint positionAttribute = glGetAttribLocation(shaderProgram, "position");
    glEnableVertexAttribArray(positionAttribute);
    glVertexAttribPointer(positionAttribute,
        3,
        GL_FLOAT,
        GL_FALSE,
        7 * sizeof(float),
        0);

    GLint colorAttribute = glGetAttribLocation(shaderProgram, "color");
    glEnableVertexAttribArray(colorAttribute);
    glVertexAttribPointer(colorAttribute,
        4,
        GL_FLOAT,
        GL_FALSE,
        7 * sizeof(float),
        (void*)(3 * sizeof(float)));

    GLuint sizePointer = glGetUniformLocation(shaderProgram, "pointSize");
    glUniform1fv(sizePointer, 1, &pointSize);

    // Draw
    glDrawArrays(GL_POINTS, 0, particles.size());

最后,particle-&gt; enterVertexInfo()

vertices->push_back(x);
vertices->push_back(y);
vertices->push_back(z);
vertices->push_back(r);
vertices->push_back(g);
vertices->push_back(b);
vertices->push_back(a);

我很确定这不是一个有效的方法来完成所有这些,但这是我在一学期前写的课程。我只是重新审视它以记录它的实际视频。

所有着色器编译和链接都没有错误。通过使用片段着色器,我已经确认我可以使用gl_PointCoord来改变粒子间的纯色,这样就可以正常工作了。当粒子在屏幕中心绘制时,纹理被正确绘制,虽然位置错误,因此也可以正确加载和绑定。我绝不是一名GL专家,因此我可以根据自己的想法进行调试。

如果它不能在旧笔记本电脑上完美运行,那么这不会让我烦恼!

编辑:包含大量代码

1 个答案:

答案 0 :(得分:1)

正如评论中所述,用于设置相机相关制服的shaderProgram变量并不依赖于实际使用的程序。因此,在绘制纹理粒子时,会针对不同的程序查询统一位置。

统一位置分配完全是特定于实现的,例如nvidia倾向于按统一名称的字母顺序分配它们,因此view的位置会根据tex实际存在而改变(或被动地使用)或不。如果其他实现只是按照它们出现在代码或其他方案中的顺序来分配它们,那么事情可能会偶然发生。