You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加Frame Buffer后gl_FragCoord.y坐标异常的问题求助

问题描述

添加Frame Buffer并向其绘制内容后,默认Frame Buffer的gl_FragCoord.y坐标范围变为底部-600、顶部0,而非原本的底部0、顶部600。尝试调整窗口尺寸、Frame Buffer尺寸及Viewport,但仍无法消除坐标负值问题,只要向Frame Buffer绘制就会触发该异常。测试时通过判断gl_FragCoord.y > -300来提亮颜色,此时屏幕一半区域亮起。

复现代码
#include <glad/glad.h> 
#include <GLFW/glfw3.h>

#include <iostream>

// vertex shader
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";

// fragment shader
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"vec4 light = vec4(0.1f, 0.1f, 0.1f, 0.1f);\n"
"void main()\n"
"{\n"
"if (gl_FragCoord.y > -300)\n"
"{\n"
"light = vec4(1.0f, 1.0f, 1.0f, 1.0f);\n"
"}\n"
"FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f) * light;\n"
"}\n\0";

const int Width = 800;
const int Height = 600;

int main()
{
    glfwInit();

    GLFWwindow* window = glfwCreateWindow(Width, Height, "Test", 
      NULL, NULL);

    glfwMakeContextCurrent(window);

    
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    // vertex shader
    unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);

    // fragment shader
    unsigned int fragmentShader = 
    glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);

    // link shaders
    unsigned int shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);


    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);


    float square[] = {
        -1.0f,  1.0f,
        -1.0f, -1.0f,
         1.0f, -1.0f,

        -1.0f,  1.0f,
         1.0f, -1.0f,
         1.0f,  1.0f,
    };

    unsigned int VBO, VAO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(square), square, 
      GL_STATIC_DRAW);

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * 
      sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindVertexArray(0);

    float vertices[] = {
        // pos      // tex
        -1.0f,  1.0f,  0.0f, 1.0f,
        -1.0f, -1.0f,  0.0f, 0.0f,
         1.0f, -1.0f,  1.0f, 0.0f,

        -1.0f,  1.0f,  0.0f, 1.0f,
         1.0f, -1.0f,  1.0f, 0.0f,
         1.0f,  1.0f,  1.0f, 1.0f
    };

    unsigned int FBO;
    unsigned int quadVAO;
    unsigned int texture;

    glGenVertexArrays(1, &quadVAO);

    glGenBuffers(1, &VBO);
    glBindVertexArray(quadVAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, 
      GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * 
      sizeof(float), (void*)0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    // load framebuffer
    glGenFramebuffers(1, &FBO);
    glBindFramebuffer(GL_FRAMEBUFFER, FBO);

    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, Width, Height, 0, 
      GL_RGB, GL_UNSIGNED_BYTE, NULL);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
      GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 
      GL_NEAREST);
    glBindTexture(GL_TEXTURE_2D, 0);

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 
      GL_TEXTURE_2D, texture, 0);
    // renderbufferobject
    unsigned int RBO;
    glGenRenderbuffers(1, &RBO);
    glBindRenderbuffer(GL_RENDERBUFFER, RBO);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 
      Width, Height);

    glBindRenderbuffer(GL_RENDERBUFFER, 0);

    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == 
      GL_FRAMEBUFFER_COMPLETE)
    {
        std::cout << "FBO connected" << "\n";
    }
    else
    {
        std::cout << "Unable to connect to FBO" << 
        glCheckFramebufferStatus(GL_FRAMEBUFFER) << "\n";
    }


    // render loop
    while (!glfwWindowShouldClose(window))
    {
        // frame buffer
        glBindFramebuffer(GL_FRAMEBUFFER, FBO);
        glClearColor(0.11f, 0.16f, 0.32f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glEnable(GL_DEPTH_TEST);
        
        // draw square
        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);
        // not drawing here stops the issue
        glDrawArrays(GL_TRIANGLES, 0, 6);

        // back to default frame buffer
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        glDisable(GL_DEPTH_TEST);
        glClearColor(0.11f, 0.16f, 0.32f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // draw square
        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES, 0, 6);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}
问题分析与解决

问题根源是切换回默认帧缓冲后未显式重置视口(Viewport)。绑定FBO并绘制时,OpenGL会自动将视口设置为FBO的尺寸,但FBO的纹理Y轴方向与默认帧缓冲存在差异,切换回默认帧缓冲后,视口原点未被正确重置,导致gl_FragCoord的Y轴范围出现负值。

解决方法:
在切换回默认帧缓冲后,调用glViewport(0, 0, Width, Height)显式设置视口,确保坐标系统与窗口匹配。修改后的渲染循环关键部分如下:

// back to default frame buffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// 显式设置视口,匹配窗口尺寸
glViewport(0, 0, Width, Height);
glDisable(GL_DEPTH_TEST);
glClearColor(0.11f, 0.16f, 0.32f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

// draw square
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 6);

也可以在初始化时设置一次视口,但由于切换FBO时OpenGL会自动修改视口,建议每次切换帧缓冲后都显式设置对应视口参数,避免坐标偏移问题。

内容的提问来源于stack exchange,提问作者Couchy123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 02:28:10