将 Sampler2D 与着色器一起使用的问题

Posted

技术标签:

【中文标题】将 Sampler2D 与着色器一起使用的问题【英文标题】:Issue with using Sampler2D with a Shader 【发布时间】:2015-03-14 14:01:36 【问题描述】:

!我知道有比这更简单的方法来绘制到屏幕上,但我需要以这种特定的方式来做!

我正在通过 fbo 绘制纹理。 然后,我使用着色器将其重新绘制到屏幕上,使用 sampler2D(纹理的)这样做,并让着色器将 gl_fragColor 设置为片段着色器所在特定点的 sampler2D 的颜色。

我遇到的问题是显示缓冲区(着色器将 fbo 绘制到该缓冲区)只是纯蓝色,即使我在蓝色背景的 fbo 上绘制了一个白色方块。

我的代码:

主渲染循环:

while(!Display.isCloseRequested())
        //Drawing on the fbo a blue background and white square
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboID);
        glColor3f(0,0,1);
        drawQuad(0,0,WIDTH,HEIGHT);
        glColor3f(1,1,1);
        drawQuad(0,0,50,50);

        //Trying to draw the texture from the previous fbo
        //on to the display buffer with a fragment shader,
        //however it only draws a blue background, no white square.

        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

        GL13.glActiveTexture(GL13.GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D,texID);
        glUseProgram(shaderProgram);
        glUniform1i(glGetUniformLocation(shaderProgram, "tex"), 0);
        glUniform1f(glGetUniformLocation(shaderProgram, "width"), WIDTH);
        glUniform1f(glGetUniformLocation(shaderProgram, "height"), HEIGHT);

        glBegin(GL_QUADS); 
            glVertex2f(0, 0);
            glVertex2f(0, HEIGHT);
            glVertex2f(WIDTH, HEIGHT);
            glVertex2f(WIDTH, 0);
         glEnd();
        glUseProgram(0);

        Display.update();
    

我的着色器:

uniform sampler2D tex;
uniform float width;
uniform float height;

void main() 
    vec4 color = texture2D( tex, gl_FragCoord.xy / vec2(width, height));
    gl_FragColor = color;

fbo 的初始化方法:

    texID=glGenTextures();
    fboID=glGenFramebuffersEXT();

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboID);
    glBindTexture(GL_TEXTURE_2D, texID);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, WIDTH, HEIGHT, 0,GL_RGBA, GL_INT, (java.nio.ByteBuffer) null);
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D, texID, 0);
    glBindTexture(GL_TEXTURE_2D, 0);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

我认为发生这种情况的一个原因可能是我没有正确地将 Sampler2D 传递给着色器,但我不知道如何修复它。

如果有人能说出为什么会发生这种情况或如何解决它(甚至只是朝着正确方向的一点),我们将不胜感激!

(对不起,英语不好!)

【问题讨论】:

固定管道,即像 glBegin)/glEnd() 这样的函数不会与编程管道(着色器)混合。你不能同时使用两者 @Amadeus:可以,只是不能在核心配置文件中使用这些功能。确实和固定功能操作无关;立即模式在 OpenGL 3.0 中被弃用并在 3.1 中被删除。当然,固定功能管道也同时被弃用和删除,因此您可能很容易将两者等同起来。 @AndonM.Coleman 是的,你可以,但它可以或不能渲染到屏幕上,这会给你带来难以找到的错误 如果glBegin (...)glEnd (...) 和朋友是固定功能管道的一部分,那将是真的,但他们不是。它们完全存在于渲染管道之外,它们将顶点状态打包在一起,并在第一阶段(顶点处理)开始之前定义原始拓扑。作为固定功能管道一部分的一个例子是顶点照明,它曾经在顶点变换期间应用。 【参考方案1】:

您已将呼叫转接到glUniform1i (...)glUseProgram (...)

在执行glUniform1i(glGetUniformLocation(shaderProgram, "tex"), 0); 时,当前活动的程序是0,实际上应该产生以下错误:

如果没有当前程序对象,则生成GL_INVALID_OPERATION

如果您交换上面提到的两行,那应该可以解决您的问题。以后当某些东西不起作用时,您应该注意检查glGetError (...)


更新:现在原始问题已解决,但您没有正确设置纹理缩小过滤器。

要设置枚举数,您必须使用glTexParameteri (...)glTexParameterf (...) 会将传递的值解释为浮点数,GL_LINEAR (0x2601) 的类型为 GLenum(32 位无符号整数)。幸运的是,所有核心 OpenGL 枚举都只使用低 16 位,因此它们可以精确地表示为 32 位浮点数(可以表示最大为 224 的所有整数),但你可以明白为什么你不想要将整数常量转换为浮点数。

因此,以下行:

glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

需要:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

更新 2:在使用 texture2D (...) 时必须使用标准化纹理坐标。

gl_FragCoord.xy 的范围为 [0, width] 和 [0, height],对于任何大于1x1。要解决这个问题,您必须除以宽度和高度。

texelFetch (...) 允许您使用非标准化坐标,但它需要 GLSL 1.30,并且您必须将 gl_FragCoord.xy 转换为 ivec2 才能使用它。如果您绘制的 FBO 的尺寸与您的窗口不同,这也可能会带来不便。

【讨论】:

@Meta:你能把分配纹理的代码添加到你的FBO的GL_COLOR_ATTACHMENT0吗? 我为fbo添加了init方法,是这个意思吗? 我换了行,但它仍然不起作用:(我用你的更新更新 q 如果我上传整个课程会有帮助吗? @Meta:顺便说一句,你以后真的不应该这样编辑你的问题。我的答案所指的原始代码完全消失了。如果您对问题进行了更改,则应保留原始代码并提及您更改的代码行。

以上是关于将 Sampler2D 与着色器一起使用的问题的主要内容,如果未能解决你的问题,请参考以下文章

在片段着色器中,为啥我不能使用平面输入整数来索引 sampler2D 的统一数组?

纹理同时用作着色器程序的 FBO 颜色附件和 sampler2D

将 emscripten 与 opengl 着色器一起使用

无法让 openGL 的 glDrawElements 与几何着色器一起使用

SpriteKit 着色器未与制服一起运行

OpenGL 2D纹理单元&纹理翻转解决策略