opengl
фреймбуферов
Поиск…
Основы фреймбуферов
Framebuffer - это тип буфера, который хранит значения цвета , глубину и информацию о трафаретах пикселей в памяти. Когда вы рисуете что-то в OpenGL, вывод сохраняется в фреймбуфере по умолчанию, а затем вы фактически видите значения цвета этого буфера на экране. Вы также можете создать свой собственный фреймбуфер, который можно использовать для множества интересных эффектов пост-обработки, таких как серо-масштаб, размытие, глубина резкости, искажения, отражения ...
Для начала вам нужно создать объект фреймбуфера ( FBO ) и связать его, как и любой другой объект в OpenGL:
unsigned int FBO;
glGenFramebuffers(1, &FBO);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
Теперь вам нужно добавить по крайней мере одно вложение (цвет, глубина или трафарет) в фреймбуфер. Вложение - это ячейка памяти, которая выступает в качестве буфера для фреймбуфера. Это может быть либо текстура , либо объект renderbuffer . Преимущество использования текстуры заключается в том, что вы можете легко использовать эту текстуру в пост-обрабатывающих шейдерах. Создание текстуры аналогично нормальной текстуре:
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
и height
должны быть такими же, как размер окна рендеринга. Указатель данных текстуры имеет NULL
потому что вы хотите выделить память и не заполнить текстуру любыми данными. Текстура готова, поэтому вы можете привязать ее к фреймбуферу:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
Теперь ваш фреймбуфер должен быть готов к использованию, но вы можете также добавить добавление глубины или вложения глубины и трафарета. Если вы хотите добавить их в качестве вложений текстуры (и использовать их для некоторой обработки), вы можете создать другие текстуры, например, выше. Единственное различие в этих строках:
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);
Или это, если вы хотите использовать глубину и трафаретную привязку в одной текстуре:
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);
Вы также можете использовать renderbuffer вместо текстуры в качестве вложения для буферов глубины и трафарета, если не хотите обрабатывать значения позже. (Это будет объяснено в другом примере ...)
Вы можете проверить, успешно ли создан и завершен фреймбуфер без каких-либо ошибок:
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
// do something...
И, наконец, не забудьте отвязать фреймбуфер, чтобы вы не случайно его отбросили:
glBindFramebuffer(GL_FRAMEBUFFER, 0);
рамки
Максимальное количество цветовых буферов, которые могут быть присоединены к буму одного кадра, может быть определено функцией OGL glGetIntegerv , используя параметр GL_MAX_COLOR_ATTACHMENTS
:
GLint maxColAttchments = 0;
glGetIntegerv( GL_MAX_COLOR_ATTACHMENTS, &maxColAttchments );
Использование фреймбуфера
Использование довольно простое. Во-первых, вы привязываете фреймбуфер и визуализируете свою сцену. Но вы ничего не увидите, потому что ваш рендеринг не отображается. Итак, вторая часть - сделать ваш фреймбуфер как текстуру полноэкранного квадрата на экране. Вы можете просто визуализировать его так, как есть, или делать некоторые эффекты пост-обработки.
Вот вершины для полноэкранного квадранта:
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
};
Вам нужно будет хранить их в VBO или рендеринг с помощью указателей атрибутов. Вам также понадобится базовая шейдерная программа для рендеринга полноэкранного квадроцикла с текстурой.
Vertex shader:
in vec2 position;
in vec2 texCoords;
out vec2 TexCoords;
void main()
{
gl_Position = vec4(position.x, position.y, 0.0, 1.0);
TexCoords = texCoords;
}
Фрагментный шейдер:
in vec2 TexCoords;
out vec4 color;
uniform sampler2D screenTexture;
void main()
{
color = texture(screenTexture, TexCoords);
}
Примечание. Возможно, вам потребуется настроить шейдеры для вашей версии GLSL .
Теперь вы можете сделать фактический рендеринг. Как описано выше, первое, что нужно сделать, сделать сцену в вашем FBO. Для этого вы просто связываете свой FBO, очищаете и рисуете сцену:
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...
Примечание. В функции glClear
вы должны указать все вложения фреймбуфферов, которые вы используете (в этом примере вложение цвета и глубины).
Теперь вы можете отобразить свой FBO в полноэкранном квадранте по умолчанию для фреймбуфера, чтобы вы могли его видеть. Для этого вы просто отвязываете свой FBO и визуализируете квад:
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);
И это все! Если вы все сделали правильно, вы должны увидеть ту же сцену, что и раньше, но отображаться на полноэкранном квадранте. Визуальный вывод такой же, как и раньше, но теперь вы можете легко добавить эффекты пост-обработки, просто отредактировав шейдер фрагмента. (Я добавлю эффекты в другой пример (ы) и свяжу его здесь)