Буфер глубины OpenGL или тест глубины не работают при рендеринге с общим контекстом

У меня есть очень специфическая настройка OpenGL, в которой 3D-геометрия сцены не отображается. В контексте OpenGL есть какое-то состояние, связанное с глубиной, которое вызывает у меня иллюзию.

Это происходит в рабочем движке, где мы добавили поддержку общего контекста с несколькими контекстами окна. Мы выполняем рендеринг в объект буфера кадра, принадлежащий общему контексту, а затем переносим буфер рендеринга прикрепления цвета в окно, используя другой контекст.

Чистый цвет отображается в результирующем блите к окну, но не в самой геометрии 3D-сцены, поэтому мы знаем, что объекты фреймбуфера и буфера рендеринга по крайней мере частично верны.

Для иллюстрации я провел рефакторинг примера с веб-сайта LearnOpenGL, чтобы проиллюстрировать мою ошибку. Он также появляется там, поэтому я понимаю, что это то, что мне не хватает.

Вот проект GitHub, в котором я сделал три коммита для образца работающего фреймбуфера, чтобы он отображался в фреймбуфере с использованием общего контекста, а затем блицировал результат: Эксперимент с общим контекстом фреймбуфера

Вот большая часть исходного кода, который приводит к ошибкам. Я вырезал несколько разделов, которые остались без изменений.

    // glfw dummy window creation
    // --------------------
    GLFWwindow* dummy = NULL;
#if USE_SHARED_CONTEXT
    dummy = glfwCreateWindow(1, 1, "Dummy", NULL, NULL);
    if (dummy == NULL)
    {
        std::cout << "Failed to create dummy GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(dummy);
#endif

    // glfw window creation
    // --------------------
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, dummy);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwShowWindow(window);
#if !USE_SHARED_CONTEXT
    glfwMakeContextCurrent(window);
#endif

    // <snip creation of shared resources>
    // <snip creation of un-shared vertex array>

    // framebuffer configuration
    // -------------------------
    unsigned int framebuffer;
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);

#if 1
    // create a color attachment render buffer
    unsigned int Colorbuffer;
    glGenRenderbuffers(1, &Colorbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, Colorbuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, SCR_WIDTH, SCR_HEIGHT); // use a single renderbuffer object for both a depth AND stencil buffer.
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, Colorbuffer); // now actually attach it
#else
    // create a color attachment texture
    unsigned int textureColorbuffer;
    glGenTextures(1, &textureColorbuffer);
    glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0);
#endif

    // create a renderbuffer object for depth and stencil attachment (we won't be sampling these)
    unsigned int rbo;
    glGenRenderbuffers(1, &rbo);
    glBindRenderbuffer(GL_RENDERBUFFER, rbo);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, SCR_WIDTH, SCR_HEIGHT); // use a single renderbuffer object for both a depth AND stencil buffer.
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // now actually attach it
    // now that we actually created the framebuffer and added all attachments we want to check if it is actually complete now
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    // render loop
    // -----------
    while (!glfwWindowShouldClose(window))
    {
        // <snip timing and input>

    #if USE_SHARED_CONTEXT
        // use shared context because that is what is holding our framebuffer and vao.
        // -----
        glfwMakeContextCurrent(dummy);
    #endif

        // render
        // ------
        // bind to framebuffer and draw scene as we normally would to color texture 
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
        glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad)

        // make sure we clear the framebuffer's content
        glClearColor(1.0f, 0.1f, 0.1f, 1.0f);
        glClearDepth(1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // following render is unchanged
        shader.use();
        glm::mat4 model;
        glm::mat4 view = camera.GetViewMatrix();
        glm::mat4 projection = glm::perspective(camera.Zoom, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
        shader.setMat4("view", view);
        shader.setMat4("projection", projection);
        // cubes
        glBindVertexArray(cubeVAO);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, cubeTexture);
        model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
        shader.setMat4("model", model);
        glDrawArrays(GL_TRIANGLES, 0, 36);
        model = glm::mat4();
        model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));
        shader.setMat4("model", model);
        glDrawArrays(GL_TRIANGLES, 0, 36);
        // floor
        glBindVertexArray(planeVAO);
        glBindTexture(GL_TEXTURE_2D, floorTexture);
        shader.setMat4("model", glm::mat4());
        glDrawArrays(GL_TRIANGLES, 0, 6);
        glBindVertexArray(0);

#if 1
    #if USE_SHARED_CONTEXT
        // use window context for presentation via blit.
        // -----
        glfwMakeContextCurrent(window);

        // temorary framebuffer for visible window since framebuffers are not shared
        // -------------------------
        unsigned int readFramebuffer;
        glGenFramebuffers(1, &readFramebuffer);
        glBindFramebuffer(GL_READ_FRAMEBUFFER, readFramebuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, Colorbuffer);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, SCR_WIDTH, SCR_HEIGHT);
        glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, Colorbuffer);
    #endif

        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
        glBlitFramebuffer(0, 0, SCR_WIDTH, SCR_HEIGHT, 0, 0, SCR_WIDTH, SCR_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST);

    #if USE_SHARED_CONTEXT
        glDeleteFramebuffers(1, &readFramebuffer);
    #endif
#else
        // now bind back to default framebuffer and draw a quad plane with the attached framebuffer color texture
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        glDisable(GL_DEPTH_TEST); // disable depth test so screen-space quad isn't discarded due to depth test.
        // clear all relevant buffers
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // set clear color to white (not really necessery actually, since we won't be able to see behind the quad anyways)
        glClear(GL_COLOR_BUFFER_BIT);

        screenShader.use();
        glBindVertexArray(quadVAO);
        glBindTexture(GL_TEXTURE_2D, textureColorbuffer);   // use the color attachment texture as the texture of the quad plane
        glDrawArrays(GL_TRIANGLES, 0, 6);
#endif

        // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
        // -------------------------------------------------------------------------------
        glfwSwapBuffers(window);
        glfwPollEvents();
    }
// <snip epilog>

Вы можете переключить переключатель времени компиляции USE_SHARED_CONTEXT, чтобы удалить небольшой фрагмент кода, который рендерится с использованием общего контекста.


person Andrew Ames    schedule 09.08.2017    source источник


Ответы (1)


Мне не хватало вызова glViewport для общего контекста рендеринга.

Значение Viewport по умолчанию было равно (0, 0) -> (ширина, высота) для контекста, используемого видимым окном. Общий контекст рендеринга по умолчанию был равен (0, 0) -> (1, 1), потому что я использовал ширину и высоту 1 для невидимого окна GLFW.

person Andrew Ames    schedule 09.08.2017