【问题标题】:How to use a renderbuffer and glBlit to render to four Windows, with GLFW如何使用渲染缓冲区和 glBlit 渲染到四个窗口,使用 GLFW
【发布时间】:2019-03-14 19:32:06
【问题描述】:

问题陈述

这应该是一个非常明显的答案,我可能在某处弄脏了一两行,但我似乎无法将三角形绘制到帧缓冲区。

我想要做的是将两个三角形连接到一个大型渲染缓冲区对象,并附加一个帧缓冲区,然后在四个窗口之一中使用 glBlitFramebuffer 显示更大的渲染缓冲区/帧缓冲区的一部分。

我使用init_FB() 来定义要渲染的三角形以及渲染这些三角形的RBO。我创建了一个渲染缓冲区对象和一个与渲染缓冲区对象关联的帧缓冲区对象。在compute_FB() 函数中,我绑定了RBO 的帧缓冲区,然后调用以绘制到该帧缓冲区中。在绘制三角形之前,我将帧缓冲区清除为特定颜色,royalblue


到底发生了什么

在名为window 的第一个窗口中,仅显示由绘制到渲染缓冲区对象的帧缓冲区的函数(compute_FB()) 定义的颜色royalblue。但是,即使我在compute_FB() 的末尾调用了一个glDrawArrays(...) 函数,也没有绘制任何三角形。

发生了什么的可能假设

我开始相信 RBO 需要自己的上下文才能成功渲染,但我不知道如何为 RBO 设置上下文。我认为上下文仅适用于 GLFW 中的窗口。


代码说明

我的尝试基于最初的 OpenGL 红皮书示例 01-三角形。在这个例子中,我编写了四个独特的窗口,并希望最终将一个大的 RBO/帧缓冲区复制到四个窗口中的每一个 - 目前我只关注第一个显示。

我正在使用带有 GLFW 的 OpenGL4.5 进行窗口化。


代码

//////////////////////////////////////////////////////////////////////////////
//
//  Triangles.cpp
//
//////////////////////////////////////////////////////////////////////////////

#include "vgl.h"
#include "LoadShaders.h"
#include <vector>

enum VAO_IDs { Triangles, NumVAOs };
enum Buffer_IDs { ArrayBuffer, NumBuffers };
enum Attrib_IDs { vPosition = 0 };

GLuint  VAOs[NumVAOs];
GLuint  Buffers[NumBuffers];

const GLuint  NumVertices = 6;

//////////////////////////////////////////////////
// Framebuffer Variables
//////////////////////////////////////////////////
enum {Color, NumRenderBuffers};
GLuint framebuffer, renderbuffer[NumRenderBuffers];
GLuint fbwidth = 3200;
GLuint fbheight = 600;


