TEMA 12 EFECTOS VISUALES: FUSIONES Y NIEBLA
Juan Carlos Hernández González - 52415268Q David Álvarez Oquina - 71024082J Juan Manuel Sánchez Manzano - 52414006L Informática Gráfica Ingeniería Informática – Universidad de Salamanca
Departamento de Informática y Automática Universidad de Salamanca
Índice: Introducción........................................................................................................ 4 1.- Fusiones (Mezclas) ....................................................................................... 5 1.1 – Combinación de colores ........................................................................ 5 1.2 – Cambio de la ecuación de fusión ........................................................... 9 1.3 – Uso de fusiones ................................................................................... 10 1.3.2 – Desvanecimiento........................................................................... 11 1.3.2 – Composición ................................................................................. 11 1.3.3 – Filtros de color............................................................................... 12 1.3.4 – Simulación de brochas y pinceles ................................................. 12 1.3.4 – Antiescalonado (Antialiasing o Suavizado) ................................... 13 1.3.5 – Billboarding ................................................................................... 13 1.4 – Manejo de la profundidad .................................................................... 14 1.5 – Capas ocultas de los objetos ............................................................... 16 2 – Antiescalonado (Antialiasing o Suavizado)................................................. 18 2.1 – Suavizado en color indexado............................................................... 22 2.2 – Muestreo múltiple................................................................................. 23 3 – La niebla..................................................................................................... 24 4 – Búfer de acumulación................................................................................. 28 5 – Otras operaciones de color ........................................................................ 31 5.1 – Máscaras de color................................................................................ 31 5.2 – Operaciones de color lógicas............................................................... 31 5.3 – Prueba Alpha ....................................................................................... 32 5.4 – Tramado .............................................................................................. 33 Conclusiones.................................................................................................... 35 Bibliografía ....................................................................................................... 36
2
Índice de Tablas y Figuras: Tabla 1 – Combinación de colores (glBlendFunc).............................................. 7 Figura 1 – Ejemplo de reflejos............................................................................ 8 Tabla 2 – Código fuente de ejemplo de reflejos ................................................. 9 Tabla 3 – Cambio de la ecuación de fusión (glBlendEquation) .......................... 9 Figura 2 – Ejemplo de transparencias.............................................................. 11 Figuras 3 y 4 – Ejemplo de composición .......................................................... 12 Figuras 5 y 6 – Aplicación de suavizado .......................................................... 13 Figura 7 – Árbol con billboarding...................................................................... 14 Tabla 4 – Manejo de la profundidad (glDepthFunc) ......................................... 16 Figura 8 – Ejemplo de bordes dentados........................................................... 18 Tabla 5 –Objetivos ........................................................................................... 19 Tabla 6 – Metodos............................................................................................ 20 Figura 9 – Puntos sin suavizado ...................................................................... 20 Figura 10 – Ejemplo de suavizado en puntos................................................... 21 Figura 11 – Ejemplo de suavizado en lineas .................................................... 21 Tabla 7 – Ecuaciones de niebla ....................................................................... 24 Figura 12 – Comportamiento de ecuaciones de niebla .................................... 25 Figura 13 – Sin niebla ...................................................................................... 26 Figura 14 – Niebla generada con la ecuación GL_LINEAR ............................. 26 Figura 15 – Niebla generada con la ecuación GL_EXP ................................... 26 Figura 16 – Niebla generada con la ecuación GL_EXP2 ................................. 26 Tabla 8 – Fragménto de código fuente de niebla ............................................. 27 Tabla 9 – Operaciones del búfer de acumulación. ........................................... 28 Figura 17 – Vista antes la acumulación............................................................ 29 Figura 18 – Vista tras el volcado del búfer (Depth of Field).............................. 29 Figura 19 – Vista tras el volcado del búfer (Motion Blur).................................. 30 Tabla 10 – Operaciones de color lógicas (glLogicOp)...................................... 32 Tabla 11 – Prueba Alpha (glAlphaFunc) .......................................................... 33
3
Introducción Para conseguir una mayor realidad en las figuras representadas con OpenGL, se puede recurrir a colores, luces y texturas entre otras opciones. No obstante se necesitan otros “efectos” para conseguir la disminución de nitidez o claridad de visión, esto se consigue mediante las fusiones, mezclas, el antiescalonado y las nieblas. Con ello se consiguen la fusión y el solapamiento de colores, suavizar bordes dentados para un mayor ajuste a la figura real y efectos atmosféricos y limitaciones de visibilidad.
4
1.- Fusiones (Mezclas) OpenGL coloca el valor del color en el búfer de colores en circunstancias normales. Los valores de profundidad para cada fragmento se sitúan en el búfer de profundidad. Cuando se desactiva la prueba de profundidad, los valores del nuevo color sobrescriben cualquier valor ya presente en el búfer de colores. Cuando la prueba de profundidad se activa, los fragmentos del nuevo color reemplazan los fragmentos existentes sólo si se parecen al plano de recorte cercano más que los valores que ya se encontraban ahí. Todo esto sucede en condiciones normales, pero estas reglas dejan de aplicarse en el momento en que activamos las fusiones de OpenGL: glEnable(GL_BLEND); para habilitar las mezclas. glDisable(GL_BLEND); para deshabilitar las mezclas.
Cuando la fusión se ha activado, el color entrante se combina con el valor del color presente en le búfer de colores. La forma en que se combinan nos proporciona una alta gama de efectos especiales.
1.1 – Combinación de colores El valor que ya se encuentra almacenado en el búfer de colores se denomina color de destino. Este valor de color tiene tres componentes individuales (rojo, verde y azul) y, opcionalmente, un valor alpha.
Un valor de color que entra como resultado de más comandos de interpretación que puedan interactuar o no con el color destino se denomina color de origen. El color de origen también tiene los componentes rojo, verde y azul y, opcionalmente, el valor alpha.
5
La forma en que se combinan los colores de origen y destino cuando se ha activado la fusión se controla a través de una ecuación de fusión. La ecuación predeterminada es: Cf = (Cs*S)+(Cd*D) Cf = Color Cs = Color Cd = Color S = Factor D = Factor
final computado. de origen. de destino. de fusión de origen. de fusión de destino.
Los factores de fusión S y D se establecen con la siguiente función: glBlendFunc(GLenum S, GLenum D);
S y D no son valores físicos que podamos especificar directamente, sino que son una enumeración de valores.
En la tabla siguiente se muestran los posibles valores para la función de fusión. Los subíndices
s,
d
y
c
se refieren
al origen, destino y color
respectivamente. R, G, B y A se refieren al rojo, verde, azul y alpha respectivamente.
Función
Factores de
Factor de
fusión RGB
fusión Alpha
GL_ZERO
(0,0,0)
0
GL_ONE
(1,1,1)
1
GL_SRC_COLOR
(Rs,Gs,Bs)
As
GL_ONE_MINUS_SRC_COLOR
(1,1,1)-(Rs,Gs,Bs)
1-As
GL_DST_COLOR
(Rd,Gd,Bd)
Ad
GL_ONE_MINUS_DST_COLOR
(1,1,1)-(Rd,Gd,Bd)
1-Ad
GL_SRC_ALPHA
(As,As,As)
As
GL_ONE_MINUS_SRC_ALPHA
(1,1,1)-(As,As,As)
1-As
GL_DST_ALPHA
(Ad,Ad,Ad)
Ad
GL_ONE_MINUS_DST_ALPHA
(1,1,1)-(Ad,Ad,Ad)
1-Ad
GL_CONSTANT_COLOR
(Rc,Gc,Bc)
Ac
GL_ONE_MINUS_CONSTANT_COLOR
(1,1,1)-(Rc,Gc,Bc)
1-Ac
6
GL_CONSTANT_ALPHA
(Ac,Ac,Ac)
Ac
GL_ONE_MINUS_CONSTANT_ALPHA
(1,1,1)-(Ac,Ac,Ac)
1-Ac
GL_SRC_ALPHA_SATURATE
(f,f,f)*
1
Tabla 1 – Combinación de colores (glBlendFunc)
*f = min(As, 1-As).
Los colores se representan mediante números de punto flotante. Por tanto, sumarlos, restarlos e incluso multiplicarlos son operaciones perfectamente válidas.
La tabla anterior puede ser algo confusa, por lo que se va a ver un ejemplo a continuación: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Esta función le indica a OpenGL que recoja el color de origen (entrante) y multiplique el color (valores RGB) por el valor alpha, que sume este resultado al resultado de multiplicar el color destino por uno menos el valor de alpha del origen. Por ejemplo, se supone que está el color Rojo (1.0f, 0.0f, 0.0f, 0.0f) preparado ya en el búfer de colores. Éste sería el color destino Cd. Si se dibuja sobre éste con el color Azul y un valor alpha de 0.5 (0.0f, 0.0f, 1.0f, 0.5f), se podrían computar los colores finales de la siguiente manera: Cd = color de destino = (1.0f, 0.0f, 0.0f, 0.0f) Cs = color de origen = (0.0f, 0.0f, 1.0f, 0.5f) S = alpha de origen = 0.5 D = uno menos alpha de origen = 1.0 – 0.5 = 0.5
La ecuación Cf=(Cs*S)+(Cd*D) se calcula así: Cf=(Azul*0.5)+(Rojo*0.5)
El color final es una combinación escalada del valor del rojo original con el valor del azul entrante. Cuando mayor sea el valor alpha entrante, se añadirá más del color entrante y se retendrá menos del color original.
7
Esta función de fusión se suele usar para conseguir el efecto de dibujar un objeto transparente delante de un objeto opaco. Sin embargo, esta técnica requiere que dibujemos primero el objeto u objetos del fondo y a continuación, el objeto transparente fusionado delante. Este efecto puede ser especular:
Figura 1 – Ejemplo de reflejos
En este ejemplo, se utiliza la fusión para crear un falso efecto reflectante. Se usa una función que hemos llamado DrawWorld() para generar los dos toros, la esfera y los movimientos que realizan. Para generar el suelo se ha codificado otra función llamada DrawGround(). En la función RenderScene() se dibuja en primer lugar la escena escalando por -1 para invertir el eje “y”, los giros y colocar la luz debajo. De este modo se obtiene la imagen reflejada. Después se dibuja el suelo y se utiliza la función de fusión para hacerlo transparente y crear así el efecto de reflejo. Y para terminar, se dibuja la escena normal: void RenderScene(void) { //Borrar la ventana con el color de borrado actual glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); //Mover la luz de debajo del suelo a la luz del mundo reflejado glLightfv(GL_LIGHT0, GL_POSITION, fLightPosMirror); if(reflejo) { glPushMatrix(); glFrontFace(GL_CW); //La geometría se refleja, //intercambiar la orientación
8
glScalef(1.0f, -1.0f, 1.0f); DrawWorld(); //Dibujar el mundo reflejado glFrontFace(GL_CCW); glPopMatrix(); } //Dibujar el suelo transparente sobre el reflejo glDisable(GL_LIGHTING); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); DrawGround(); glDisable(GL_BLEND); glEnable(GL_LIGHTING); //Restablecer la iluminación y dibujar el mundo correctamente glLightfv(GL_LIGHT0, GL_POSITION, fLightPos); DrawWorld(); //Dibujar el mundo normal glPopMatrix(); //Realizar el intercambio del búfer glutSwapBuffers(); } Tabla 2 – Código fuente de ejemplo de reflejos
1.2 – Cambio de la ecuación de fusión La ecuación de fusión vista en el apartado anterior es la ecuación predeterminada, pero se puede elegir entre cinco ecuaciones diferentes y seleccionarlas con la siguiente función: void glBlendEquation(GLenum modo);
Modo
Función
GL_FUNC_ADD (predeterminado)
Cf=(Cs*S)+(Cd*D)
GL_FUNC_SUBSTRACT
Cf=(Cs*S)-(Cd*D)
GL_FUNC_REVERSE_SUBSTRACT
Cf=(Cd*D)-(Cs*S)
GL_MIN
Cf=min(Cs,Cd)
GL_MAX
Cf=max(Cs,Cd)
Tabla 3 – Cambio de la ecuación de fusión (glBlendEquation)
Además de glBlendFunc
(vista en el apartado anterior), hay más
flexibilidad con la siguiente función: void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
9
Mientras que glBlendFunc especifica las funciones de fusión para los valores RGBA de origen y destino, glBlendFuncSeparate permite especificar funciones de fusión para los componentes RGB y alpha por separado.
Todos
los
valores
GL_CONSTANT_COLOR,
GL_ONE_MINUS_CONSTANT_COLOR
y
GL_CONSTANT_ALPHA,
GL_ONE_MINUS_CONSTANT_ALPHA
permiten que se introduzca un color de fusión constante en la ecuación de fusión. Este color de fusión constante es inicialmente Negro (0.0f, 0.0f, 0.0f, 0.0f), pero puede cambiarse con la siguiente función: void glBlendColor(GLclampf rojo, GLclampf verde, GLclampf azul, GLclampf alpha);
1.3 – Uso de fusiones Las funciones vistas en los apartados anteriores se pueden utilizar para crear distintos tipos de efectos. A continuación se verán los más comúnmente utilizados.
1.3.1 – Transparencias
Es el uso más habitual de las mezclas. Si se desea dibujar una imagen compuesta por varios elementos translúcidos, se dibujará primero el fondo con los valores por defecto de los factores origen y destino. A continuación se modifican esos factores asignando al origen GL_SRC_ALPHA y al destino GL_ONE_MINUS_SRC_ALPHA, como se pudo ver en el primer apartado a cerca de las fusiones, dibujando las figuras partiendo de la más alejada hasta la más próxima (que será la última en ser dibujada).
10
Figura 2 – Ejemplo de transparencias
1.3.2 – Desvanecimiento
Partiendo de los factores usados al realizar las transparencias es muy sencillo hacer que un objeto desaparezca de la escena. Basta con indicar un valor alpha 0.0f a la figura, que asignará a la misma una transparencia total.
1.3.2 – Composición
Se puede representar una imagen compuesta a partir de otras dos en dos pasos. Primero se aplica el valor GL_ONE al factor origen, GL_ZERO al destino y se dibuja la imagen. Después se asigna GL_SRC_ALPHA al origen y GL_ONE_MINUS_SRC_ALPHA al destino y se dibuja la imagen con un factor alpha de 0.5f.
11
Figuras 3 y 4 – Ejemplo de composición
1.3.3 – Filtros de color
Para modular cada componente de color de forma individual potenciando o reduciendo
las
componentes
GL_ONE_MINUS_DST_COLOR
RGB
para
el
se
utilizan
origen
y
GL_DST_COLOR
o
GL_SRC_COLOR
o
GL_ONE_MINUS_SRC_COLOR para el destino. Este proceso se utiliza para el filtrado fotográfico de colores.
1.3.4 – Simulación de brochas y pinceles
Las fusiones se pueden utilizar para simular brochas que cubren una superficie con un determinado color de forma gradual. Se puede hacer que, por ejemplo, cada pincelada añada un 10% de color sobre un 90% del color original de la superficie donde se pinta, es decir, que cada pincelada añadiría un cierto valor de mezcla.
Para hacerlo, se utilizar el factor GL_SRC_COLOR sobre el origen. Modificando los valores de alpha a través de la imagen de la brocha se puede
12
simular el efecto de añadir más color en el centro que en los extremos, con los que se obtiene la forma de un pincel antiescalonado.
De la misma forma se puede hacer un borrador, asignando los valores de color del fondo.
1.3.4 – Antiescalonado (Antialiasing o Suavizado)
Un efecto muy importante para el que se emplean las fusiones es el de suavizado (o antiescalonado), que se utiliza, como su propio nombre indica, para suavizar los bordes de las figuras representadas. Debido
a su
importancia, posteriormente se verá este tipo de efecto en profundidad.
Figuras 5 y 6 – Aplicación de suavizado
1.3.5 – Billboarding
Se puede conseguir que imágenes raster (trama) tengan un aspecto ligeramente tridimensional y de profundidad asignando diferentes valores alpha a los fragmentos individuales que componen la imagen. Este efecto mejora aplicando varias capas o cruces de la misma imagen.
Este método se puede utilizar, por ejemplo para dibujar árboles. Se puede dibujar un polígono con la forma de la copa del árbol y aplicarle una textura que represente las hojas del árbol. Después utilizando esta técnica se puede
13
conseguir que parezca una imagen tridimensional. De esta forma se puede crear un árbol mucho más rápidamente que haciendo un modelo tridimensional completo.
Figura 7 – Árbol con billboarding
1.4 – Manejo de la profundidad El orden en que se dibujan las cosas afecta al resultado final de las fusiones. Cuando se representan objetos traslúcidos en tres dimensiones se obtienen resultados diferentes en función del orden en que se dibujen los elementos.
Para solucionar este problema se dispone del búfer de profundidad (ZBuffer). Este búfer supervisa la distancia entre el punto de vista y la parte del objeto que ocupa un determinado píxel en una ventana de la pantalla. Cuando se asigna un color a dicho píxel sólo se dibuja si el objeto está más cerca del punto de vista, almacenando el valor de profundidad en el búfer. Utilizando este búfer se asegura no representar innecesariamente las partes ocultas de las superficies, y por tanto, no se utilizan en las fusiones.
Es muy importante el uso de este búfer en las escenas que muestran tanto objetos traslúcidos como opacos para eliminar las superficies ocultas tras los elementos opacos. Si una figura opaca oculta a otros objetos, el búfer de
14
profundidad se encarga de eliminar la figura más lejana. En cambio, si es una figura traslúcida la que está delante de otros objetos, habrá que realizar la fusión de la figura con los que haya detrás.
Es sencillo establecer el orden correcto en que se dibujan los objetos si es una escena estática, pero si el punto de vista o los objetos se mueven, puede suponer un problema. Por ello es conveniente usar el búfer de profundidad para evitar estos problemas.
La técnica de comprobación de la profundidad se maneja con las siguientes funciones: glEnable(GL_DEPTH_TEST); para activar la comprobación de profundidad. glDisable(GL_DEPTH_TEST); para desactivarla.
La condición de validación según la profundidad se calcula con la siguiente función: glDepthFunc(GLenum tipo); donde tipo es el tipo de condición.
Tipo GL_NEVER GL_LESS
Significado Los fragmentos nunca pasan la prueba de profundidad. Los fragmentos sólo pasan la prueba de profundidad si el valor z entrante es menor que el valor z presente en el búfer de profundidad. Éste es el valor predeterminado.
GL_LEQUAL
Los fragmentos sólo pasan la prueba de profundidad si el valor z entrante es menor o igual que el valor z presente en el búfer de profundidad.
GL_EQUAL
Los fragmentos sólo pasan la prueba de profundidad si el valor z entrante es igual que el valor z presente en el búfer de profundidad.
GL_GREATER
Los fragmentos sólo pasan la prueba de profundidad si el valor z entrante es mayor que el valor z presente en el búfer de profundidad.
GL_NOTEQUAL Los fragmentos sólo pasan la prueba de profundidad si el valor z entrante es distinto que el valor z presente en el búfer de profundidad.
GL_GEQUAL
Los fragmentos sólo pasan la prueba de profundidad si el valor z entrante es mayor o igual que el valor z presente en el búfer de profundidad.
GL_ALWAYS
Los
fragmentos
siempre
15
pasan
la
prueba
de
profundidad,
independientemente del valor z. Tabla 4 – Manejo de la profundidad (glDepthFunc)
Para evitar los problemas con las fusiones y la profundidad, es recomendable pintar en primer lugar los objetos opacos y dibujar los objetos comenzando por los que se encuentran al fondo para continuar sucesivamente con los objetos a medida que van estando más próximos al punto de vista.
Esto no siempre puede realizarse, porque se enmarca casi exclusivamente en la representación estática, así que se recomienda la activación de la comprobación de profundidad cuando se incluyan movimientos de los objetos o del punto de vista.
1.5 – Capas ocultas de los objetos Cuando se representan objetos translúcidos tridimensionales hay que tener en cuenta las siguientes capas: Capa delantera visible: la porción que se aprecia en primer plano. Parte posterior de la capa delantera: el interior de la capa delantera visible. Parte anterior de la capa trasera: el interior de la capa trasera. Parte posterior de la capa trasera. El mayor grado de realismo se consigue con el uso de tarjetas gráficas con capacidades para el almacenamiento de varios búfer de profundidad.
En algunos casos, las características del objeto hacen que haya que eliminar el dibujo de sus capas ocultas (cuando esas capas tengan un grosor mínimo). Un ejemplo muy claro de este caso es la representación de una burbuja. Al aplicar el efecto de las fusiones de transparencia se muestra no sólo la transparencia, sino también los brillos y reflejos correspondientes a las cuatro capas de la esfera.
16
Para usar esta característica se usan las siguientes funciones: glEnable(GL_CULL_FACE); para habilitar el efecto de representación de capas ocultas. glDisable(GL_CULL_FACE); para deshabilitar el efecto.
17
2 – Antiescalonado (Antialiasing o Suavizado) Cuando representamos imágenes en la pantalla un punto se representa como mínimo por un píxel que suelen tener forma cuadrática o casi cuadrática. De hecho debido a la resolución de pantalla varios puntos pueden ser representados por el mismo píxel con lo que líneas que tienen distinto ángulo pueden tener una representación similar al ser formadas por puntos situados en los mismos píxeles. Esto produce que cuando pintamos líneas oblicuas se vea muy claramente la división de colores entre la línea y el fondo, observándose los bordes dentados. Estos bordes dejan descubrir al observador que la imagen esta claramente generada por ordenador con lo que se pierde la sensación de realidad que queremos que tenga la imagen; este realismo es muy deseado.
Figura 8 – Ejemplo de bordes dentados
Para eliminar los bordes dentados se utiliza el suavizado para fundir el color de lo que queremos pintar con el color de destino del píxel y los píxeles próximos, esto consiste en difuminar ligeramente los colores del píxel hacía los píxeles próximos a los bordes.
Para realizar el suavizado se activan las mezclas estableciendose la misma función de fusión que para la transparencia:
glEnable(GL_Blend); glBlenfunc(Gl_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
18
La ecuación de fusión utilizada será la predeterminada no es necesario cambiarla.
Seguidamente
se
activa
el
suavizado
también
con
glEnable
seleccionando:
glEnable(GL_POINT_SMOOTH); // Suavizar puntos glEnable(GL_LINE_SMOOTH); // Suavizar líneas glEnable(GL_POLYGON_SMOOTH);
//
Suavizar
bordes
de
polígono
Finalmente con glHint podemos especificar el algoritmo deseado para realizar el suavizado:
glHInt (GLenum Objetivo,Glenum metodo)
En Objetivo podemos introducir:
Objetivo
Significado
GL_LINE_SMOOTH_HINT El tipo de suavizado
GL_POINT_SMOOTH_HINT
GL_POLYGON_SMOOTH_HINT
Para especificar la calidad de la
GL_FOG_HINT
niebla, por píxel (mayor coste mejor calidad) o por vértice
GL_PERSPECTIVE_CORRECTION_HINT
Para
especificar
la
calidad
de
interpolación en colores y texturas
Tabla 5 –Objetivos
19
En método seleccionaremos:
Método
Significado
GL_FASTEST
El de mayor rendimiento
GL_NICEST
El de mayor calidad
El que se pueda
GL_DONT_CARE
Tabla 6 – Metodos
Finalmente decir que si queremos desactivar el suavizado usaremos
glDisable (tipo de suavizado)
Figura 9 – Puntos sin suavizado
20
Figura 10 – Ejemplo de suavizado en puntos
Figura 11 – Ejemplo de suavizado en lineas
El cono rojo esta suavizado mientras que antes de pintar el verde se desactivo el suavizado.
21
En la función Iniciar que se ejecuta al comenzar el programa activamos las mezclas, seleccionamos la función de mezclas y el algoritmo a utilizar. En la función Mostrar que genera la escena se activa y desactiva el suavizado previamente a pintar la figura deseada (con o sin suavizado). void CALLBACK Iniciar(void) { glEnable(GL_BLEND); //Activar mezclas glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //Tipo de mezcla glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE); //Aplicar mezclas como sea glLineWidth(1.5); glClearColor(0.0, 0.0, 0.0, 0.0); //Color de fondo negro }
void CALLBACK Mostrar(void) { //Limpiado de los buffers de color y profundidad glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glRotatef(xRot, 1.0f, 0.0f, 0.0f); glRotatef(yRot, 0.0f, 1.0f, 0.0f); //Cono rojo suavizado glTranslatef(-0.9f, 0.0f, 0.0f); glColor4f(1.0, 0.0, 0.0, 1.0); glEnable(GL_LINE_SMOOTH); //Activamos suavizado auxWireCone(0.7,1); //Cono verde no suavizado glTranslatef(1.8f, 0.0f, 0.0f); glDisable(GL_LINE_SMOOTH); //Desactivamos suavizado glColor4f(0.0, 1.0, 0.0, 1.0); auxWireCone(0.7,1); glPopMatrix(); glFlush(); } Tabla 7 – Fragménto de código fuente de suavizado
2.1 – Suavizado en color indexado En el modo de color indexado no están habilitadas las mezclas por lo que tenemos que construir rampas de color para producir el difuminado del color. Normalmente se suele hacer en escala de grises pero si se hace con detalle se puede realizar con cualquier color. 22
2.2 – Muestreo múltiple El suavizado de puntos y líneas se admite ampliamente pero no todas las implantaciones de Opengl admiten el suavizado poligonal e incluso en aquellas que lo admiten no es el medio más conveniente para realizar el suavizado ya que se deberían ordenar todos los dibujos de adelante hacia atrás. Una alternativa para resolver esto es el muestreo múltiple, consistente en utilizar búfer que incluye los valores decolor de la profundidad y las plantillas; todos los primitivos se muestrean varias veces por píxel y el resultado se guarda en este búfer
Par activar el muestreo múltiple hay que tener un contexto que lo admita, por ejemplo en glut se establece con el campo de bits GLUT_MULTISAMPLE de la forma:
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH|GL UT_MULTISAMPLE) ;
Seguidamente activamos o desactivamos el muestreo con:
glEnable(GL_MULTISAMPLE) o glDisable(GL_MULTISAMPLE)
Una última aclaración es que si se activa el muestreo múltiple se ignoran los suavizados de líneas, puntos y polígonos por lo que lo más conveniente es dibujar primero lo que queramos que tenga suavizado y después activar el muestreo y dibujar seguidamente lo que creamos necesite el muestreo múltiple ya que los cambios de estado pueden ser costosos en cuanto al rendimiento.
23
3 – La niebla La niebla es un efecto de openGL que simula la limitación de visibilidad, consiguiéndose la fusión del color especificado para la niebla en el elemento geométrico una vez efectuados los cálculos del color. Para utilizar las nieblas deben
aplicarse las funciones de OpenGL: glEnable(GL_FOG); para habilitar las nieblas. glDisable(GL_FOG); para deshabilitar las nieblas.
Para cambiar el comportamiento de las nieblas deben aplicarse las variantes de la función glFog de OpenGL: void glFogi(GLenum paname, GLint param); void glFogf(GLenum paname, GLfloat param); void glFogiv(GLenum paname, Glint* param); void glFogfv(GLenum paname, GLfloat* param);
Con todo ello se conseguirá un efecto 3D, gracias a que los objetos mas alejados geométricamente de la cámara, irán “desapareciendo” en función de la distancia.
Para hacer distintas escalas de niebla se emplean las ecuaciones de niebla. Estas calculan un factor de niebla entre 0 y 1 en función de la progresión de la distancia. Existen tres ecuaciones de niebla para conseguir distintos efectos en función de la profundidad, considerando densidades de nieblas: Modo de niebla
Ecuación de niebla
GL_LINEAR
f=(fin – c)/(fin – inicio)
GL_EXP
f=exp(-d * c)
GL_EXP2
f=exp(-(d * c)^2) Tabla 8 – Ecuaciones de niebla
24
Donde c es la distancia del fragmento al punto visual, fin es la distancia GL_FOG_END, inicio es la distancia GL_FOG_START y d la densidad de la niebla. Para emplear una u otra ecuación bastara con introducirla como param en la función glFog vista anteriormente.
En la figura 3.2 se puede apreciar el comportamiento de la niebla generado por las distintas ecuaciones:
Figura 12 – Comportamiento de ecuaciones de niebla
El factor f de niebla se utiliza para obtener el color definitivo aplicando la siguiente ecuación: C = F*Ci + (1 - f)*Cf donde Ci representa el color del objeto y Cf el color de la niebla definido utilizando GL_FOG_COLOR.
A continuación se puede observar el comportamiento de la niebla según la ecuación empleada:
25
Figura 13 – Sin niebla
Figura 14 – Niebla generada con la ecuación GL_LINEAR
Figura 15 – Niebla generada con la ecuación GL_EXP
Figura 16 – Niebla generada con la ecuación GL_EXP2
26
Las partes interesantes del código son las siguientes: //Inicialización
GLfloat final = 25.0; GLfloat densidad = 0.1; GLint fogMode = GL_EXP2; GLfloat fog_color[4] = { 0.5, 0.5, 0.5, 1.0}; //Inicializacion de las nieblas
glFogi(GL_FOG_MODE, GL_EXP); glFogfv(GL_FOG_COLOR, fog_color); glFogf(GL_FOG_START, 0.0); glFogf(GL_FOG_END, final); glFogf(GL_FOG_DENSITY, densidad); glClearColor(0.5, 0.5, 0.5, 1.0); glEnable(GL_FOG); //activación
glFogf(GL_FOG_START, 0.0); glFogf(GL_FOG_END, final); Tabla 9 – Fragménto de código fuente de niebla
27
4 – Búfer de acumulación El búfer de acumulación ha sido creado para la integración de múltiples imágenes. Esto se consigue mediante la acumulación, en el búfer de acumulación, de copias del contenido del búfer de color, fusionándose así el contenido del búfer de color con el contenido acumulado en el búfer de acumulación. Tras acabar la acumulación de la imagen, se copiara de nuevo el contenido del búfer de acumulación al búfer de color.
Para manejar este búfer se emplea las funciones de OpenGL: glClearAccum();para la limpieza del búfer glAccum(GLenumm operación,GLfloat valor);
El parámetro valor será el valor en punto flotante que se usa para escalar la operación, las posibles operaciones que se pueden realizar son:
operación
Acción
GL_ACCUM
Escala los valores del búfer de color por un valor y los añade al contenido actual del búfer de acumulación.
GL_LOAD
Escala los valores del búfer de color por un valor y reemplaza al contenido actual del búfer de acumulación.
GL_RETURN
Escala los valores del búfer de color por un valor y copia los valores del búfer de color.
GL_ADD
Escala los valores del búfer de color por un valor y lo añade al contenido del búfer de acumulación.
GL_MULT
Escala los valores del búfer de color por un valor y lo guarda en el búfer de acumulación. Tabla 10 – Operaciones del búfer de acumulación.
A continuación se puede observar como se comporta el búfer de acumulación en los ejemplos Depth of Field y Motion Blur:
28
Figura 17 – Vista antes la acumulación
Figura 18 – Vista tras el volcado del búfer (Depth of Field)
29
Figura 19 – Vista tras el volcado del búfer (Motion Blur)
En ambos casos se parte de la misma imagen inicial, en el primer caso toda la habitación (salvo la esfera) es movida a partir de un corte horizontal y en el segundo caso solo se mueve la espera. Después de cada movimiento, se almacena la situación en el búfer de acumulación y al final se vuelca el contenido de éste, dotando a la imagen con una sensación de movimiento en los lugares donde antes estuvo la imagen.
30
5 – Otras operaciones de color A parte de admitir las fusiones, la niebla y el búfer de acumulación, OpenGL también admite otros medios de ajuste de valores y fragmentos del color cuando se describen en el búfer de color.
5.1 – Máscaras de color Una vez calculado un color final y antes de escribirlo en el búfer de color, OpenGl permite enmascarar uno o más canales del color con la siguiente función: void glColorMask(GLboolean rojo, GLboolean verde, GLboolean azul, GLboolean alpha);
Cada parámetro de la función se corresponde con un canal. El paso de GL_TRUE permite la escritura en ese canal, mientras que GL_FALSE evita la escritura.
5.2 – Operaciones de color lógicas La ejecución de operaciones lógicas entre los colores de origen y destino se permiten en muchos gráficos y APIs 2D. OpenGL también admite este tipo de operaciones 2D mediante la siguiente función: void glLogicOp(GLenum op);
Los modos de operación lógica que puede recibir como parámetros la función anterior son los siguientes:
Valor del argumento
Operación
GL_CLEAR
0
AL_AND
S & D
31
GL_AND_REVERSE
S & -D
GL_COPY
S
GL_AND_INVERTED
-S & D
NOOP
D
XOR
S XOR D
OR
S | D
NOR
-(S | D)
GL_EQUIV
-(S XOR D)
GL_INVENT
-D
GL_OR_REVERSE
S | -D
GL_COPY_INVERTED
-S
GL_OR_INVERTED
-S | D
GL_NAND
-(S & D)
SET
Todo 1
Tabla 11 – Operaciones de color lógicas (glLogicOp)
La operación lógica se encuentra desactivada de forma predeterminada y se controla con las siguientes funciones: glEnable(GL_COLOR_LOGIC_OP); para activar la operación lógica. glDisable(GL_COLOR_LOGIC_OP); para desactivarla.
5.3 – Prueba Alpha La prueba alpha permite indicar que se descarte fragmentos cuyo valor de alpha falle en la prueba de comparación alpha. Los fragmentos que se descarten no se escriben en los búferes de color, profundidad, plantillas o acumulación.
Esta opción es muy útil para mejorar el rendimiento al descartar valores y permite elementos del búfer de profundidad que pueden no ser visibles en el búfer de color por tener un valor de alpha muy bajo.
32
La activación y desactivación de la prueba alpha se realiza con las siguientes funciones: glEnable(GL_ALPHA_TEST); para activar la prueba alpha. glDisable(GL_ALPHA_TEST); para desactivarla.
El valor de la prueba alpha y de la función de comparación se especifican con la siguiente función: void glAlphaFunc(GLenum tipo, GLclampf ref);
El valor de referencia ref se ajusta al rango 0.0f a 1.0f. La función de comparación se especifica con los siguientes valores:
Tipo GL_NEVER GL_LESS GL_LEQUAL GL_EQUAL
Significado Nunca pasa. Pasa si el fragmento es menor que el valor de referencia. Pasa si el fragmento es menor o igual que el valor de referencia. Pasa si el fragmento es igual que el valor de referencia.
GL_GREATER
Pasa si el fragmento es mayor que el valor de referencia.
GL_NOTEQUAL
Pasa si el fragmento es distinto que el valor de referencia.
GL_GEQUAL
Pasa si el fragmento es mayor o igual que el valor de referencia.
GL_ALWAYS
Pasa siempre. Tabla 12 – Prueba Alpha (glAlphaFunc)
5.4 – Tramado El tramado es una operación que permite mostrar un sistema con un pequeño número de colores discretos para simular la presentación de un rango de colores mucho más amplio. Por ejemplo, se puede simular un color gris mostrando una mezcla de puntos blancos y negros.
Esta técnica es útil para mostrar sistemas que sólo admiten 8 o 16 bits de información de color.
33
El tramado se encuentra activado de forma predeterminada, y se puede controlar con las siguientes funciones: glEnable(GL_DITHER); para activar el tramado. glDisable(GL_DITHER); para desactivarlo.
En sistemas de presentación con una mayor resolución de color puede que no se necesite el tramado y puede desactivarse para conseguir ahorros de rendimiento considerables.
34
Conclusiones En Opengl podemos conseguir efectos espectaculares y dotar de mayor realismo a las imágenes usando las mezclas y las nieblas y con el suavizado eliminar la apariencia cuadrática (lo que también hace más reales las imágenes) Para aplicar estas herramientas debemos tener en cuenta: Las mezclas están sólo habilitadas en modo RGBA aunque de forma excepcional el antiescalonado se puede realizar en modo indexado definiendo correctamente una rampa de color por la que desplazarnos de forma suave Podemos
seleccionar
la
implementación
para
los
efectos
de
antiescalonado y nieblas; no siempre es aconsejable utilizar el mejor algoritmo, ya que puede afectar seriamente al rendimiento de la animación. Se debe activar la comprobación de profundidad para no representar las partes ocultas y que estas no afecten a las mezclas y a las nieblas No todas las implementaciones de Opengl permiten la realización de todos los efectos y la utilización de algunos efectos desactiva otros.
35
Bibliografía Richard S. Wright, Benjamín Lipchak, OpenGL Superbible. Ediciones Anaya Multimedia (Grupo Anaya S.A.), 2005.
Mason Woo, Jackie Neider, Tom Davis, OpenGL Programming Guide, 2nd Edition, Addison-Wesley Publishing Company, 1997.
Silicon Graphics, Inc., OpenGL Reference Manual, The Official Reference Document for OpenGL, Release1, Addison-Wesley Publishing Company, 1994.
Alan Oursland, Using OpenGL in Visual C++, Interface Technologies, Inc., 2000.
http://www.opengl.org
http://ponton.dcs.fi.uva.es/web/programacion/opengl/index2.html
http://www.sgi.com/products/software/opengl/examples/index.html
36