为啥从帧缓冲区创建的纹理没有正确映射

Posted

技术标签:

【中文标题】为啥从帧缓冲区创建的纹理没有正确映射【英文标题】:Why the texture created from the framebuffer is not mapping correctly为什么从帧缓冲区创建的纹理没有正确映射 【发布时间】:2020-02-23 05:02:09 【问题描述】:

我正在创建一个大小为 1920 X 1080 的自定义帧缓冲区,然后将此帧缓冲区的纹理映射到大小为 800 X 600 的默认帧缓冲区中的全屏矩形。

我在自定义帧缓冲区中的屏幕中心绘制了一个矩形,在映射纹理后,我希望矩形出现在中心。

但是矩形出现在左下角。

当我在自定义缓冲区中绘制一个全屏矩形并将其映射到大小为 800 X 600 的默认帧缓冲区中的全屏矩形而不是全屏显示时,它会覆盖整个左下角。

SCR_WIDTH = 800;
SCR_HEIGHT = 600;
int main(int argc, char *argv[])


    QApplication a(argc, argv);
    cont.SetName("RootItem");
    TreeModel* model = new TreeModel("RootElement", &cont);
    WavefrontRenderer w(model);
    w.show();
    glfwInit();
    int return_code;
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Renderer", nullptr, nullptr);   // Create the render window
    glfwSetWindowPos(window, 1120, 480);
    glfwFocusWindow(window);    
    glfwMakeContextCurrent(window);
    GLenum GlewInitResult;
    glewExperimental = GL_TRUE;
    GlewInitResult = glewInit();    
    glEnable(GL_MULTISAMPLE);
    glEnable(GL_DEPTH_TEST);    
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    ResourceManager::LoadShader("C:\\Shaders\\Test\\Vert.txt", "C:\\Shaders\\Test\\Frag.txt", nullptr, "ScreenShader");

    //create a texture object
    glGenTextures(1, &textureId);
    glBindTexture(GL_TEXTURE_2D, textureId);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1920, 1080, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    glBindTexture(GL_TEXTURE_2D, 0);


    // create a  renderbuffer object for depthbuffer
    glGenRenderbuffers(1, &rboDepthId);
    glBindRenderbuffer(GL_RENDERBUFFER, rboDepthId);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 1920, 1080);
    glBindRenderbuffer(GL_RENDERBUFFER, 0);

    // create a  framebuffer
    glGenFramebuffers(1, &fboMsaaId);
    glBindFramebuffer(GL_FRAMEBUFFER, fboMsaaId);

    // attach colorbuffer image to FBO
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId , 0);

    // attach depthbuffer image to FBO
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepthId);
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);   
    while (!glfwWindowShouldClose(window))
    
        glBindFramebuffer(GL_FRAMEBUFFER, fboMsaaId);
        glClearColor(1.0, 0.0, 0.0, 1.0);
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
        w.render(); // Do rendering here    
        ResourceManager::GetShader("ScreenShader").Use();       
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        glDisable(GL_DEPTH_TEST);
        glClearColor(0.0, 0.0, 0.0, 0.0);
        glClear(GL_COLOR_BUFFER_BIT);
        ResourceManager::GetShader("ScreenShader").Use();
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, textureId);
        renderQuad();
        glfwPollEvents();
        glfwSwapBuffers(window);
          
     glfwTerminate();   
     return  a.exec();



/////////////////////////////////////// ///////////////////////////////////////// // Render Quad函数的定义

unsigned int quadVAO = 0;
unsigned int quadVBO;
void renderQuad()

    if (quadVAO == 0)
    
        float quadVertices[] =  // vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates.
        // positions   // texCoords
        -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
        ;
        //  VAO
        glGenVertexArrays(1, &quadVAO);
        glGenBuffers(1, &quadVBO);
        glBindVertexArray(quadVAO);
        glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));

    

    glBindVertexArray(quadVAO);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
    glBindVertexArray(0);

【问题讨论】:

【参考方案1】:

当您在不同大小的帧缓冲区之间切换时,您必须将视口调整为新大小。使用glViewport 设置视口。默认framebuffer的大小可以通过glfwGetFramebufferSize获取(窗口大小改变时,窗口framebuffer的大小也会改变)。 此外,OpenGL 是一个状态引擎。状态是持久的,直到它们再次被改变,甚至超出框架。如果第一遍使用Depth Test,但第二遍没有,那么深度测试必须在循环中打开和关闭:

int main(int argc, char *argv[])

    // [...]

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1920, 1080, ....);

    // [...]

    while (!glfwWindowShouldClose(window))
    
        int sizex, sizey;
        glfwGetFramebufferSize(window, &sizex, &sizey);

        glBindFramebuffer(GL_FRAMEBUFFER, fboMsaaId);
        glViewport(0, 0, 1920, 1080);
        glClearColor(1.0, 0.0, 0.0, 1.0);
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
        glEnable(GL_DEPTH_TEST);

        // [...]

        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        glViewport(0, 0, sizex, sizey);
        glClearColor(0.0, 0.0, 0.0, 0.0);
        glClear(GL_COLOR_BUFFER_BIT);
        glDisable(GL_DEPTH_TEST);

        // [...]
    

【讨论】:

以上是关于为啥从帧缓冲区创建的纹理没有正确映射的主要内容,如果未能解决你的问题,请参考以下文章

尝试从帧缓冲区传递纹理会导致 L_INVALID_OPERATION:glDrawArrays:绘制的源纹理和目标纹理相同

WebGL - 当我从帧缓冲区读取像素数据时,图标失去透明度

readPixels 函数返回未修改的纹理

OpenTK 屏幕外帧缓冲区扭曲并使用相同的材​​料不正确地渲染?

从帧缓冲区处理 YUV I420?

OpenGL 帧缓冲区 - 渲染到纹理创建带有主帧缓冲区内容的纹理