//----------------------------------------------------------------------------
//
// init
//
void init_FB( void )
{
    // Create an Empty RenderBuffer and Associated Framebuffer
    glCreateRenderbuffers(NumRenderBuffers, renderbuffer);
    glNamedRenderbufferStorage(renderbuffer[Color], GL_RGBA, fbwidth, fbheight);
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
    glNamedFramebufferRenderbuffer(framebuffer, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer[Color]);
    glEnable(GL_DEPTH_TEST);


    // Here's some info to initialize for the RBO
    // The framebuffer for the RBO has been bound (above) and ?SHOULD? be ready to draw to, right?
    glGenVertexArrays( NumVAOs, VAOs );
    glBindVertexArray( VAOs[Triangles] );

    GLfloat  vertices[NumVertices][2] = {
        { -1.00f, -1.00f }, { -1.00f,  0.40f }, {  0.00f, -1.00f },  // Triangle 1
        {  0.00f,  0.40f }, {  0.40f,  0.40f }, {  0.40f, -0.40f }   // Triangle 2
    };

    ShaderInfo  shaders[] =
        {
            { GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
            { GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
            { GL_NONE, NULL }
        };

    GLuint program = LoadShaders( shaders );
    glUseProgram( program );

    glVertexAttribPointer( vPosition, 2, GL_FLOAT,
                           GL_FALSE, 0, BUFFER_OFFSET(0) );
    glEnableVertexAttribArray( vPosition );
}


void init( void )
{
    // Create the standard window framebuffer for this window context
    // Basically, I want to give the window a framebuffer so that I can draw into it later in the 'draw' phase
    glCreateBuffers( NumBuffers, Buffers );
    glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );

    static const float black[] = { 1.0f, 0.5f, 0.2f, 0.0f };

    // May as well clear it to a color that's visually separate from the color that it will be cleared to
    //      .. in the draw phase.
    glClearBufferfv(GL_COLOR, 0, black);
}


void init2( void )
{
    glGenVertexArrays( NumVAOs, VAOs );
    glBindVertexArray( VAOs[Triangles] );

    GLfloat  vertices[NumVertices][2] = {
        { -0.90f, -0.60f }, { -0.85f, -0.60f }, { -0.50f, -0.65f },  // Triangle 1
        {  0.90f, -0.85f }, {  0.90f,  0.90f }, { -0.85f,  0.90f }   // Triangle 2
    };

    glCreateBuffers( NumBuffers, Buffers );
    glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );
    glBufferStorage( GL_ARRAY_BUFFER, sizeof(vertices), vertices, 0);

    ShaderInfo  shaders[] =
    {
        { GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
        { GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
        { GL_NONE, NULL }
    };

    GLuint program = LoadShaders( shaders );
    glUseProgram( program );

    glVertexAttribPointer( vPosition, 2, GL_FLOAT,
                           GL_FALSE, 0, BUFFER_OFFSET(0) );
    glEnableVertexAttribArray( vPosition );
}


void init3( void )
{
    glGenVertexArrays( NumVAOs, VAOs );
    glBindVertexArray( VAOs[Triangles] );

    GLfloat  vertices[NumVertices][2] = {
        { -0.90f, -0.90f }, { -0.90f,  0.90f }, {  0.00f, -0.90f },  // Triangle 1
        {  0.00f,  0.90f }, {  0.90f,  0.90f }, {  0.90f, -0.90f }   // Triangle 2
    };

    glCreateBuffers( NumBuffers, Buffers );
    glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );
    glBufferStorage( GL_ARRAY_BUFFER, sizeof(vertices), vertices, 0);

    ShaderInfo  shaders[] =
    {
        { GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
        { GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
        { GL_NONE, NULL }
    };

    GLuint program = LoadShaders( shaders );
    glUseProgram( program );

    glVertexAttribPointer( vPosition, 2, GL_FLOAT,
                           GL_FALSE, 0, BUFFER_OFFSET(0) );
    glEnableVertexAttribArray( vPosition );
}


void init4( void )
{
    glGenVertexArrays( NumVAOs, VAOs );
    glBindVertexArray( VAOs[Triangles] );

    GLfloat  vertices[NumVertices][2] = {
        { -0.40f, -0.40f }, { -0.40f,  0.40f }, {  0.00f, -0.40f },  // Triangle 1
        {  0.00f,  0.40f }, {  0.40f,  0.40f }, {  0.40f, -0.40f }   // Triangle 2
    };

    glCreateBuffers( NumBuffers, Buffers );
    glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );
    glBufferStorage( GL_ARRAY_BUFFER, sizeof(vertices), vertices, 0);

    ShaderInfo  shaders[] =
    {
        { GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
        { GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
        { GL_NONE, NULL }
    };

    GLuint program = LoadShaders( shaders );
    glUseProgram( program );

    glVertexAttribPointer( vPosition, 2, GL_FLOAT,
                           GL_FALSE, 0, BUFFER_OFFSET(0) );
    glEnableVertexAttribArray( vPosition );
}


//----------------------------------------------------------------------------
//
// display
//

void compute_FB()
{
    // Prepare to render into the framebuffer
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
    glViewport(0, 0, fbwidth, fbheight);

    // Clear before drawing. This shade of color comes through to the first window display
    static const float black[] = { 0.0f, 0.3f, 0.8f, 0.0f };

    glClearBufferfv(GL_COLOR, 0, black);

    // Try drawing the triangles... Nuthin
    glBindVertexArray( VAOs[Triangles] );
    glDrawArrays( GL_TRIANGLES, 0, NumVertices );
}

// Read from a section of the RBO/framebuffer
void display( void )
{
    static const float black[] = { 0.8f, 0.0f, 0.0f, 0.0f };

    glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer); // Set framebuffer to read from
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // set window to draw to
    glViewport(0, 0, 800, 600); // Probbaly not needed

    // Copy from READ framebuffer to DRAW framebuffer
    // QUESTION: Why isn't this copying to just a small corner of the window context's framebuffer?
    glBlitFramebuffer(0, 0, fbwidth, fbheight, 0, 0, 100, 200, GL_COLOR_BUFFER_BIT, GL_NEAREST);
}

void display2( void )
{
    static const float black[] = { 0.0f, 0.3f, 0.4f, 0.0f };

    glClearBufferfv(GL_COLOR, 0, black);

    glBindVertexArray( VAOs[Triangles] );
    glDrawArrays( GL_TRIANGLES, 0, NumVertices );
}

void display3( void )
{
    static const float black[] = { 0.7f, 0.6f, 0.4f, 0.0f };

    glClearBufferfv(GL_COLOR, 0, black);

    glBindVertexArray( VAOs[Triangles] );
    glDrawArrays( GL_TRIANGLES, 0, NumVertices );
}

void display4( void )
{
    static const float black[] = { 0.2f, 0.3f, 0.7f, 0.0f };

    glClearBufferfv(GL_COLOR, 0, black);

    glBindVertexArray( VAOs[Triangles] );
    glDrawArrays( GL_TRIANGLES, 0, NumVertices );
}


//----------------------------------------------------------------------------
//
// main
//

#ifdef _WIN32
int CALLBACK WinMain(
  _In_ HINSTANCE hInstance,
  _In_ HINSTANCE hPrevInstance,
  _In_ LPSTR     lpCmdLine,
  _In_ int       nCmdShow
)
#else
int
main( int argc, char** argv )
#endif
{
    // Initialize GLFW
    glfwInit();


    //TODO Create Windows Class
    // Create Windows
    GLFWwindow* window = glfwCreateWindow(800, 600, "Triangles", NULL, NULL);
    GLFWwindow* window2 = glfwCreateWindow(800, 600, "Triangles2", NULL, NULL);
    GLFWwindow* window3 = glfwCreateWindow(800, 600, "Triangles3", NULL, NULL);
    GLFWwindow* window4 = glfwCreateWindow(800, 600, "Triangles4", NULL, NULL);



    // Initialize OpenGL
    gl3wInit();


    // Framebuffer Initialization
    init_FB();


    // Initialize Windows
    glfwMakeContextCurrent(window);
    init();
    glfwMakeContextCurrent(window2);
    init2();
    glfwMakeContextCurrent(window3);
    init3();
    glfwMakeContextCurrent(window4);
    init4();


    // Draw the Windows
    while (!glfwWindowShouldClose(window) && !glfwWindowShouldClose(window2) && !glfwWindowShouldClose(window3) && !glfwWindowShouldClose(window4))
    {
        glfwMakeContextCurrent(window);
        compute_FB();
        display();
        glfwSwapBuffers(window);
        glfwPollEvents();

        glfwMakeContextCurrent(window2);
        display2();
        glfwSwapBuffers(window2);
        glfwPollEvents();

        glfwMakeContextCurrent(window3);
        display3();
        glfwSwapBuffers(window3);
        glfwPollEvents();

        glfwMakeContextCurrent(window4);
        display4();
        glfwSwapBuffers(window4);
        glfwPollEvents();
    }


    // Destroy Windows
    glfwDestroyWindow(window);
    glfwDestroyWindow(window2);
    glfwDestroyWindow(window3);
    glfwDestroyWindow(window4);


    // Terminate GLFW Instance
    glfwTerminate();
}


编辑#2

感谢@Ripi2,我现在可以使用 glBlit 和渲染缓冲区。不知何故,尽管我没有正确使用第二个窗口的渲染缓冲区和不同的 FBO 中的一个或两个。 注意此时,我还没有在第三个或第四个窗口上实现 glBlit(虽然我会,一旦我可以成功地将渲染缓冲区和 glBlit 集成到第二个窗口中)

编辑 #2 代码

//////////////////////////////////////////////////////////////////////////////
//
//  Triangles.cpp
//
//////////////////////////////////////////////////////////////////////////////
#include <cstdio>
#include "vgl.h"
#include "LoadShaders.h"

enum VAO_IDs { Triangles, NumVAOs };
enum Buffer_IDs { ArrayBuffer, NumBuffers };
enum Attrib_IDs { vPosition = 0 };

GLuint  VAOs[NumVAOs];
GLuint  Buffers[NumBuffers];

const GLuint  NumVertices = 6;
////////////////////////////////////
//RBO variables
enum {Color=0, NumRenderBuffers=1, NumFBOs=4};
GLuint renderbuffer[NumRenderBuffers], fbos[NumFBOs];
GLuint buffwidth = 3200;
GLuint buffheight = 600;


//----------------------------------------------------------------------------
//
// init
//

void
init( void )
{
    glCreateRenderbuffers(NumRenderBuffers, renderbuffer);
    glNamedRenderbufferStorage(renderbuffer[Color], GL_RGBA, buffwidth, buffheight);
    glGenFramebuffers(1, &fbos[0]);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[0]);
    glNamedFramebufferRenderbuffer(fbos[0], GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer[Color]);

    glGenVertexArrays( NumVAOs, VAOs );
    glBindVertexArray( VAOs[Triangles] );

    GLfloat  vertices[NumVertices][2] = {
        { -0.90f, -0.90f }, { -0.90f,  0.90f }, {  0.00f, -0.90f },  // Triangle 1
        {  0.00f,  0.90f }, {  0.90f,  0.90f }, {  0.90f, -0.90f }   // Triangle 2
    };

    glCreateBuffers( NumBuffers, Buffers );
    glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );
    glBufferStorage( GL_ARRAY_BUFFER, sizeof(vertices), vertices, 0);

    ShaderInfo  shaders[] =
    {
        { GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
        { GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
        { GL_NONE, NULL }
    };

    GLuint program = LoadShaders( shaders );
    glUseProgram( program );

    glVertexAttribPointer( vPosition, 2, GL_FLOAT,
                           GL_FALSE, 0, BUFFER_OFFSET(0) );
    glEnableVertexAttribArray( vPosition );
}


void
init2( void )
{
    glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer[Color]);
    glGenFramebuffers(1, &fbos[1]);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
    glNamedFramebufferRenderbuffer(fbos[1], GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, renderbuffer[Color]);

}


void
init3( void )
{
    glGenVertexArrays( NumVAOs, VAOs );
    glBindVertexArray( VAOs[Triangles] );

    GLfloat  vertices[NumVertices][2] = {
        { -0.90f, -0.90f }, { -0.90f,  0.90f }, {  0.00f, -0.90f },  // Triangle 1
        {  0.00f,  0.90f }, {  0.90f,  0.90f }, {  0.90f, -0.90f }   // Triangle 2
    };

    glCreateBuffers( NumBuffers, Buffers );
    glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );
    glBufferStorage( GL_ARRAY_BUFFER, sizeof(vertices), vertices, 0);

    ShaderInfo  shaders[] =
    {
        { GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
        { GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
        { GL_NONE, NULL }
    };

    GLuint program = LoadShaders( shaders );
    glUseProgram( program );

    glVertexAttribPointer( vPosition, 2, GL_FLOAT,
                           GL_FALSE, 0, BUFFER_OFFSET(0) );
    glEnableVertexAttribArray( vPosition );
}


void
init4( void )
{
    glGenVertexArrays( NumVAOs, VAOs );
    glBindVertexArray( VAOs[Triangles] );

    GLfloat  vertices[NumVertices][2] = {
        { -0.40f, -0.40f }, { -0.40f,  0.40f }, {  0.00f, -0.40f },  // Triangle 1
        {  0.00f,  0.40f }, {  0.40f,  0.40f }, {  0.40f, -0.40f }   // Triangle 2
    };

    glCreateBuffers( NumBuffers, Buffers );
    glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );
    glBufferStorage( GL_ARRAY_BUFFER, sizeof(vertices), vertices, 0);

    ShaderInfo  shaders[] =
    {
        { GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
        { GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
        { GL_NONE, NULL }
    };

    GLuint program = LoadShaders( shaders );
    glUseProgram( program );

    glVertexAttribPointer( vPosition, 2, GL_FLOAT,
                           GL_FALSE, 0, BUFFER_OFFSET(0) );
    glEnableVertexAttribArray( vPosition );
}


//----------------------------------------------------------------------------
//
// display
//

void
display( void )
{
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[0]);
    glViewport(0, 0, buffwidth, buffheight);
    static const float black[] = { 0.2f, 0.2f, 0.2f, 0.0f };
    static const float redish[] = { 0.6f, 0.4f, 0.3f, 0.0f };
    glClearBufferfv(GL_COLOR, 0, black);

    glBindVertexArray( VAOs[Triangles] );
    glDrawArrays( GL_TRIANGLES, 0, NumVertices );


    glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    glViewport(0, 0, 800, 600);
    glClearBufferfv(GL_COLOR, 0, redish);

    glBlitFramebuffer(0, 0, 800, 600, 0, 0, 800, 600, GL_COLOR_BUFFER_BIT, GL_NEAREST);

}

void
display2( void )
{
    glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[1]);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    glViewport(0, 0, 800, 600);
    static const float redish[] = { 0.6f, 0.4f, 0.3f, 0.0f };
    glClearBufferfv(GL_COLOR, 0, redish);

    glBlitFramebuffer(buffwidth, 0, buffwidth+800, 600, 0, 0, 800, 600, GL_COLOR_BUFFER_BIT, GL_NEAREST);
}

void
display3( void )
{
    static const float black[] = { 0.7f, 0.6f, 0.4f, 0.0f };

    glClearBufferfv(GL_COLOR, 0, black);

    glBindVertexArray( VAOs[Triangles] );
    glDrawArrays( GL_TRIANGLES, 0, NumVertices );
}

void
display4( void )
{
    static const float black[] = { 0.2f, 0.3f, 0.7f, 0.0f };

    glClearBufferfv(GL_COLOR, 0, black);

    glBindVertexArray( VAOs[Triangles] );
    glDrawArrays( GL_TRIANGLES, 0, NumVertices );
}


//----------------------------------------------------------------------------
//
// main
//

#ifdef _WIN32
int CALLBACK WinMain(
  _In_ HINSTANCE hInstance,
  _In_ HINSTANCE hPrevInstance,
  _In_ LPSTR     lpCmdLine,
  _In_ int       nCmdShow
)
#else
int
main( int argc, char** argv )
#endif
{
    // Initialize GLFW
    glfwInit();
    // Initialize OpenGL
    // Place it here before any OpenGL objects are needed, other OpenGL crashes
    //      ... in a "Segmentation fault (core dumped)" error
    gl3wInit();


    //TODO Create Windows Class
    // Create Windows
    GLFWwindow* window = glfwCreateWindow(800, 600, "Triangles", NULL, NULL);
    GLFWwindow* window2 = glfwCreateWindow(800, 600, "Triangles2", NULL, window);
    GLFWwindow* window3 = glfwCreateWindow(800, 600, "Triangles3", NULL, window);
    GLFWwindow* window4 = glfwCreateWindow(800, 600, "Triangles4", NULL, window);

    // Initialize Windows
    glfwMakeContextCurrent(window);
    init();
    glfwMakeContextCurrent(window2);
    init2();
    glfwMakeContextCurrent(window3);
    init3();
    glfwMakeContextCurrent(window4);
    init4();


    // Draw the Windows
    while (!glfwWindowShouldClose(window) && !glfwWindowShouldClose(window2) && !glfwWindowShouldClose(window3) && !glfwWindowShouldClose(window4))
    {
        glfwMakeContextCurrent(window);
        display();
        glfwSwapBuffers(window);
        glfwPollEvents();

        glfwMakeContextCurrent(window2);
        display2();
        glfwSwapBuffers(window2);
        glfwPollEvents();

        glfwMakeContextCurrent(window3);
        display3();
        glfwSwapBuffers(window3);
        glfwPollEvents();

        glfwMakeContextCurrent(window4);
        display4();
        glfwSwapBuffers(window4);
        glfwPollEvents();
    }


    // Destroy Windows
    glfwDestroyWindow(window);
    glfwDestroyWindow(window2);
    glfwDestroyWindow(window3);
    glfwDestroyWindow(window4);


    // Terminate GLFW Instance
    glfwTerminate();
}

【问题讨论】:

  • 您可以将三角形渲染到默认帧缓冲区吗?你确定蓝色是来自 blit 而不是以前的清除?

标签: c++ opengl rendering glfw framebuffer


【解决方案1】:

终于找到了解决办法。

备注

  • 我要感谢Ripi2 在文档和代码初步审查方面的推动。非常感谢您的帮助和指导。
  • 此答案中发布的代码并不复杂,也不打算如此,因此这显然不是生产质量代码。我在这里概述的内容应该易于任何人阅读 - 无论是初学者还是高级
  • 作为经验不足的 OpenGL 程序员,可能会做出一些不是最佳或最佳实践的风格选择。我将更新此答案,以反映对此代码的任何可行改进,这些改进仍然为新概念的新手保持易读性。
  • 我想采用的更复杂的窗口系统类似于this. 这里的开发人员创建了一个非常强大的窗口系统。如果我要做出改变,那就是创建一个窗口类。但是......这是一个学术讨论,与手头的答案高度相切。

解决方案是什么?

  1. 正在接近上下文共享。再次感谢Ripi2 。最初,我打算在一个单独的上下文中渲染一个大的帧缓冲区,如在第五个窗口,不可见窗口中,然后对每个活动窗口执行glBlit 复制。这可能行得通,但在指导下,我被说服在主窗口中执行实际渲染,然后复制到最后三个窗口中。这更快,因为操作更少
  2. 实际上打开了与 GLFW 的上下文共享。每个glfwCreateWindow(); 命令的末尾都有一个参数,用于从另一个窗口传递上下文。由于我在第一个窗口的初始 init() 中创建渲染缓冲区,因此我必须为所有其他三个窗口的最终参数设置 window,如下所示:GLFWwindow *window2 = glfwCreateWindow(width, height, title, NULL, window-whose-context-i-want-to-share);
  3. 对我来说,困难的部分是确切地知道如何理解渲染缓冲区对象可以共享的想法,它的数据也可以共享,但是您只能通过无法访问的项目来访问它 跨上下文共享。这导致了为所有窗口设置一个渲染缓冲区,为每个窗口设置一个帧缓冲区的想法。事实证明,实际实现这一点比预期的要简单——但那是经过数小时的阅读和研究。希望这个答案能帮助您直接跳到问题的核心。
  4. 每次调用 init 函数之一都会创建一个帧缓冲区并将渲染缓冲区绑定到当前上下文。
  5. 您必须将渲染缓冲区重新绑定到当前上下文,即使它是共享资源。不这样做将不会从第一个 display() 函数加载渲染数据。换句话说,虽然渲染的数据仍然存在,但在您将其绑定到当前上下文之前,您将无法访问它......每次您更改为渲染到新窗口时。
  6. 我必须弄清楚的真正重要部分是确保我设置了正确的 renderbuffer-target。在这种情况下,您将在init2(const int) 中注意到将当前上下文的帧缓冲区绑定到共享渲染缓冲区glNamedFramebufferRenderbuffer(...) 的命令必须与原始 具有相同的 renderbuffer-target >renderbuffer-target 定义在init():GL_COLOR_ATTACHMENT0。事后看来,这应该是显而易见的,但是很难找到从渲染缓冲区对象进行多窗口渲染的文档数量。几乎所有其他人都使用 glTexture 对象而不是渲染缓冲区进行了演示。这个GL_COLOR_ATTACHMENTi 就像一个内部地址,可以存储多组渲染数据……对未来的项目来说是一个很好的提示。
  7. display2(const int) 函数中为每个上下文绑定帧缓冲区时,此处设置的重要一点是帧缓冲区只会从渲染缓冲区读取,因此请使用GL_READ_FRAMEBUFFER - 因为数据已经存在,我们只是使用帧缓冲区对象来访问渲染缓冲区中的数据。 FBO 是管道,而不是存储。实际上,如果不先附加 FBO,就无法访​​问渲染缓冲区中的数据。
  8. 调试 - 我开始使用各种版本的glGet 函数系列,以获取有关不同上下文中的渲染缓冲区以及帧缓冲区的信息。当结果符合我的预期时,我知道我走在了正确的轨道上。您将在display2(const int) 中看到我在其中留下了两行以获得渲染缓冲区参数:宽度。我把它留在了这个代码 sn-p 中,供任何可能对它如何工作感兴趣的人使用。 警告display 函数打印对于基本调试以外的任何事情都是一个坏主意,因为它会在每个周期写入一次控制台 - 写入标准输出非常慢。

代码

//////////////////////////////////////////////////////////////////////////////
//
//  Triangles.cpp
//
//////////////////////////////////////////////////////////////////////////////
#include <cstdio>
#include "vgl.h"
#include "LoadShaders.h"

enum VAO_IDs { Triangles, NumVAOs };
enum Buffer_IDs { ArrayBuffer, NumBuffers };
enum Attrib_IDs { vPosition = 0 };

GLuint  VAOs[NumVAOs];
GLuint  Buffers[NumBuffers];

const GLuint  NumVertices = 6;
////////////////////////////////////
//RBO variables
enum {Color=0, NumRenderBuffers=1, NumFBOs=4};
GLuint renderbuffer[NumRenderBuffers], fbos[NumFBOs];
GLuint buffwidth = 3200;
GLuint buffheight = 600;



//----------------------------------------------------------------------------
//
// init
//

void
init( void )
{
    glCreateRenderbuffers(NumRenderBuffers, renderbuffer);
    glNamedRenderbufferStorage(renderbuffer[Color], GL_RGBA, buffwidth, buffheight);
    glGenFramebuffers(1, &fbos[0]);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[0]);
    glNamedFramebufferRenderbuffer(fbos[0], GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer[Color]);
    printf("\"init()\", is RB valid: %i\n", glIsRenderbuffer(renderbuffer[Color]));
    printf("\"init()\", is FBO valid: %i\n", glCheckNamedFramebufferStatus(fbos[0], GL_DRAW_FRAMEBUFFER));

    glGenVertexArrays( NumVAOs, VAOs );
    glBindVertexArray( VAOs[Triangles] );

    GLfloat  vertices[NumVertices][2] = {
        { -0.90f, -0.90f }, { -0.90f,  0.90f }, {  0.00f, -0.90f },  // Triangle 1
        {  0.00f,  0.90f }, {  0.90f,  0.90f }, {  0.90f, -0.90f }   // Triangle 2
    };

    glCreateBuffers( NumBuffers, Buffers );
    glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );
    glBufferStorage( GL_ARRAY_BUFFER, sizeof(vertices), vertices, 0);

    ShaderInfo  shaders[] =
    {
        { GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
        { GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
        { GL_NONE, NULL }
    };

    GLuint program = LoadShaders( shaders );
    glUseProgram( program );

    glVertexAttribPointer( vPosition, 2, GL_FLOAT,
                           GL_FALSE, 0, BUFFER_OFFSET(0) );
    glEnableVertexAttribArray( vPosition );
}

void
init2( const int idx_in )
{
    glGenFramebuffers(1, &fbos[idx_in]);
    glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[idx_in]);
    glEnable(GL_RENDERBUFFER);
    glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer[Color]);
    GLint tmpwidth = 0;
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &tmpwidth);

    glNamedFramebufferRenderbuffer(fbos[idx_in], GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer[Color]);
    printf("\"init2()\", RB width is: %i\n", tmpwidth);
    printf("\"init2()\", is RB valid: %i\n", glIsRenderbuffer(renderbuffer[Color]));
    printf("\"init2()\", is FBO valid: %i\n", glCheckNamedFramebufferStatus(fbos[idx_in], GL_DRAW_FRAMEBUFFER));

}

