opengl
Bufory ramki
Szukaj…
Podstawy buforów ramki
Bufor ramki jest rodzajem bufora, który przechowuje wartości kolorów, głębia i wzornik informacje pikseli w pamięci. Kiedy rysujesz coś w OpenGL, dane wyjściowe są zapisywane w domyślnym buforze ramek, a następnie na ekranie widać wartości kolorów tego bufora. Możesz także stworzyć własny bufor ramki, którego można używać do wielu fajnych efektów przetwarzania końcowego, takich jak skala szarości, rozmycie, głębia ostrości, zniekształcenia, odbicia ...
Na początek musisz utworzyć obiekt bufora ramki ( FBO ) i powiązać go jak każdy inny obiekt w OpenGL:
unsigned int FBO;
glGenFramebuffers(1, &FBO);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
Teraz musisz dodać co najmniej jeden załącznik (kolor, głębokość lub szablon) do bufora ramki. Załącznik to miejsce w pamięci, które działa jako bufor bufora ramki. Może to być zarówno tekstura , jak i obiekt renderbuffer . Zaletą korzystania z tekstury jest to, że można łatwo używać tej tekstury w modułach cieniujących po obróbce. Tworzenie tekstury jest podobne do normalnej tekstury:
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
i height
powinny być takie same jak rozmiar okna renderowania. Wskaźnik danych tekstury ma NULL
ponieważ chcesz tylko przydzielić pamięć i nie wypełniać tekstury żadnymi danymi. Tekstura jest gotowa, więc możesz ją dołączyć do bufora ramki:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
Bufor ramki powinien być teraz gotowy do użycia, ale możesz również dodać opcję głębokości lub zarówno głębokości, jak i załączników szablonu. Jeśli chcesz dodać je jako załączniki tekstur (i użyć ich do przetwarzania), możesz utworzyć kolejne tekstury, jak wyżej. Jedyną różnicą byłyby te linie:
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);
Lub te, jeśli chcesz użyć głębokości i szablonu w jednej teksturze:
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);
Możesz również użyć bufora renderowania zamiast tekstury jako załącznika do buforów głębokości i szablonów, jeśli nie chcesz później przetwarzać wartości. (Zostanie to wyjaśnione w innym przykładzie ...)
Możesz sprawdzić, czy bufor ramki został pomyślnie utworzony i ukończony bez żadnych błędów:
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
// do something...
I na koniec nie zapomnij rozpiąć bufora ramki, aby przypadkowo go nie renderować:
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Granice
Maksymalną liczbę buforów kolorów, które można dołączyć do bufora pojedynczej ramki, można określić za pomocą funkcji OGL glGetIntegerv , używając parametru GL_MAX_COLOR_ATTACHMENTS
:
GLint maxColAttchments = 0;
glGetIntegerv( GL_MAX_COLOR_ATTACHMENTS, &maxColAttchments );
Korzystanie z bufora ramki
Użycie jest dość proste. Najpierw związujesz bufor ramki i renderujesz w nim scenę. Ale tak naprawdę nic nie zobaczysz, ponieważ twój renderbuffer nie jest widoczny. Tak więc drugą częścią jest wyrenderowanie bufora ramki jako tekstury pełnoekranowego kwadratu na ekranie. Możesz po prostu wyrenderować go takim, jaki jest lub wykonać kilka efektów przetwarzania końcowego.
Oto wierzchołki quada pełnoekranowego:
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
};
Będziesz musiał przechowywać je w VBO lub renderować za pomocą wskaźników atrybutów. Będziesz także potrzebował podstawowego programu do cieniowania do renderowania quada pełnoekranowego z teksturą.
Moduł cieniujący wierzchołek:
in vec2 position;
in vec2 texCoords;
out vec2 TexCoords;
void main()
{
gl_Position = vec4(position.x, position.y, 0.0, 1.0);
TexCoords = texCoords;
}
Moduł cieniujący fragmenty:
in vec2 TexCoords;
out vec4 color;
uniform sampler2D screenTexture;
void main()
{
color = texture(screenTexture, TexCoords);
}
Uwaga: Może być konieczne dostosowanie modułów cieniujących do wersji GLSL .
Teraz możesz wykonać rzeczywiste renderowanie. Jak opisano powyżej, pierwszą rzeczą jest renderowanie sceny w FBO. Aby to zrobić, po prostu powiąż FBO, wyczyść go i narysuj scenę:
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...
Uwaga: W funkcji glClear
należy określić wszystkie używane załączniki bufora ramki (w tym przykładzie załączniki koloru i głębokości).
Teraz możesz wyrenderować FBO jako pełnoekranowy quad w domyślnym buforze klatek, abyś mógł go zobaczyć. Aby to zrobić, po prostu rozpisz FBO i wyrenderuj quad:
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);
I to wszystko! Jeśli zrobiłeś wszystko poprawnie, powinieneś zobaczyć tę samą scenę, co poprzednio, ale renderować na quadzie na pełnym ekranie. Rezultat wizualny jest taki sam jak poprzednio, ale teraz możesz łatwo dodawać efekty przetwarzania końcowego poprzez edycję modułu cieniującego fragmenty. (Dodam efekty w innym przykładzie lub linkach tutaj)