opengl
framebuffers
Sök…
Grunderna i framebuffrar
Framebuffer är en typ av buffert, som lagrar färgvärden, djup och stencilen information av pixlar i minnet. När du ritar något i OpenGL lagras utgången i standardbildbufferten och då ser du faktiskt färgvärdena på denna buffert på skärmen. Du kan också skapa din egen framebuffer som kan användas för en hel del coola efterbehandlingseffekter som gråskala, oskärpa, fältdjup, distorsioner, reflektioner ...
För att börja med måste du skapa ett framebuffer-objekt ( FBO ) och binda det som alla andra objekt i OpenGL:
unsigned int FBO;
glGenFramebuffers(1, &FBO);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
Nu måste du lägga till minst en bilaga (färg, djup eller stencil) till framebuffern. En bilaga är en minnesplats som fungerar som en buffert för frambuffern. Det kan antingen vara en struktur eller ett renderbuffer-objekt . Fördelen med att använda en konsistens är att du enkelt kan använda den här strukturen i en efterbehandlande skuggare. Att skapa strukturen liknar en vanlig struktur:
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, 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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
width
och height
ska vara densamma som din renderingsfönsterstorlek. Pekaren för texturdata är NULL
eftersom du bara vill tilldela minnet och inte fylla strukturen med några data. Strukturen är klar så att du faktiskt kan fästa den i framebuffern:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
Din framebuffer bör vara redo att användas nu men du kanske också vill lägga till djupfäste eller både djup- och stencilsfästen. Om du vill lägga till dem som textilbilagor (och använda dem för en del bearbetning) kan du skapa en annan struktur som ovan. Den enda skillnaden skulle vara i dessa rader:
glTexImage2D(
GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0,
GL_DEPTH_COMPONENT, GL_FLOAT, NULL
);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texture, 0);
Eller dessa om du vill använda djup och stencilfäste i en enda struktur:
glTexImage2D(
GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0,
GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL
);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texture, 0);
Du kan också använda en renderbuffer istället för en struktur som en bilaga för djup och stencil buffertar om du inte vill bearbeta värdena senare. (Det kommer att förklaras i ett annat exempel ...)
Du kan kontrollera om framebuffern har skapats och slutförts utan några fel:
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
// do something...
Och slutligen glöm inte att lossa framebuffern så att du inte avser att av misstag:
glBindFramebuffer(GL_FRAMEBUFFER, 0);
gränser
Det maximala antalet färgbuffertar som kan kopplas till en enda rambuffert kan bestämmas med OGL-funktionen glGetIntegerv med hjälp av parametern GL_MAX_COLOR_ATTACHMENTS
:
GLint maxColAttchments = 0;
glGetIntegerv( GL_MAX_COLOR_ATTACHMENTS, &maxColAttchments );
Använda framebuffern
Användningen är ganska enkel. Först binder du din framebuffer och återger din scen till den. Men du kommer faktiskt inte se någonting ännu eftersom din renderbuffer inte är synlig. Så den andra delen är att framställa din framebuffer som en struktur på en fullskärms fyrdubbla på skärmen. Du kan bara göra det som det är eller göra några efterbehandlingseffekter.
Här är vertikalerna för en fyrskärms fyrduk:
float vertices[] = {
// positions texture coordinates
-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
};
Du måste lagra dem i en VBO eller återge med attributpekare. Du kommer också att behöva något grundläggande Shader-program för att göra fullskärms fyrduken med textur.
Korsskärm:
in vec2 position;
in vec2 texCoords;
out vec2 TexCoords;
void main()
{
gl_Position = vec4(position.x, position.y, 0.0, 1.0);
TexCoords = texCoords;
}
Fragment shader:
in vec2 TexCoords;
out vec4 color;
uniform sampler2D screenTexture;
void main()
{
color = texture(screenTexture, TexCoords);
}
Obs: Du kan behöva justera skuggmaskinerna för din version av GLSL .
Nu kan du göra själva rendering. Som beskrivits ovan är det första att återge scenen till din FBO. För att göra det binder du helt enkelt din FBO, rensa den och rita scenen:
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// draw your scene here...
Obs: I glClear
funktionen ska du ange alla bilagor för framebuffer-filer som du använder (i det här exemplet färg- och djupbilagor).
Nu kan du återge din FBO som en fullskärms fyrdubbla på standardbildbufferten så att du kan se den. För att göra detta lossar du helt enkelt din FBO och gör fyrhjulet:
glBindFramebuffer(GL_FRAMEBUFFER, 0); // unbind your FBO to set the default framebuffer
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader.Use(); // shader program for rendering the quad
glBindTexture(GL_TEXTURE_2D, texture); // color attachment texture
glBindBuffer(GL_ARRAY_BUFFER, VBO); // VBO of the quad
// You can also use VAO or attribute pointers instead of only VBO...
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindBuffer(GL_ARRAY_BUFFER, 0);
Och det är allt! Om du har gjort allt på rätt sätt ska du se samma scen som tidigare men återges på en fullskärms fyrkant. Den visuella utgången är densamma som tidigare men nu kan du enkelt lägga till efterbehandlingseffekter bara genom att redigera fragmentet. (Jag lägger till effekter i ett annat exempel och länkar det här)