//----------------------------------------------------------------------------
//
// display
//

void
display( void )
{
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[0]);
    glViewport(0, 0, buffwidth, buffheight);
    static const float black[] = { 0.2f, 0.2f, 0.2f, 0.0f };
    static const float redish[] = { 0.6f, 0.4f, 0.3f, 0.0f };
    glClearBufferfv(GL_COLOR, 0, black);

    glBindVertexArray( VAOs[Triangles] );
    glDrawArrays( GL_TRIANGLES, 0, NumVertices );


    glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    glViewport(0, 0, 800, 600);
    glClearBufferfv(GL_COLOR, 0, redish);

    glBlitFramebuffer(0, 0, 800, 600, 0, 0, 800, 600, GL_COLOR_BUFFER_BIT, GL_NEAREST);

}

void
display2( const int idx_in )
{
    glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[idx_in]);

    GLint tmpwidth = 0;
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &tmpwidth);

    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    glViewport(0, 0, 800, 600);


    glBlitFramebuffer(800 * idx_in - 1, 0, 800 * idx_in - 1 + 800, 600, 0, 0, 800, 600, GL_COLOR_BUFFER_BIT, GL_NEAREST);
}


//----------------------------------------------------------------------------
//
// main
//

#ifdef _WIN32
int CALLBACK WinMain(
  _In_ HINSTANCE hInstance,
  _In_ HINSTANCE hPrevInstance,
  _In_ LPSTR     lpCmdLine,
  _In_ int       nCmdShow
)
#else
int
main( int argc, char** argv )
#endif
{
    // Initialize GLFW
    glfwInit();

    //TODO Create Windows Class
    // Create Window Hints
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
    // Create Windows
    GLFWwindow* window = glfwCreateWindow(800, 600, "Triangles", NULL, NULL);
    GLFWwindow* window2 = glfwCreateWindow(800, 600, "Triangles2", NULL, window);
    GLFWwindow* window3 = glfwCreateWindow(800, 600, "Triangles3", NULL, window);
    GLFWwindow* window4 = glfwCreateWindow(800, 600, "Triangles4", NULL, window);

    // Set window positions
    glfwSetWindowPos(window,  100, 100);
    glfwSetWindowPos(window2, 900, 100);
    glfwSetWindowPos(window3, 1700, 100);
    glfwSetWindowPos(window4, 2500, 100);

    // Initialize Windows
    glfwMakeContextCurrent(window);
    // Initialize gl3w - thanks @Ripi2 for the assist
    gl3wInit();
    init();
    glfwMakeContextCurrent(window2);
    init2(1);
    glfwMakeContextCurrent(window3);
    init2(2);
    glfwMakeContextCurrent(window4);
    init2(3);


    // Draw the Windows
    while (!glfwWindowShouldClose(window) && !glfwWindowShouldClose(window2) && !glfwWindowShouldClose(window3) && !glfwWindowShouldClose(window4))
    {
        glfwMakeContextCurrent(window);
        display();
        glfwSwapBuffers(window);
        glfwPollEvents();
        glFinish();

        glfwMakeContextCurrent(window2);
        display2(1);
        glfwSwapBuffers(window2);
        glfwPollEvents();
        glFinish();

        glfwMakeContextCurrent(window3);
        display2(2);
        glfwSwapBuffers(window3);
        glfwPollEvents();

        glfwMakeContextCurrent(window4);
        display2(3);
        glfwSwapBuffers(window4);
        glfwPollEvents();
    }


    // Destroy Windows
    glfwDestroyWindow(window);
    glfwDestroyWindow(window2);
    glfwDestroyWindow(window3);
    glfwDestroyWindow(window4);


    // Terminate GLFW Instance
    glfwTerminate();
}

