当前位置: 首页 > 知识库问答 >
问题:

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

孟翰藻
2023-03-14

我对这个问题感到非常恼火!我有一个简单的顶点和片段着色器,它在一台旧的Vaio笔记本电脑上运行得非常好(并且仍然如此)。它适用于粒子系统,并使用点精灵和单个纹理来渲染粒子。

当我使用更新的显卡(Nvidia GTX 660)在桌面上运行程序时,问题就开始了。我很确定我已经将其缩小到片段着色器,就好像我忽略了纹理并简单地再次传递inColor一样,一切都按预期进行。

当我在着色器计算中包括纹理时(如下图所示),在使用该着色器时绘制的所有点都会显示在屏幕中心,而不管相机位置如何。

使用可疑着色器,可以看到一大堆死心的粒子,以及右侧正确渲染的无纹理粒子。

顶点着色器是安全的:

#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窗口事件,并调用两个函数,绘制和更新。更新在任何时候都不会触及总账,绘图如下所示:

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

}

发射器-

照相机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));

发射器-

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

最后,粒子-

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个答案

张俊茂
2023-03-14

正如评论中所示,用于设置与相机相关的制服的shaderProgram变量并不取决于实际使用的程序。因此,在绘制纹理粒子时,会为不同的程序查询均匀位置。

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

 类似资料:
  • 片段着色器调用每个需要渲染的像素。我们将开发一个红色透镜,它将会增加图片的红色通道的值。 配置场景(Setting up the scene) 首先我们配置我们的场景,在区域中央使用一个网格显示我们的源图片(source image)。 import QtQuick 2.0 Rectangle { width: 480; height: 240 color: '#1e1e1e'

  • 我需要一个着色程序,然后我需要一个着色程序。一旦我从我的着色器中获得和后,是否可以将它们作为采样器发送到着色器中,以便在屏幕上渲染到四元体上? 我需要将颜色附件发送到第二个着色器的原因是,我正在不同的监视器上渲染和将出现在一个屏幕上,而将出现在另一个屏幕上。。。 我正在做测试视力的心理实验。我的第一个着色器处理我的原始纹理集,但由于两个输出纹理所需的大部分处理是相同的,所以如果不需要,我基本上不想

  • 如何使用片段着色器绘制一条线或一条曲线? 我有一个程序,根据用户指定的一组顶点计算贝塞尔曲线。在早期,我非常简单,只需在应用程序端处理每个顶点,就可以根据三次贝塞尔曲线方程生成一组插值点: ... 然后将所有处理过的顶点存储到GL_VERTEX_数组中,以便使用glDrawArrays(GL_LINE_STRIP,0,myArraySize)绘制。虽然解决方案很简单,但此实现的时间复杂度为O(n^

  • 我希望在2D OpenGL应用程序上实现着色器。我的计划是将场景渲染到帧缓冲区对象,然后使用着色器将该帧缓冲区对象渲染到屏幕。 这是我绘制到帧缓冲区对象的场景,然后从那里绘制到屏幕。使用箭头键可以让月亮四处移动(我很自豪!) 但是,当我尝试使用着色器程序将帧缓冲区对象渲染到屏幕上时,我得到以下结果: 这是非常可悲的。这个片段着色器是我从一个教程中得到的,我相信问题一定是统一变量。 以下是片段着色器

  • 我已经写了一个C程序,在这里我画了一个茶壶并应用了照明。它本身很简单,但我也使用着色器。简单我是GLSL新手我刚刚尝试了一个简单的片段着色器,但是屏幕输出令人费解。 在这个文件中,我在init方法中初始化了glew,在这里我还编译了顶点和片段着色器。它们位于“顶点着色器”和“片段着色器”文件中。 你可能不认识什么是Light和材质。它们只是一些包含有关灯的所有信息的结构。我已经测试了这些结构,所以

  • WebGL的着色器代码分为顶点着色器代码和片元着色器代码两部分,顶点着色器代码会在GPU的顶点着色器单元执行,片元着色器代码会在GPU的片元着色器单元执行,在WebGL渲染管线流程中,或者说GPU的渲染流程中,顶点着色器代码先执行处理顶点,得到一系列片元,然后再执行片元着色器代码处理片元。 main()函数 顶点着色器和片元着色器代码都有一个唯一的主函数main(),attribute、varyi