Как использовать renderbuffer и glBlit для рендеринга до четырех окон с помощью GLFW - PullRequest
0 голосов
/ 10 октября 2018

Постановка задачи

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

Я пытаюсь получить два треугольника для большого объекта буфера рендеринга с прикрепленным кадровым буфером, а затем в одном из четырех окон отобразить фрагмент большего буфера / кадрового буфера рендеринга, используя glBlitFramebuffer.

Я использую init_FB() для определения треугольников для рендеринга и RBO для рендеринга этих треугольников.Я создал объект renderbuffer и объект framebuffer, связанный с объектом renderbuffer.В функции compute_FB() я связываю кадровый буфер RBO, а затем выполняю вызов для рисования в этом кадровом буфере.Прежде чем нарисовать треугольники, я очищаю кадровый буфер до определенного цвета, royalblue.


Что происходит

В первом окне, которое называется window, отображается следующее:только цвет royalblue, определенный функцией (compute_FB()), который рисует в кадровом буфере объекта renderbuffer.Однако ни один из треугольников не рисуется, хотя у меня есть функция glDrawArrays(...), вызываемая в конце compute_FB().

Возможная гипотеза о том, что происходит

Я начинаю верить, что RBO нужен свой собственный контекст для успешного рендеринга, но я не знаю, как настроить контекст дляБВУ.Я думал, что контексты были только для окон в GLFW.


Объяснение кода

Я основываю свою попытку на первоначальном примере OpenGL Redbook 01-треугольники.В этом примере я закодировал четыре уникальных окна и хочу со временем скопировать большой RBO / кадровый буфер в каждое из четырех окон - в настоящее время я просто фокусируюсь на первом дисплее.

Я использую OpenGL4.5 с GLFW для управления окнами.


КОД

//////////////////////////////////////////////////////////////////////////////
//
//  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 и renderbuffer.Как-то, хотя я не правильно использую один или оба из renderbuffer и другой FBO для второго окна. NOTE На данный момент я еще не реализую glBlit в третьем или четвертом окне (хотя я сделаю это, как только смогу успешно интегрировать renderbuffer и 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();
}

Ответы [ 3 ]

0 голосов
/ 11 октября 2018

Некоторые проблемы, которые я вижу:

Вы создаете четыре различных gl-контекста, по одному для каждого окна.Вы хотите использовать кадровый буфер, отображаемый в window_1 для других окон.Для этого вам понадобятся две вещи:
1) Используйте общие контексты, которые можно создать при вызове glfwCreateWindow .
2) Совместно использовать рендер-буфер RB , а не FBO (FBO, как и VAO, не могут быть общими).Это означает, что вам нужны разные FBO для каждого окна и присоединять один и тот же RB к каждому FBO.

Перед рисованием из буфера (VBO) он должен быть «связан» в VAO через glVertexAttribPointer.Другими словами, каждому окну нужен собственный VAO.
Вы не запрашиваете Базовый профиль контекст.Это достигается с помощью glfwWindowHint с контекстными подсказками до glfwCreateWindow.Несоблюдение этого требования может сработать, поскольку некоторые драйверы предоставляют профиль совместимости ;но может и не быть, поэтому лучше использовать Core Profile.VAOs требуется для основного профиля.

gl3wInit() следует вызывать после того, как некоторый gl-context установлен в качестве текущего.Я не знаю, если glfw каким-то образом создает текущий контекст, так что вы не получите ошибку.

Ваш enum s делает NumVAOs = 1 и NumBuffers = 1.Таким образом, glGenVertexArrays и другие вызовы glGenXXX перезаписывают последние значения.Это испортит рисунок.

На init() вы создаете VBO, но не устанавливаете его размер.Итак, glClearBufferfv не знает, сколько байтов должно быть "очищено".

0 голосов
/ 17 октября 2018

Наконец-то нашли решение.

Примечания

  • Я хочу поблагодарить 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. сложная часть,для меня было точно знать, как ориентироваться в идее, что объект renderbuffer может совместно использоваться, и его данные тоже могут, но вы можете получить доступ к нему только через элемент, который не может совместно использоваться в разных контекстах.,Это приводит к идее иметь один рендер-буфер для всех окон и один фрейм-буфер для каждого окна.Оказывается, что на самом деле реализовать это было проще, чем ожидалось - но это было после часов чтения и исследований.Надеемся, что этот ответ поможет вам перейти к сути вопроса.
  4. Каждый вызов одной из init функций создает кадровый буфер и связывает буфер визуализации с текущим контекстом.
  5. Youпридется привязать рендер-буфер к текущему контексту, даже если это общий ресурс.Без этого загруженные данные не будут загружены из первой функции display().Другими словами, в то время как визуализированные данные все еще будут существовать, у вас не будет доступа к ним, пока вы не свяжете их с текущим контекстом ... каждый раз, когда вы переключаетесь на рендеринг в новом окне.
  6. * ДЕЙСТВИТЕЛЬНО важная часть, которую я только что должен был выяснить, это обеспечение правильной установки renderbuffer-target .В этом случае, что вы заметите в init2(const int), это команда, которая связывает кадровый буфер текущего контекста с общим renderbuffer, glNamedFramebufferRenderbuffer(...), должен иметь тот же renderbuffer-target , что и исходный renderbuffer-target , определенный в init(): GL_COLOR_ATTACHMENT0.Оглядываясь назад, это должно было быть очевидно, но объем документации для многооконного рендеринга из объекта renderbuffer было трудно найти.Почти все остальные провели демонстрации с использованием объектов glTexture вместо рендеринга буфера.Этот GL_COLOR_ATTACHMENTi подобен внутреннему адресу, где могут храниться несколько наборов визуализированных данных ... очень хороший совет для будущих проектов.
  7. При связывании кадрового буфера для каждого контекста в функции display2(const int) важно установить здесь, что кадровый буфер только собирался READ из renderbuffer, поэтому используйте GL_READ_FRAMEBUFFER - потому чтоданные уже есть, и мы просто используем объект framebuffer как способ получить доступ к данным внутри renderbuffer.FBO - это канал, а не хранилище.Действительно, нет способа получить доступ к данным внутри рендеринга без предварительного подключения FBO.
  8. Отладка - я начал использовать различные версии семейства функций glGet для получения информациио рендер-буфере в разных контекстах, а также фрейм-буфере.Когда результаты этих соревнований совпали с моими ожиданиями, я понял, что на правильном пути.В display2(const int) вы увидите, что я оставил две строки для получения параметра renderbuffer: ширина.Я оставил его в этом фрагменте кода для всех, кому может быть интересно, как это будет работать. ПРЕДУПРЕЖДЕНИЕ Печать из функции display - плохая идея для чего-либо, кроме элементарной отладки, потому что она будет писать консоль один раз за цикл - а запись в stdout смехотворно медленная.

Код

//////////////////////////////////////////////////////////////////////////////
//
//  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();
}

Окончательный рендер

enter image description here

0 голосов
/ 11 октября 2018

Ваши функции инициализации пытаются разделить состояние между контекстами.Контекст GL является экземпляром всех состояний GL, контексты обмениваются данными только в том случае, если указано сделать это явно при инициализации .Я бы порекомендовал использовать только одно окно и glviewport для его разбиения.

Возможно, вы также допустили ошибку, не сделав ваши объекты массивом массивов, поскольку каждый glgen перезаписывает их.Это не ошибка GL, а синтаксиса массива C.

...