Introducción Buffer Definimos un buffer por su resolución espacial (nxm) y su profundidad (o precisión) k, la cantidad de bits/pixel Buffers pixel S. Castro, D. Urribarri Introducción Tradicionalmente el Framebuffer de OpenGL comprende los siguientes buffers: Introducción Frame Buffer de OpenGL La implementación particular de OpenGL determina qué buffers están disponibles y cuántos bits por pixel puede almacenar cada uno de ellos. Mediante glGetIntegerv(parámetro) y seteando el valor apropiado del parámetro, se le puede preguntar a OpenGL cuántos bits por pixel puede almacenar un buffer en partiular. Veamos ahora cuál es la característica de cada uno de los buffers que podemos manipular De Color. Su contenido puede mostrarse. – front-left, front-right, back-left, back-right, y buffers de color auxiliares que pueden estar acivos De Profundidad Stencil S. Castro, D. Urribarri CG 2015 S. Castro, D. Urribarri Los Buffers CG 2015 Los Buffers El doble buffering es una técnica para engañar al ojo para que vea animaciones suaves que se generan de escenas renderizadas. Buffers de Color Son aquéllos en los que usualmente se dibuja Contienen información del color como índice o como valor RGB y también el A. Si la versión de OpenGL soporta estereoscopía, se cuenta con los buffers de color izquierdo y derecho; si no, sólo se tiene el izquierdo. Si se tiene doble buffering se tiene el front y back buffers; si no, sólo se tiene el front. Opcionalmente se pueden soportar buffers de color auxiliares cuyo contenido no puede mostrarse directamente. S. Castro, D. Urribarri CG 2015 CG 2015 El front buffer (fb) se muestra mientras la aplicación renderiza en el back buffer (bb). Cuando se completa el rendering en el bb, se pide al hardware que se haga un swap de los roles de los buffers, haciendo que se muestre el bb y el fb previo sea ahora el bb. S. Castro, D. Urribarri CG 2015 1 Los Buffers Los Buffers Buffer de profundidad Buffer de Profundidad Este buffer almacena el valor de profundidad para cada pixel Éste es medida en función de la distancia al ojo, de modo que pixels con mayores valores de profundidad se sobreescriben con valores menores A menudo se denomina z-buffer. El comportamiento en profundidad puede alterarse modificando la función de comparación (glDepthFunc(GLenum valor) donde valor puede ser GL_LESS, GL_EQUAL, ...). Por defecto es GL_LESS que significa que el fragmento que se comparará pasa el test si su valor de z es menor que el ya almacenado en el buffer. S. Castro, D. Urribarri CG 2015 El buffer de profundidad se usa para determinar cómo se ocluyen entre sí las primitivas de la escena.. Los valores del buffer de profundidad de OpenGL están en el rango [0,1]. S. Castro, D. Urribarri Los Buffers CG 2015 Operaciones sobre los buffers Hay distintas operaciones que pueden realizarse: Stencil Buffer Un uso de este buffer es restringir el dibujado a ciertas porciones de la pantalla (no ocupadas por el stencil). Se puede almacenar una imagen determinada en una región (por ejemplo un tablero de auto). Entonces, al renderizarse toda la escena, este buffer impedirá que sea visible en el lugar ocupado por lo almacenado en esa región. Limpiarlos – Se pueden limpiar uno o más buffers a la vez; antes de limpiarlos se establece el valor que se guardará. Seleccionar los buffers de color para leer y escribir – Los resultados de una operación de lectura o escritura sobre los buffers pueden ir o venir de cualquiera de los buffers de color (glDrawBuffer() y glReadBuffer()). Enmascaramiento – Antes de que OpenGL escriba en los buffers habilitados de color, profundidad o stencil, se aplica sobre los datos una operación de enmascaramiento. Se lleva a cabo una operación AND de cada máscara con el dato correspondiente a ser escrito. S. Castro, D. Urribarri CG 2015 S. Castro, D. Urribarri Operaciones sobre los buffers CG 2015 Operaciones sobre los buffers Modelo de escritura Escribiendo en los buffers Conceptualmente, podemos considerar toda la memoria como un gran arreglo bi-dimensional de pixels Se lee el pixel destino antes de escribir el fuente Podemos leer y escribir bloques rectangulares de pixels – Operaciones Bit block transfer (bitblt) El frame buffer es parte de esta memoria memoria fuente frame buffer (destino) Escribiendo en el frame buffer S. Castro, D. Urribarri CG 2015 S. Castro, D. Urribarri CG 2015 2 Operaciones sobre los buffers Modos de escritura Testeo y Operaciones sobre los fragmentos CO Los bits fuente y destino se combinan bit a bit Hay 16 funciones posibles (una por columna en la tabla) CO T.Model . CM T.Mundo COjo T.Vista COjo Iluminación XOR reemplazo T.Perspectiva CClip OR Procesamiento Geométrico (de vértices) División Perspectiva (/w) Pantalla 3D (CND) T. Viewport Procesamiento de Fragmentos Proc.fragmento, Texturado, Ilum fragmento, … Operaciones Raster S. Castro, D. Urribarri CG 2015 Testeo y Operaciones sobre los fragmentos Luego que OpenGL determina que un fragmento individual debe generarse y cuál es su color, hay varios tests que debe atravesar para determinar si el fragmento se convertirá en un pixel en el frame buffer y, si esto ocurre, cómo se hará. El conjunto de tests y las operaciones a las que debe ser sometido un fragmento son: CP CP CP CP Rasterización S. Castro, D. Urribarri CG 2015 Testeo y Operaciones sobre los fragmentos fragmentos Test Recortado Test alpha Test stencil Test Profundidad – Test de recortado Blending – Test alpha Dithering – Test stencil Operac. lógicas – Test de profundidad al framebuffer – Blending Test de Recortado – Dithering – Operaciones lógicas Los tests y las operaciones están listados en orden; si un fragmento se elimina en un determinado momento, no tiene lugar sobre el mismo ninguno de los tests u operaciones posteriores. S. Castro, D. Urribarri CG 2015 Testeo y Operaciones sobre los fragmentos Se puede definir una porción rectangular en la ventana y restringir a ésta el dibujado mediante el comando glScissor(). S. Castro, D. Urribarri Testeo y Operaciones sobre los fragmentos fragmentos Test Recortado fragmentos Test alpha Blending CG 2015 Test stencil Dithering Test Recortado Test Profundidad Operac. lógicas Test alpha Blending al framebuffer Test stencil Dithering Test Profundidad Operac. lógicas al framebuffer Test Alfa Test Stencil En modo RGBA, este test permite aceptar o rechazar un fragmento basándose en su valor de alfa. Si está habilitado, el test compara el valor de alfa del segmento con un valor de referencia. El fragmento es aceptado o rechazado dependiendo del resultado de esta comparación. Tanto el valor de referencia como la función de comparación pueden setearse con glAlphaFunc(). Se compara un valor de referencia con el almacenado en el pixel en el stencil buffer. Este test se realiza si este buffer está presente; si no, siempre pasa. Dependiendo del resultado del test se modifica o no el valor en el stencil buffer. Se puede elegir una función de comparación en particular, el valor de referencia y la modificación que se lleva a cabo. S. Castro, D. Urribarri CG 2015 S. Castro, D. Urribarri CG 2015 3 Testeo y Operaciones sobre los fragmentos Testeo y Operaciones sobre los fragmentos fragmentos Test Recortado fragmentos Test alpha Blending Test stencil Dithering Test Recortado Test Profundidad Operac. lógicas Test alpha Blending Test stencil Dithering al framebuffer Test Profundidad Operac. lógicas al framebuffer Test de Profundidad Para cada pixel en la pantalla, este buffer guarda la distancia entre el punto de vista y el objeto que ocupa ese pixel. Si el test pasa, el valor que entra reemplaza el valor en el buffer. Este buffer se usa principalmente para cara oculta. S. Castro, D. Urribarri CG 2015 Blending Combina fragmentos con pixels ya almacenados en el frame buffer para producir un nuevo color para dicho pixel. Se pueden aplicar distintas operaciones de blending y el blending que ocurra depende del valor de alfa del segmento que ingresa y del valor de alfa (si hay alguno) del pixel almacenado. S. Castro, D. Urribarri CG 2015 Blending Blending Las imágenes pueden ser de 1, 2, 3 ó 4 dimensiones. La cuarta dimensión es la componente α y es una medida de la opacidad del fragmento. Como las otras componentes de color, el rango de los valores es desde 0.0 (completamente transparente) a 1.0 (completamente opaco). Opacidad y transparencia Los valores de α son importantes en distintos contextos: Las superficies translúcidas permite que pase algo de luz Las superficies transparentes permiten que toda la luz pase a través de ellas transparencua = 1 – opacidad (a) - Simular objetos translúcidos como el vidrio, el agua, etc -Blending y composición de Las superficies opacas permiten que la luz no pase a través de ellas imágenes -Antialiasing de primitivas geométricas Superficie opacca a =1 S. Castro, D. Urribarri CG 2015 S. Castro, D. Urribarri CG 2015 Blending Blending El blending combina fragmentos con pixels ya almacenados en el frame buffer para producir un nuevo color para dicho pixel. Tanto el fragmento como el pixel tienen asociado un factor que controla su contribución al color final del pixel. Estos factores de blending se setean con la primitiva: Se pueden aplicar distintas operaciones de blending y el blending que ocurra depende del valor alfa del segmento que ingresa y del valor alfa (si hay alguno) del pixel almacenado. glBlendFunct(src,dst) Cr = src Cf + dst Cp Los factores comunes de blending que se usan en OpenGL son GL_ONE, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA y GL_SRC_ALPHA,. S. Castro, D. Urribarri CG 2015 S. Castro, D. Urribarri CG 2015 4 Blending Debe habilitarse el blending y tomar los factores fuente y destino Ejemplo Suponer que comenzamos con un color de fondo opaco (R0,G0,B0,1) – Este color es el color destino inicial glEnable(GL_BLEND) Ahora queremos hacer un blend de un polígono translúcido de color (R1,G1,B1,a1) glBlendFunc(src_factor, dst_factor) Seleccionamos GL_SRC_ALPHA y GL_ONE_MINUS_SRC_ALPHA como los factores de blending de fuente y destino Sólo se soportan ciertos factores R’1 = a1 R1 +(1- a1) R0, …… – GL_ZERO, GL_ONE Notar que esta fórmula es correcta si el polígono es opaco o transparente – GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA – GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA En el Redbook hay una lista de éstos S. Castro, D. Urribarri CG 2015 S. Castro, D. Urribarri Blending CG 2015 Blending Dependencia del orden Polígonos opacos y translúcidos ¿Es correcta esta imagen? Supongamos que tenemos un grupo de polígonos algunos de los cuales son opacos y algunos transparentes – En OpenGL, los polígonos se renderizaron en el orden que iban apareciendo en el pipeline ¿Cómo removemos las caras ocultas? – Las funciones de Blending son dependientes del orden Los polígonos opacos bloquean todos los polígonos que están detrás de ellos y afectan el buffer de profundidad Los polígonos transparentes no deberían afectar el buffer de profundidad – Renderizar con glDepthMask(GL_FALSE) que permite que el buffer de profundidad sea de sólo lectura Ordenar los polígonos primero para eliminar cualquier dependencia del orden S. Castro, D. Urribarri CG 2015 S. Castro, D. Urribarri Testeo y Operaciones sobre los fragmentos fragmentos Test Recortado Test alpha Blending Test stencil Dithering CG 2015 Dithering Los sistemas con poca cantidad de bits dedicada a los colores pueden mejorar la resolución de color a expensas de la resolución espacial mediante el dithering. Test Profundidad Operac. lógicas al framebuffer Dithering Es el proceso de aplicación de cierto tipo de ruido con el objetivo de randomizar el error de cuantización. De este modo se evitan los patrones de gran escala tales como la generación de bandas de color (en imágenes). S. Castro, D. Urribarri CG 2015 S. Castro, D. Urribarri CG 2015 5 Dithering Dithering Los sistemas con poca cantidad de bits dedicada a los colores pueden mejorar la resolución de color a expensas de la resolución espacial mediante el dithering. Con blanco y negro, por ejemplo, se pueden generar distintos tonos de grises. Los sistemas con poca cantidad de bits dedicada a los colores pueden mejorar la resolución de color a expensas de la resolución espacial mediante el dithering. Imagen Original Paleta 256 col. S. Castro, D. Urribarri CG 2015 Paleta web-safe Test Recortado CG 2015 Operaciones lógicas Las operaciones lógicas constituyen la última operación a llevarse a cabo sobre un fragmento y se llevan a cabo mediante la primitiva: Test alpha Test stencil Test Profundidad glLogicOp(GLenum CodOperación) reemplazo Blending Paleta 16 col. con dithering S. Castro, D. Urribarri Testeo y Operaciones sobre los fragmentos fragmentos Paleta 16 col. Dithering XOR OR Operac. lógicas al framebuffer Operaciones lógicas Las operaciones lógicas (tales como OR, XOR, INVERT,…) son la última operación que se realiza sobre un fragmento. Ésta es aplicada a los valores de los fragmentos de entrada (source) y/o a los que se encuentran en ese momento en el buffer de color (destination). S. Castro, D. Urribarri CG 2015 S. Castro, D. Urribarri CG 2015 Framebuffer Object (FBO) Aplicaciones usando los Buffers El framebuffer que se provee con el sistema de ventanas usado es el único framebuffer que puede verse en pantalla. Hay framebuffers que pueden crearse en una aplicación y su contenido no puede verse en el monitor pero soportan off-screen rendering. Otra diferencia entre los framebuffers creados por el sistema de ventanas y los framebuffers que se crean especialmente desde la aplicación es que los primeros alocan sus propios buffers -color, profundidad y stencil - cuando se crea la ventana. Cuando se crean framebuffers manejados por la aplicación, es necesario que se le adicionen los renderbuffers que se quiera asociarles a los FBOs creados. Los buffers provistos cuando se crean con el sistema de ventanas nunca podrán asociarse al FBO creado por la aplicación y viceversa. S. Castro, D. Urribarri CG 2015 6 Framebuffer Object (FBO) Primero debe alocarse un nombre al FBO creado en la aplicación. Para esto se usa glGenFramebuffers(), que permite alocar un identificador no usado para el FBO. Luego,se utiliza glBindFramebuffer() – que opera de manera similar a las otras primitivas glBind*() vistas-. La primera vez que se usa para un framebuffer particular, hace que el objeto sea alocado e inicializado. Las llamadas posteriores al mismo harán del mismo un objeto activo. Una vez creado el FBO, es necesario proveer un lugar donde se renderizará y desde donde se leerá; estos son los framebuffer attachments. Los renderbuffers son los tipo de buffer que se pueden adicionar al FBO. S. Castro, D. Urribarri CG 2015 Framebuffer Object (FBO) Renderbuffers Los Renderbuffers son manejados eficientemente por OpenGL. Los datos almacenados en un renderbuffer tienen significado una vez que éste ha sido adicionado a un FBO, asumiendo que el formato del buffer coincide con lo que OpenGL espera renderizar en él (e.g., no se pueden renderizar colores en un buffer de profundidad). Como con cualquiera de los otros buffers en OpenGL, el proceso de alocar y borrar buffers es similar al visto. Para crear un nuevo renderbuffer, se debe usar glGenRenderbuffers(). Una llamada a glDeleteRenderbuffers() liberará el almacenamiento asociado con el renderbuffer. Cuando se usa por primera vez glBindRenderbuffer(), OpenGL crea un renderbuffer con su información de estado seteada a valores por defecto. S. Castro, D. Urribarri CG 2015 Framebuffer Object (FBO) Framebuffer Object (FBO) Renderbuffers Adicionar el/los renderbuffers al FBO Hasta ahora no se reservó memoria para guardar información sobre la imagen. Antes de adicionar un renderbuffer a un framebuffer y renderizar en él, es necesario alocar memoria y especificar el formato de la imagen. Cuando se renderiza, es posible enviar los resultados del rendering a distintos buffers. Las distintas alternativas son: Esto se realiza mediante glRenderbufferStorage() o • Uno o múltiples buffers de color simultáneamente • Buffer de profundidad para almacenar información de oclusión. • Stencil buffer para almacenar máscaras por pixel para controlar el rendering. glRenderbufferStorageMultisample(). Para crear un renderbuffer color de 256 × 256 RGBA: glGenRenderbuffers(1, &color); glBindRenderbuffer(GL_RENDERBUFFER, color); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, 256, 256); Cada uno de estos buffers representa un framebuffer que puede adicionarse. A estos pueden adicionarse buffers de imágenes en los cuales puede renderizarse o desde los cuales puede leerse. Ahora sólo falta adicionarlo al FBO antes de renderizar en él. S. Castro, D. Urribarri CG 2015 S. Castro, D. Urribarri Renderizado a una Textura Renderizado a una textura Algunas veces es necesario generar o modificar texturas durante la ejecución de un programa. La textura puede ser, por ejemplo, la escena o una parte de la misma. CG 2015 Renderizado a una Textura Para renderizar a una textura y aplicar esa textura a una escena en una segunda pasada deben seguirse los pasos mencionados. 1. Seteo del FBO. GLuint fboHandle; // Handler del FBO El proceso involucra los siguientes pasos cuando se renderiza: // Generar y enlazar el framebuffer 1. Seteo del FBO. Crear un target de rendering particular (FBO) y adicionar a éste la textura glGenFramebuffers(1, &fboHandle); 2. Renderizar la textura T al FBO // Crear el objeto textura 3. Desafectar el contexto de rendering del FBO y ponerlo nuevamente en el framebuffer GLuint renderTex; 4. Renderizar la escena normalmente usando la textura T generada glActiveTexture(GL_TEXTURE0); // Usar la unidad de textura 0 glBindFramebuffer(GL_FRAMEBUFFER, fboHandle); glGenTextures(1, &renderTex); glBindTexture(GL_TEXTURE_2D, renderTex); glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,512,512,0,GL_RGBA,GL_UNSIGNED _BYTE,NULL); … S. Castro, D. Urribarri CG 2015 S. Castro, D. Urribarri CG 2015 7 Renderizado a una Textura Renderizado a una Textura // Crear el buffer de profundidad Para que el programa de fragmentos sea siempre el mismo (cuando renderizo a textura una textura blanca no afecta el color y cuando renderizo con la textura se usa la textura generada) se define una textura blanca en la unidad de textura 1. GLuint depthBuf; // Bind a la textura del FBO glGenRenderbuffers(1, &depthBuf); glBindFramebuffer(GL_FRAMEBUFFER, fboHandle); glBindRenderbuffer(GL_RENDERBUFFER, depthBuf); glViewport(0,0,512,512); // Viewport para la textura glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, // Usar la textura “blanca" 512, 512); int loc = glGetUniformLocation(programHandle, "Texture"); // Bind la textura al FBO glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderTex, 0); glUniform1i(loc, 1); // Bind el buffer de profundidad al FBO // Setup matrices para renderizar escena a textura. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, … GL_RENDERBUFFER, depthBuf); renderTextureScene(); // Setear el target para la salida del shader de fragmentos glBindFramebuffer(GL_FRAMEBUFFER, 0); GLenum drawBufs[] = {GL_COLOR_ATTACHMENT0}; glDrawBuffers(1, drawBufs); S. Castro, D. Urribarri CG 2015 S. Castro, D. Urribarri Renderizado a una Textura Para que el programa de fragmentos sea siempre el mismo (cuando renderizo a textura una textura blanca no afecta el color y cuando renderizo con la textura se usa la textura generada) se define una textura blanca en la unidad de textura 1. Sombreado diferido (Deferred shading) Sombreado diferido (Deferred shading) El sombreado diferido es una técnica que pospone la etapa de iluminación/sombreado a una segunda pasada para evitar calcular el sombreado de un pixel más de una vez. La idea básica es la siguiente: glViewport(0,0,width,height); // Viewport para la ventana principal 1. Primera pasada. Se renderiza la escena pero en lugar de evaluar el modelo de reflexión para determinar el color de un fragmento, se almacena la información geométrica (posición, normal y además coordenadas de textura, reflectividad, etc) en un conjunto intermedio de buffers denominados colectivamente g-buffer 2. Segunda pasada. Se lee del g-buffer, se evalúa el modelo de reflexión y se produce el color final de cada pixel / Usar la textura asociada con el FBO int loc = glGetUniformLocation(programHandle, "Texture"); glUniform1i(loc, 0); // Resetear las matrices de proyección y vista … renderScene(); ¿Puede utilizar lo visto para renderizar en un espejo? Si es así, ¿cómo? S. Castro, D. Urribarri CG 2015 CG 2015 Sombreado diferido (Deferred shading) Guardaremos, para cada pixel del g-buffer la posición, la normal y el color difuso. S. Castro, D. Urribarri Sombreado diferido (Deferred shading) Sombreado diferido (Deferred shading) Sombreado diferido (Deferred shading) En la primera pasada, en la aplicación, se debe:: El FBO deberá contener nuestro g-buffer. 1. Hacer el binding al FBO. 2. Limpiar los buffers de color/profundidad, habilitar el test de profundidad y utilizar los shaders desarrollados para la pasada 1. 3. Renderizar la escena normalmente CG 2015 Se deberá crear el FBO y a éste se le deberá adicionar el buffer de profundidad, el de posición, el de normales y el de reflectividad. GLuint depthBuf, posTex, normTex, colorTex; glGenFramebuffers(1, &deferredFBO); glBindFramebuffer(GL_FRAMEBUFFER, deferredFBO); // Buffer de profundidad glGenRenderbuffers(1, &depthBuf); glBindRenderbuffer(GL_RENDERBUFFER, depthBuf); En la pasada dos: glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 1. Revertir el FBO al framebuffer por defecto 2. Limpiar el buffer de color, deshabilitar el test de profundidad (si se quiere) y utilizar los shaders para esta pasada. 3. Renderizar en un rectángulo (2 triángulos) con coordenadas de textura que vayan de 0 a 1 en cada direccción. S. Castro, D. Urribarri CG 2015 width, height); // Buffer de posición glActiveTexture(GL_TEXTURE0); // Use texture unit 0 for position glGenTextures(1, &posTex); glBindTexture(GL_TEXTURE_2D, posTex); S. Castro, D. Urribarri CG 2015 8 Sombreado diferido (Deferred shading) Sombreado diferido (Deferred shading) Sombreado diferido (Deferred shading) Sombreado diferido (Deferred shading) El FBO deberá contener nuestro g-buffer. El shader de vértices es el siguiente: … glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); layout( location = 0 ) in vec3 VertexPosition; layout( location = 1 ) in vec3 VertexNormal; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST); … layout( location = 2 ) in vec2 VertexTexCoord; out vec3 Position; uniform mat4 ModelViewMatrix; out vec3 Normal; uniform mat3 NormalMatrix; glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuf); out vec2 TexCoord; uniform mat4 ProjectionMatrix; glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, void main() GL_TEXTURE_2D, posTex, 0); … { Normal = normalize( NormalMatrix * VertexNormal); y luego se deben adicionar las imágenes al framebuffer: uniform mat4 MVP; Position = vec3( ModelViewMatrix * GLenumdrawBuffers[] = {GL_NONE, GL_COLOR_ATTACHMENT0, vec4(VertexPosition,1.0) ); GL_COLOR_ATTACHMENT1,GL_COLOR_ATTACHMENT2}; glDrawBuffers(4, drawBuffers); TexCoord = VertexTexCoord; gl_Position = MVP * vec4(VertexPosition,1.0); } S. Castro, D. Urribarri CG 2015 S. Castro, D. Urribarri Sombreado diferido (Deferred shading) CG 2015 Sombreado diferido (Deferred shading) Sombreado diferido (Deferred shading) Sombreado diferido (Deferred shading) El código común a ambos shaders de fragmentos: El código común a ambos shaders de fragmentos: // Texturas del g-buffer uniform sampler2D PositionTex, NormalTex, ColorTex; struct LightInfo { in vec3 Position; vec4 Position; // Light position in eye coords. vec3 Intensity; // Diffuse intensity in vec3 Normal; in vec2 TexCoord; }; layout (location = 0) out vec4 FragColor; uniform LightInfo Light; struct MaterialInfo { layout (location = 1) out vec3 PositionData; layout (location = 2) out vec3 NormalData; vec3 Kd; // Diffuse reflectivity layout (location = 3) out vec3 ColorData; }; vec3 diffuseModel( vec3 pos, vec3 norm, vec3 diff ) { vec3 s = normalize(vec3(Light.Position) - pos); uniform MaterialInfo Material; float sDotN = max( dot(s,norm), 0.0 ); subroutine void RenderPassType(); vec3 diffuse = Light.Intensity * diff * sDotN; return diffuse; subroutine uniform RenderPassType RenderPass; … }: S. Castro, D. Urribarri CG 2015 S. Castro, D. Urribarri CG 2015 Sombreado diferido (Deferred shading) Sombreado diferido (Deferred shading) Antialiasing El antialiasing es un proceso que permite, en la primitivas geométricas, remover los jaggies. Esto puede hacerse en OpenGL Shader de fragmentos, pasada 1: // Almacenar posición, normal color difuso en el g-buffer glEnable(modo) PositionData = Position; NormalData = Normal; ColorData = Material.Kd; - modo GL_POINT_SMOOTH GL_LINE_SMOOTH Shader de fragmentos, pasada 2: // Recuperar posición, normal color difuso // texturas del g-buffer GL_POLYGON_SMOOTH de las vec3 pos = vec3( texture( PositionTex, TexCoord ) ); vec3 norm = vec3( texture( NormalTex, TexCoord ) ); vec3 diffColor = vec3( texture(ColorTex, TexCoord) ); - valores de alpha calculados teniendo en cuenta el cubrimiento a nivel de sub-pixel FragColor = vec4( diffuseModel(pos,norm,diffColor), 1.0 ); - disponible en los modos RGBA y colormaps S. Castro, D. Urribarri CG 2015 S. Castro, D. Urribarri CG 2015 9 Antialiasing Antialiasing Puede tratar de pintar un pixel adicionando una fracción de su color al frame buffer Aliasing de líneas La línea raster ideal tiene un pixel de ancho Todos los segmentos de línea que no sean los verticales y los horizontales, cubren pixels parcialmente – Esta fracción depende del porcentaje de pixel que es cubierto por el fragmento – Esta fracción depende de si hay solapamiento (overlap) Los algoritmos simples pintan sólo pixels completos Estos conduce a aliasing Situaciones similares se presentan con los polígonos no overlap S. Castro, D. Urribarri CG 2015 S. Castro, D. Urribarri overlap CG 2015 Antialiasing Antialiasing en OpenGL Puede habilitarse separadamente para puntos, líneas o polígonos glEnable(GL_POINT_SMOOTH); glEnable(GL_LINE_SMOOTH); glEnable(GL_POLYGON_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); S. Castro, D. Urribarri CG 2015 10