最终渲染

【讨论】:

    【解决方案2】:

    我看到的一些问题:

    您正在创建四个不同的 gl 上下文,每个窗口一个。您想将在 window_1 中呈现的帧缓冲区用于其他窗口。为此,您需要两件事:
    1) 使用共享上下文,可以在glfwCreateWindow 调用中创建。
    2) 共享 renderbuffer RB,而不是 FBO(FBO 和 VAO 一样,不能共享)。这意味着您需要为每个窗口使用不同的 FBO,并将相同的 RB 附加到每个 FBO。

    在从缓冲区 (VBO) 中绘制之前,它必须通过 glVertexAttribPointer 在 VAO 中“关联”。换句话说,每个窗口都需要自己的 VAO。
    您不是在请求 Core Profile 上下文。这是通过glfwWindowHintcontext hints before glfwCreateWindow 实现的。不这样做可能会起作用,因为某些驱动程序会提供兼容性配置文件;但可能不是,所以最好使用 Core Profile。核心配置文件需要 VAO。

    gl3wInit() 应该在某些 gl-context 设置为当前后调用。我不知道 glfw 是否会以某种方式使当前某些上下文成为当前的上下文,因此您不会收到错误。

    您的 枚举NumVAOs = 1NumBuffers = 1。因此,glGenVertexArrays 和其他 glGenXXX 调用将覆盖最后的值。这会弄乱绘图。

    init() 创建一个 VBO,但不要设置它的大小。所以,glClearBufferfv 不知道必须“清除”多少字节。

    【讨论】:

    • 谢谢!这是一些很棒的反馈。我会研究您的笔记和链接,并根据需要进行更改。
    • 如何创建渲染到 RB 的上下文?我是否应该在 glfw 中创建第五个窗口,使其不可见,在其中创建 RB?然后,将该窗口作为第四个参数共享给其他每个可见窗口?然后,为每个可见窗口创建一个framebuffer,一旦进入每个窗口的draw,执行从RB到本地感知framebuffer的glBlit操作?请致电init()。那是准备绘制三角形。关于通过 glGenxxx 调用覆盖值,每个窗口都可以绘制自己的三角形,这些三角形将移动到单个 RB。
    • @Andrew 不需要第 5 个窗口。创建第一个,将此窗口传递给其他创建调用。在任何地方渲染到 FBO。对于其他每个窗口,创建一个新的 FBO,附加 RB,并从此 FBO 进行 blit。如果每个窗口呈现不同的三角形,那么您不仅需要不同的 VAO,还需要更好的不同 VBO。一次又一次地创造是浪费时间。
    • 所以我已经更新了代码和问题,但是 - 没有 bueno - 第二个窗口。因此,我一直在查看 GLFW 共享示例并查看函数gladLoadGLLoader((GLADloadproc) glfwGetProcAddress),尽管我找不到关于其总体目的的好的文档。它似乎是一种复制当前状态共享信息的方法,或者通过函数或对象的寻址使其可用。想法?不管怎样,我会继续研究。提前致谢。
    • 这是我正在使用的共享示例:github.com/glfw/glfw/blob/master/examples/sharing.c
    【解决方案3】:

    您的初始化函数正在尝试在上下文之间共享状态。 GL 的上下文是所有 GL 状态的实例,上下文仅在 instructed to do so explicitly when initialized 时共享数据。我建议只使用一个窗口,并使用 glviewport 对其进行分区。

    也许你也犯了一个错误,没有让你的对象成为数组数组,因为每个 glgen 都会覆盖它们。这不是 GL 的错误,而是 C 数组语法的错误。

    【讨论】:

    • 我不想要一个窗口。我的问题仅与第一个窗口中发生的事情有关。请重新格式化您的答案以解决手头的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-18
    • 1970-01-01
    相关资源
    最近更新 更多