OpenGL Tutorial (Version 3.3) – Post Processing, Multiple Render Targets (Download)

In den bisherigen Programmbeispielen haben wir einem Framebuffer-Objekt (FBO) stets nur eine Textur als Render Target zugewiesen. Sollte nun die sichtbare Szene in eine Textur und das zugehörige Tiefenabbild in eine zweite Textur rendern werden, waren dafür stets zwei komplette Renderdurchgänge notwendig. Selbstredend ist dies eine unnötige Verschwendung von GPU-Rechenleistung, denn man kann einem FBO auch mehrere Texturen als Render Targets zuweisen:




// die sichtbare Szene wird in die PrimaryScreenTexture gerendert:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,
                       PrimaryScreenTexture->TextureID, 0);

// das zugehörige Tiefenabbild wird in die PrimaryCameraDepthTexture
// gerendert:

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,GL_TEXTURE_2D,
                       PrimaryCameraDepthTexture->TextureID, 0);


Hinweis: Die Anzahl der Texturen, die maximal an ein FBO gebunden werden können, lässt sich wie folgt bestimmen:

GLuint maxbuffers;
glGetIntergeri(GL_MAX_COLOR_ATTACHMENTS, &maxbuffers);

Bevor wir mit dem Rendern eines neuen Frames (Szenenbild) beginnen können, müssen wir das vorangegangene Frame zunächst aus den einzelnen Render Targets löschen:

das eigentliche Szenenbild:


// Framebuffer vor der Benutzung binden:
glBindFramebuffer(GL_FRAMEBUFFER, PrimaryScreenFrameBuffer);

glViewport(0, 0, g_screenwidth, g_screenheight);

// Render Target (PrimaryScreenTexture) auswählen:
glDrawBuffer(GL_COLOR_ATTACHMENT0);

glClearColor(pBackgroundColor->x, pBackgroundColor->y, pBackgroundColor->z,
             pBackgroundColor->w);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Framebuffer nach der Benutzung wieder abkoppeln:
glBindFramebuffer(GL_FRAMEBUFFER, 0);



das zum Szenenbild zugehörige Tiefenabbild:



// Framebuffer vor der Benutzung binden:
glBindFramebuffer(GL_FRAMEBUFFER, PrimaryScreenFrameBuffer);

glViewport(0, 0, g_screenwidth, g_screenheight);

// Render Target (PrimaryCameraDepthTexture) auswählen:
glDrawBuffer(GL_COLOR_ATTACHMENT1);

glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Framebuffer nach der Benutzung wieder abkoppeln:
glBindFramebuffer(GL_FRAMEBUFFER, 0);


Nachdem die Render Targets für die Aufnahme des neuen Szenenbilds vorbereitet sind, können wir auswählen, welche der Targets im Verlauf des aktuellen Render-Durchgangs wann verwendet werden sollen. Beispielsweise setzen wir für die Hintergrunddarstellung sceneColorOnly auf true, denn natürlich benötigen wir keinen Tiefenabbild des Hintergrundes.

// Framebuffer vor der Benutzung binden:
glBindFramebuffer(GL_FRAMEBUFFER, PrimaryScreenFrameBuffer);

if(sceneColorOnly == true)
{
    // Render Target (PrimaryScreenTexture) auswählen:
    glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
    glViewport(0, 0, g_screenwidth, g_screenheight);
}
else
{
    // mehrere Render Targets (PrimaryScreenTexture,
    // PrimaryCameraDepthTexture) auswählen:
    GLenum buffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
    glDrawBuffers(2, buffers);

    glViewport(0, 0, g_screenwidth, g_screenheight);
}


Soll nun ein Fragment Shader in mehrere Render Targets schreiben können, benötigen wir zunächst eine entsprechende Anzahl von Output-Variablen (gs_FragColor[2]). In unserem Beispiel schreibt gs_FragColor[0] in die PrimaryScreenTexture, da wir in buffers[] GL_COLOR_ATTACHMENT0 als ersten Render Buffer festgelegt haben. Dementsprechend schreibt gs_FragColor[1] in die PrimaryCameraDepthTexture, da wir in buffers[] GL_COLOR_ATTACHMENT1 als zweiten Render Buffer festgelegt haben.

// Output Variablen:
out vec4 gs_FragColor[2];

void main()
{
    // GL_COLOR_ATTACHMENT0:
    gs_FragColor[0] = vec4(0.0, 1.0, 0.0, 1.0);

    // GL_COLOR_ATTACHMENT1:
    gs_FragColor[1] = vec4(0.0, 0.0, 1.0, 1.0);
}

Hinweis:
Für die Ausführung dieses Programmbeispiels muss der Treiber Ihrer Grafikkarte die OpenGL Version 3.3 unterstützen.

Visual C++ 2010: DemoWithOpenGL2010_Tut18