You are on page 1of 61

Luces

y
Lámparas

Universidad de Salamanca
Departamento de Informática y Automática
Informática Gráfica

Mercedes Sánchez Marcos


Almudena Sardón García
Contenido

1. Introducción ..................................................................................................... 1
2. Los modelos de iluminación .......................................................................... 3
2.1. Luz ambiente ............................................................................................... 5
2.2. Reflexión difusa ........................................................................................... 5
2.3. Reflexión especular ..................................................................................... 6
2.4. Modelo de Pong .......................................................................................... 6
2.5. Modelo básico de iluminación ..................................................................... 9
2.6. Modelo básico de iluminación con n fuentes múltiples ............................... 9
2.7. Atenuación de la intensidad a lo largo de la distancia a la luz .................. 10
3. Rendering. Determinación de superficies visibles .................................... 11
3.1. Método de la normal ................................................................................. 11
3.2. Método de buffer con profundidad. Buffer Z ............................................. 12
3.3. Algoritmo del pintor ................................................................................... 13
3.4. Método de traza de rayos ......................................................................... 14
4. Métodos de rendering de los polígonos ..................................................... 15
4.1. Sombreado con intensidad constante ....................................................... 15
4.2. Método de sombreado de Gouraud (Gouraud Shading) ........................... 15
4.3. Método de sombreado de Phong (Phong Shading) .................................. 16
5. Rendering con alta calidad ........................................................................... 17
5.1. El método de ray-tracing ........................................................................... 17
5.2. El método de radiosidad ........................................................................... 19
5.3. Método radiance ....................................................................................... 21
6. La iluminación en OpenGl ........................................................................... 22
6.1. Tipos de iluminación en OpenGl ............................................................... 22
6.2. Características de las fuentes de luz ........................................................ 23
6.3. Vectores normales a una superficie .......................................................... 24
6.4. Colocar las luces ....................................................................................... 26
6.5. Atenuación de la distancia ........................................................................ 27
6.6. Área de cobertura ..................................................................................... 28
7. Los materiales en OpengGl .......................................................................... 29
7.1. Las propiedades de los materiales ........................................................... 29
7.2. La luz en los materiales ............................................................................ 29
7.3. Especificación de los materiales en OpenGL . ......................................... 30
8. Render óptimo en OpenGl ............................................................................ 32
8.1. Z-Buffer y superficies ocultas . .................................................................. 32
8.2. El canal alfa . .................................................. .......................................... 34
8.3. Efecto de niebla . .................................................. ................................... 35
9. Efectos de iluminación ................................................................................. 37
9.1. Componente especular . .................................................. ........................ 37
9.2. Luz especular . .................................................. ....................................... 38
9.3. Reflectancia especular . .................................................. ......................... 39
9.4. Técnicas de iluminación . .......................................................................... 40
9.5. Promedio normal .. 40
9.6. CUBE ENVIRONMENT MAPIN . .............................................................. 41
9.7. BI-DIRECTIONAL REFLECTANCE DISTRIBUTION FUNCTION ………. 42
10. Focos de luz . ................................................. ............................................... 47
10.1. Iluminación global . .......................................................................... 48
11. Sombras . ................................................. ..................................................... 51
11.1. Sombras proyectadas . .................................................................... 51
11.2. STENCIL BUFFER O BUFFER PLANTILLA . ................................. 51
12. Apéndice A . ................................................. ................................................. 54
12.1. Efectos de niebla . .................................................. ........................ 54
13. Conclusiones . .................................................. ..............................................
57
Luces y lámparas

1. INTRODUCCIÓN

En este capitulo se verá cómo actúa la luz al chocar con una superficie y cómo
OpenGL es capaz de representar la luz y todos sus fenómenos. Los primeros apartados son
mas teóricos y en ellos se verá cual es la composición de la luz, cómo actúa ésta al chocar
con otros cuerpos, etc. Todo desde un punto físico pero con vistas a lo que luego se usará
en OpenGL. A continuación, se irá introduciendo cómo se usa la luz para construir escenas.
Se explicarán los modelos de renderizado más usados, que posteriormente se usarán al
hablar de OpenGL. Más adelante, se empezará a ver cómo OpenGL hace uso de la
iluminación. Se hablará del modo de activar y desactivar la iluminación, de cómo se puede
crear una fuente de luz y de la manera en que ésta se puede colocar. También se hablará de
las propiedades de la luz y de una parte muy importante, que es cómo especificar las
propiedades de los materiales de la escena donde va a incidir la luz. Obviamente, la luz no
actúa de igual manera al chocar con un objeto que al chocar con otro. Por ejemplo, la luz no
se refleja del mismo modo en una barra de oro que en una manzana. Por ultimo, se tratarán
todos los efectos de iluminación que se pueden conseguir con OpenGL, que son bastantes.

Se empezará haciendo una pequeña introducción a los modelos de iluminación. Un


modelo de reflexión, representa la interacción o forma de actuar de la luz al llegar a una
superficie. Un modelo de iluminación, consiste en ver cómo se comporta la luz cuando sale
de una fuente de luz. Los modelos de iluminación y reflexión suelen ser muy sencillos. En
principio, se van a considerar modelos locales, es decir, modelos que tienen una fuente de
luz y una superficie. No se tendrá en cuenta la posición.

Figura 8.1

Cuando la luz llega un punto cumple una ecuación:


Luz incidente = luz reflejada + luz dispersa + luz absorbida + luz transmitida

Los algoritmos van a intentar representar todos estos parámetros de la luz. Los
factores de los que dependen los elementos de la ecuación son los siguientes:
• Longitud de la onda de la luz incidente.
• Rugosidad de la superficie.
• Tipo de material, para ver cuanta luz absorbe.
• Angulo de incidencia de la luz.

1
Luces y lámparas

Es obvio que todos estos elementos afectan al modo en que la luz actúa. Está claro
que cuanto más lejos esté la fuente de luz de un objeto menos luz le llega a ese objeto. Por
ello, es importante conocer la distancia a la que se encuentra la luz respecto de un objeto.
También es importante saber si una superficie es rugosa o no, ya que, en caso de serlo la luz
se dispersará en más direcciones al incidir en ella. Otro factor importante es el tipo de
material de un objeto. Al indicarlo es necesario especificar el color del material, el modo en
que la luz va a actuar al chocar con él, si el material es brillante o no, etc. También hay que
indicar el ángulo de incidencia de la luz. Cuanto mayor sea el ángulo de incidencia menos
luz se reflejara en el objeto.

2
Luces y lámparas

2. LOS MODELOS DE ILUMINACIÓN


El fenómeno de iluminación y reflexión indica cómo la luz interactúa con un sólido.
Se puede clasificar la luz en:
• Luz incidente.
• Luz de reflexión:
Luz difusa:
o Luz difusa global.
o Luz difusa local.
Luz especular.
• Luz de refracción.
• Luz de transmisión.

Figura 8.2

Los diferentes tipos de iluminación producen diferentes efectos. Estos direrentes


efectos de brillo y color se llaman reflectancia. El brillo de una superficie es regulado por
su orientación respecto al foco de luz. El ángulo entre los rayos de luz y la perpendicular de
la superficie determina en que medida la superficie aparecerá brillante a los ojos del
espectador. Esto es llamado a veces Ley del coseno de Lambert. La perpendicular de una
superficie es la línea que sale de la superficie plana con un ángulo de 90 grados respecto a
dicha superficie. A veces recibe el nombre de normal a la superficie.

Figura 8.3: El brillo de una


superficie se determina de
acuerdo con su orientación con
respecto de la fuente de luz.

3
Luces y lámparas

Una superficie plana aparecerá más brillante cuando su perpendicular apunte


directamente hacia el foco de luz. Cuanto mayor sea el ángulo entre la perpendicular de la
superficie y el rayo de luz, más apagada aparecerá. La superficie no reflejará la luz cuando
esté a más de 90 grados de los rayos de luz, ni tampoco cuando esté mirando hacia el lado
opuesto del foco luminoso. En tal caso, la superficie estaría solo iluminada por la luz
ambiental, no por la fuente de luz específica que se esté analizando.

Figura 8.4: Cuanto más grande sea


el ángulo entre la perpendicular a la
superficie y el rayo de luz, más
oscura aparecerá la superficie.

En el modelo básico de iluminación se consideran sólo las reflexiones. La


intensidad de iluminación de cada punto de las superficies será por tanto:

Intensidad = luz_ambiente + luz_difusa + luz_especular =


I ambiente + I difusa + I especular

4
Luces y lámparas

2.1. LUZ AMBIENTE

La luz distribuida es una fuente de luz amplia que está relativamente cerca del
objeto. Una bola de ping-pong que descansa sobre una mesa cerca de una ventana orientada
al norte es un buen ejemplo de luz distribuida. Si la bola estuviera iluminada por un tubo de
luz fluorescente, estaría iluminada por luz distribuida. La luz distribuida, también llamada
banco de luz, produce unas sombras determinadas. La luz que vemos en un día encapotado
pero brillante o en un día nebuloso es luz distribuida. Se dice que un modelo sólido bañado
por luz distribuida muestra reflectancia ambiental o reflexión ambiental.
La luz ambiente es el resultado de la reflexión múltiple de todos los objetos en la
escena. Viene representada por la siguiente ecuación:

I ambiente = k a I a

donde k a es la constante de ambiente del objeto, dependiente del material y I a se


define por el usuario para dar el efecto de luz de fondo de la escena.

2.2. REFLEXION DIFUSA

La luz ambiental es la luz indirecta, por ejemplo la luz que se ve en un día muy
encapotado o nuboso es la luz ambiental. La luz que hay en el interior de una habitación
con una ventana orientada al norte es, normalmente, luz ambiental. En teoría, la luz
ambiental no produce sombras en el mundo real, sin embargo, es a menudo más fuerte
cuando viene de arriba, de manera que algunas veces se producen sombras suaves y
delicadas. En el modelo no se ven matices de luz o puntos brillantes porque no hay focos de
luz intensos. Un modelo sólido bañado en luz ambiental se dice que muestra reflectancia
difusa o reflexión difusa.

La luz difusa es la que la superficie de un objeto refleja y dispersa en todas las


direcciones hacia fuera de la cara del objeto debido a la iluminación directa. Es la
responsable del color del objeto. Es una característica propia de los objetos mates tales
como paredes, telas, papel, etc.

Figura 8.5

5
Luces y lámparas

Ley de Lambert: “la componente difusa de la luz reflejada por una superficie es
proporcional al coseno del ángulo de incidencia”.

I difusa = k d I l cos θ = k d I l (N·L)


donde:
k d es la constante difusa del objeto, dependiente del material del mismo.
I l es la intensidad de la fuente de luz puntual (point light source).
L es el vector unitario de la luz incidencia.
N es el vector unitario de la normal a la superficie en este punto.
θ es el ángulo entre N y L.

2.3. REFLEXIÓN ESPECULAR

Un punto de luz es una sola fuente de luz, como, por ejemplo, una bombilla, una
linterna, o incluso el sol. Un punto de luz produce un fuerte matiz de luz y marcadas
sombras. El matiz de luz es llamado reflexión especular. Mientras que la reflectancia difusa
y la reflectancia ambiental normalmente son varias sombras del color del objeto, las
reflexiones especulares (brillo) son normalmente del mismo color que la fuente de luz.
La luz especular es la luz con alta intensidad que una superficie brillante refleja a lo
largo de la dirección del espejo. Esta luz es la que produce el efecto espejo. Además tiene el
color de la fuente de luz.
Cabe destacar que la reflexión especular depende de la posición del observador. En
las superficies normales el brillo decae cuando el observador se aleja de la dirección de
reflexión perfecta (R en la figura 8.6).

2.4. MODELO DE PHONG

Según este modelo, la luz en un punto tiene tres componentes y es igual a la suma
de las tres:
Luz difusa + luz especular + luz ambiental

El modelo de Phong consiste en modelar el efecto de la luz especular. Propone


potencias del coseno de (R·V) para determinar la intensidad del brillo visto.

Figura 8.6

6
Luces y lámparas

N: vector unitario de la normal de la superficie.


L: vector unitario de la luz incidente.
R: vector unitario de la dirección de la reflexión especular.
V: vector unitario de la dirección del observador.
θ: ángulo de incidencia que es igual al ángulo de reflexión especular.
α: ángulo de observación entre R y V.

El efecto de espejo se puede observar alrededor de una zona de la dirección R si la


superficie no es perfectamente especular. El modelo de Phong modela la luz especular
como:
I esp = k s I l cos n φ = k s I l (V·R)n

donde,
n es el parámetro de reflexión especular (desde 1 hasta mas que 100). Si la
superficie es más brillante, n es mas grande.
φ es el ángulo entre R y V, es decir la desviación de la dirección de reflexión
perfecta.
k s es la constante de reflexión especular del objeto, dependiente del tipo del
objeto.

Figura 8.7

Figura 8.8

Para calcular R se puede tener en cuenta la siguiente relación y realizar los cálculos
oportunos.

7
Luces y lámparas

L+R
=N
|L+R|

Figura 8.9

En el caso de superficie curva, N se cambia según el lugar del punto. Se complica el


calculo de R.
Se puede simplificar el calculo de V · R de la siguiente forma:
Se utiliza H · N para sustituir R · V , y el cosα sustituye al cos φ
H es el vector equidistante entre L y V. Dicho de otra forma, es la orientación de la
zona de máximo brillo (highlight).
L +V
H=
| L +V |

Figura 8.10

En el caso de que el observador y la luz estén lejos, L y V son constantes. Esto


significa que:

I especular = k s I l (V · R)n = k x I l (N · H)n


La componente difusa toma el color de la superficie. Y el rayo reflejado
(componente especular), toma el color de la fuente de luz. Se obtiene de esta forma la
siguiente ecuación:

8
Luces y lámparas

I d = I i k d cos θ
donde,
I d es la luz difusa.
I i es la luz incidente.
k d es la constante de difusión.
Se obtiene esta otra ecuación:

I d = I i k d (N · L)

Si únicamente se consideran la componente difusa y la componente especular, el


objeto queda como si estuviera iluminado por un flash. Es decir, tenemos objetos muy
brillantes y otros objetos que apenas están iluminados. Para evitar esto, se usa la tercer
componente, que es la componente ambiental:

Ig=Iaka
En la componente ambiental se engloban las otras componentes. Resumiendo el
modelo de Phong, se puede decir que las fuente de luz son puntuales. Las componentes de
difusión y especular se consideran como componentes locales. Todos los factores que
aparecen en la fórmula son empíricos. La componente difusa va a ser del color de la
superficie. La componente reflejada es del color de la fuente de luz.

2.5. MODELO BÁSICO DE ILUMINACIÓN

Considerando el modelo de Phong se puede definir el modelo básico de iluminación


de la siguiente forma:

I = I ambiente + I difusa + I especular = k a I a + k d I l (N · L) + k s I l (N · H)n

2.6. MODELO BÁSICO DE ILUMINACIÓN CON n FUENTES MÚLTIPLES

De la misma forma, se puede definir el modelo básico de iluminación si se dispone


de n fuentes de luz:

∑ II { kd(N · Ll) + ks (N · Hl)


n
I = Iambiente + Idifusa + Iespecular = ka Ia + }
l=1

9
Luces y lámparas

2.7. ATENUACIÓN DE LA INTENSIDAD A LO LARGO DE LA DISTANCIA A LA


LUZ

A veces se usa un término de atenuación. Para tener en cuenta que los objetos más
cercanos son más brillantes que los más lejanos se usa esta atenuación.
Según la ley de física, el factor de la atenuación es 1/d2, donde d es la distancia
recorrida por la luz.
Este factor tiene el problema de que se atenúa demasiado rápido para el dibujo. Por
ello, se utiliza una función de atenuación empírica:
El modelo básico con atenuación de distancia y fuentes múltiples:

∑ f(dl)II { kd(N · Ll) + ks (N · Hl)


n
I = ka Ia + }
l=1
donde,
⎛ 1 ⎞
f (d ) = min⎜⎜ ⎟
2 ⎟
⎝ 0
a + a1 d + a 2 d ⎠
a0 puede impedir que f(d) sea muy alto cuando d es muy bajo.
f(d) se limita a no ser mas grande de 1.

10
Luces y lámparas

3. RENDERING. DETERMINACIÓN DE SUPERFICIES VISIBLES


“Rendering” es el proceso de usar el modelo de un objeto o escena para crear su
imagen, o sea un “bitmap” de “pixeles”. Para ello, se toma un modelo tridimensional y se
obtiene una imagen bidimensional. Esto involucra proyecciones (ortográficas o de
perspectiva). Al principio sólo se dibujaban las aristas de los objetos, obteniendo un
“render” alambrado. Un problema de esto era que las imágenes así generadas eran
confusas.

Una parte importante de la generación de gráficos realistas es la identificación de las


partes de una escena que son visibles desde un punto de vista determinado. Hay muchos
planteamientos que se pueden manejar para solucionar este problema y se han desarrollado
algunos algoritmos con el fin de identificar con eficiencia objetos visibles para diferentes
tipos de aplicaciones. Algunos métodos requieren mucha memoria, otros implican mucho
tiempo de procesamiento y otros sólo se aplican en objetos específicos.
Seleccionar un método para una aplicación en particular puede depender de factores
como la complejidad de la escena, el tipo de objetos a desplegar, el equipo del que se
dispone y la necesidad de generar despliegues gráficos animados o estáticos. Los diversos
métodos de algoritmos se conocen como métodos de detección de superficie visible o como
métodos de eliminación de superficies ocultas (a pesar de que puede ser diferente
identificar superficies visibles y eliminar superficies ocultas).
Los algoritmos de detección de superficies visibles se pueden clasificar dependiendo de
si manejan definiciones de objetos de manera directa o con sus imágenes proyectadas. Estos
planteamientos se denominan métodos de objeto-espacio y métodos de imagen-espacio,
respectivamente.

• Imagen-espacio: Se basan en la imagen que tenemos del objeto. Van a ir viendo


en la pantalla qué objeto es visible y cuál no. La decisión se toma a nivel de
pixel. Se toma un pixel y se dice qué color se le pone. Son muy engorrosos.
• Objeto-espacio: La decisión se toma con la propia definición de los objetos. Hay
que tener en cuenta qué objetos están delante de otro.

A pesar de que hay importantes diferencias en el planteamiento básico que se utiliza en


los diversos algoritmos de detección de superficie visible, la mayoría de éstos usan métodos
de clasificación y coherencia para mejorar el resultado. La clasificación sirve para hacer
comparaciones de la profundidad al ordenar las superficies visibles en una escena de
acuerdo con su distancia desde el plano de visión.

3.1. METODO DE LA NORMAL

Este método se aplica en figuras planas. Permite ocultar la mitad de las superficies que hay
en escena. Para un poliedro converso, este método permite definir todas las superficies
ocultas. Se basa en calcular la normal a todas las superficies. Las normales cuya proyección
en la dirección de visión sean positivas son superficies ocultas. Y las que son negativas son
visibles.

11
Luces y lámparas

Figura 8.11: Se hace el producto


escalar del vector de visión por el
vector normal de cada cara, para ver si
es positivo o negativo

Si un objeto es poliédrico, las caras de dicho objeto, son totalmente visibles o


totalmente ocultas. Con este algoritmo se determinan las caras visibles de dicho objeto. Si
hay varios objetos de este tipo, entonces se realiza el algoritmo para todos los objetos. Lo
que hace este algoritmo es eliminar la cara posterior de los objetos.

3.2. METODO DE BUFFER CON PROFUNDIDAD. BUFFER Z

El método Z-Buffer de eliminación de superficies ocultas es un método de espacio-


imagen basado en el buffer de pantalla del adaptador de gráficos. Se mantiene una base de
datos que corresponde a cada pixel de la pantalla de visión. Por ejemplo, si se esta usando
el modo gráfico de 640*480 de 16 colores, se necesitará una base de datos de 614400 bytes,
lo bastante para mantener 307200 enteros.
La base de datos contiene información sobre la profundidad de la coordenada visual
z para cada parte de un objeto que ocupe una posición determinada de pixel. Cuando se
están preparando las superficies o los objetos para ser visualizados, el programa primero
comprueba el buffer z. Si al pixel que se está considerando le ha sido asignado un valor z
superior a la superficie que se está considerando, entonces no se realiza ningún cambio
sobre el pixel. Si el valor de z de la superficie es mayor que el valor en el buffer z para ese
pixel en concreto, entonces la superficie está más cerca del punto de vista. En este caso,
habrá que actualizar el pixel y el buffer z, por supuesto.
Para cada pixel (x,y) de la imagen, el punto con menor coordenada z es visible.

12
Luces y lámparas

Figura 8.12

Para implementar este método, la mayoría de los sistemas usa dos buffer. Para cada
pixel se almacena en el primer buffer, llamado buffer de profundidad, la coordenada z. En
otro buffer, llamado de redundancia, se almacena bien el color o bien la intensidad. El
inconveniente de este método es que, si se usa una pantalla de 1024*1024, se utiliza mucha
memoria. Partiendo de este método se ha llegado a definir modelos, que lo que hacen es un
muestreo a escala subpixel. Se divide el pixel en un rectángulo de 4*8. Se analiza el color
de los 32 subpixel y luego se considera el color medio que define al pixel. De esta forma si
se dispone de dos figuras superpuestas, se obtendrá una mezcla. Se muestrea con un 1/32 de
pixel en lugar de un pixel. La media de los 32 colores será el color predominante.
El método del Z-Buffer es infalible para todas las escenas 3D, no importa cuál sea
su complejidad. Sin embargo, es de memoria intensiva y de informatización también
intensiva.
Cuando se está dibujando un plano, se debe utilizar trigonometría y geometría muy
complicadas para determinar las coordenadas x, y, z de la parte de la superficie del plano
que será mapeada en un pixel determinado. Entonces la coordenada z debe compararse con
la coordenada z para el pixel de la base de datos del buffer z. La generación de una escena
compleja en el ordenador personal puede llevar horas, aunque los resultados son
impecables.

3.3. ALGORITMO DEL PINTOR

Se basa en pintar primero el fondo. Sobre este fondo, se dibuja la siguiente figura.
Si sobre esa figura va otra, se dibujaría encima. Es decir, se ordenan todas las figuras según
su distancia al plano de visión. Luego se van pintando todas, empezando por las alejadas.

13
Luces y lámparas

Figura 8.13

Este método tiene un inconveniente cuando las superficies se oscurecen


alternativamente.

Figura 8.14

La figura 1 esta detrás de la figura 3. La figura 3 detrás de la figura 2. Y la figura 2


detrás de la figura 1. Cuando ocurre esto, este método tiene problemas. Lo que se hace es
dividir la figura en trozos. Si se divide la figura por la mitad, ya quedaría bien definida.

3.4. METODO DE TRAZA DE RAYOS

En este método lo que se hace es aplicar la definición del algoritmo de superficie


oculta (método de imagen-espacio). Para cada pixel se traza un rayo. Si no intercepta
ningún objeto se le da el color de fondo. Si intercepta un objeto, se le da el color del primer
objeto interceptado. Este método es muy lento. Pero tiene la ventaja de dar imágenes muy
realistas. Por ejemplo, usando varias fuentes de luz, se obtienen unos resultados muy
buenos, casi fotográficos.

14
Luces y lámparas

4. MÉTODOS DE RENDERING DE LOS POLÍGONOS


4.1. SOMBREADO CON INTENSIDAD CONSTANTE

Este método consiste en calcular una única intensidad para cada polígono. Una vez
calculada la intensidad de cada polígono, se visualizan todos los puntos del mismo
polígono con una única intensidad.
Este método es muy rápido y preciso si las luces y el observador están lejos. Pero
presenta el inconveniente de que hay discontinuidad de intensidad entre los polígonos. Este
método es el más ineficiente y menos usado de los tres.

4.2. METODO DE SOMBREADO DE GOURAUD (GOURAUD SHADING)

El método consiste en calcular la intensidad de los pixeles a lo largo de la línea de


escaneo por interpolación. Este método elimina la discontinuidad de la intensidad entre los
polígonos que presentaba el método anterior.
Para cada polígono hay que hacer los siguientes cálculos:
• Determinar el vector unitario de la normal de los vértices. Este vector es el
promedio de las normales de las caras que comparten el vértice.

∑N k
Nv = k =l
n

∑N
k =l
k

Figura 8.15

• Calcular la intensidad de cada vértice aplicando el modelo de iluminación.


• Interpolar linealmente las intensidades sobre las aristas del polígono.

y4 + y2 y + y4
I4 = I1 + 1 I2
y1 + y 2 y1 + y 2

Figura 8.16

• Interpolar las intensidades de los pixeles entre las aristas.

15
Luces y lámparas

x5 + x p x p + x4
Ip = I4 + I5
x5 + x 4 x5 + x 4

4.3. METODO DE SOMBREADO DE PHONG (PHONG SHADING)

Este método, en vez de interpolar las intensidades, lo que hace es interpolar las
normales para cada punto de la superficie. El método consistirá en realizar los siguientes
pasos:
• Paso 1. Determinar el vector unitario de la normal de los vértices. Este vector es
el promedio de las normales de las caras que comparten el vértice.
• Paso 2. Interpolar linealmente las normales sobre las aristas del polígono N1

y + y2 y +y
N= N1 + 1 N2
y1 + y 2 y1 + y 2

Figura 8.17

• Paso 3. Interpolar linealmente las normales de los pixeles entre las aristas.
• Paso 4. Aplicar el modelo de iluminación a lo largo de cada línea de escaneo
para calcular las intensidades de cada pixel.

Con este método es con el que se consiguen resultados mas realistas, pero tiene el
inconveniente de que necesita realizar entre 6 y 7 veces mas cálculos que para el método de
Gouraud.

16
Luces y lámparas

5. RENDERING CON ALTA CALIDAD

5.1. EL MÉTODO DE RAY-TRACING

El método de ray-tracing (rastreo de rayos) consiste en asignar la intensidad a cada


pixel según el efecto de todas las iluminaciones acumuladas en la escena hacia este pixel.
La idea del método es emitir un rayo de luz desde la pantalla a lo largo de la
dirección de observación hacia la escena 3D para buscar las contribuciones de iluminación
acumulada.

Figura 8.18

La ventaja del método consiste en combinar todos los cálculos siguientes en un solo
modelo:
• Eliminación de superficies invisibles
• Sombreado debido a la iluminación directa y local.
• Sombreado debido a la iluminación global.
• Cálculo de sombras.

Figura 8.19

17
Luces y lámparas

Hay que tener en cuenta unas consideraciones básicas antes de entrar con más
detalle en el método:
• El color y la intensidad de cualquier punto visible en la pantalla debe venir de
una superficie en la escena 3D.
• La dirección de rastreo: se puede encontrar en las contribuciones en el punto por
rastrear un rayo a través del sentido inverso desde el pixel a la escena.
• Si el rayo intersecciona con un objeto, el rayo es el resultado de la luces que el
punto de intersección recibe. La contribución de la luz en este punto se puede
rastrear más lejos recurrentemente.
• El rastreo se para cuando el rayo intersecciona con el fondo o a una profundidad
de rastreo predeterminada.

Cálculo recurrente de ray-tracing

Figura 8.20

El color e intensidad del pixel son la acumulación del árbol de rastreo desde las
hojas.
Hay tres contribuciones de luces de un punto de una superficie:
• Intensidad local, debida a la iluminación de la luz directa y la luz ambiente.
• Luz de la dirección de la reflexión.
• Luz de la dirección de transmisión de refracción

Hay una atenuación de la intensidad según la distancia del nodo hasta la raíz del
árbol. Para antialias, hay que crear más rayos para cada pixel y utilizar la técnica jittering.

Figura 8.21

18
Luces y lámparas

5.2. EL MÉTODO DE RADIOSIDAD

Se considera que todos los objetos están dentro de un sistema cerrado donde se
conserva la energía. Cada superficie será un reflector o un emisor o ambas cosas a la vez.
La energía emitida desde un punto de superficie es la suma de la contribución de todas las
direcciones sobre un hemisferio centrado en el punto.

Figura 8.22

Figura 8.23

19
Luces y lámparas

Figura 8.24

Rendering por el método de radiosidad

• Paso 1. Calcular los factores de forma F jk .


Este paso se puede simplificar utilizando el hemicubo para sustituir el hemisferio.
• Paso 2. Calcular los Bk resolviendo la matriz de ecuaciones (usando por ejemplo
el método de Gauss-Seidel).

Los pasos 1 y 2 son independientes del punto de vista. Sólo hay que realizarlos una
vez para cada escena.

• Paso 3. Para un punto de vista dado, realizar el rendering por un método de


sombreado, por ejemplo, el método de Gouraud. Utilizar los Bk como la
intensidad de luz incidente a todas las superficies que ven la superficie k para el
cálculo de interpolación.
• Paso 4. Repetir los pasos 2 y 3 para cada banda de color.

Cada superficie se puede subdividir en muchos polígonos (pataches). La imagen


aparece más real si los polígonos son mas pequeños.
El método de radiosidad produce imágenes muy realistas con alta calidad, pero
necesita una gran cantidad de cálculo, sobre todo, el cálculo de los factores de forma.
Una variante a este método sería el método de refinamiento progresivo. Este método
consiste en calcular los factores de forma y producir imágenes de la misma escena cada vez
con más luces durante el procesamiento.
La forma de ir añadiendo luces a la escena seria la siguiente:
• Aplicar primero la luz (el emisor de energía) más fuerte.
• Visualizar inmediatamente el efecto de esta luz.
• Añadir las luces a la escena progresivamente según sus intensidades.
• Visualizar la escena cada etapa hasta que el usuario este satisfecho.

20
Luces y lámparas

5.3. MÉTODO RADIANCE

Radiance es un algoritmo de renderizado basado en el comportamiento físico de la


luz. Radiance es el nombre de un sistema de renderizado desarrollado por Gregory J.Ward
durante más de nueve años en el Laboratorio Lawrence Berkeley (LBL) en California y el
EPFL ( Ecole Polytechnique Federale de Lausanne ) en Suiza. Comenzó como un estudio
de algoritmos de trazado de rayos (ray- tracing) y después de demostrar su potencial para el
ahorro de energía a partir de un mejor diseño de iluminación, adquirió fondos del
Departamento de Energía de Estados Unidos y más tarde del gobierno suizo. Entre los
objetivos principales de diseño de Radiance están asegurar el cálculo preciso de la
luminancia y modelar tanto interiores como exteriores en escenas con una geometría
complicada.
Radiance, al igual que el método de Radiosidad, son técnicas de iluminación global
utilizadas en el campo de renderización de entornos 3D. Estas técnicas de iluminación
global consideran la influencia de todos los objetos en la escena. Es decir, la iluminación
que recibe una superficie se debe tanto a las fuentes de luz que existan en la escena como a
la que reflejan otras superficies.

En la siguiente figura se muestra un ejemplo de una escena renderizada con


Radiance.

Figura 8.25

El algoritmo de Radiance ofrece grandes ventajas en el diseño real de iluminación


tanto en espacios interiores como exteriores, no obstante el programa presenta una serie de
desventajas entre las cuales se pueden señalar las siguientes:

21
Luces y lámparas

• Aunque hay software conversores de formatos que permiten traducir desde y


hacia el formato de descripción de escenas de Radiance, se utilizan como
programas independientes del propio renderizador, lo cual hace más tediosa su
utilización.
• Carece de una interfaz adecuada para la introducción de los objetos a modelar,
para lo cual es necesario editar un fichero ASCII con la descripción adecuada de
los mismos. Esto resulta una tarea bastante tediosa y difícil al no poder ver de
forma interactiva las posiciones relativas entre los objetos.
• La descripción y mapeo de las texturas en Radiance es bastante limitada,
incluyendo un solo tipo de formato de imagen, propio de este software, que es el
formato PIC.
• Las posibilidades que ofrece de animación de una escena son bastante pobres,
incluyendo sólo la posibilidad de animar la cámara para realizar recorridos
virtuales dentro de la escena, dejando de lado la modificación de las
características o posición de los objetos a lo largo del tiempo.

22
Luces y lámparas

6. LA ILUMINACION EN OPENGL

6.1. TIPOS DE ILUMINACIÓN EN OPENGL

Vamos a ver que tipos de iluminación soporta OpenGL. Básicamente son tres tipos:
• Iluminación plana o FLAT.
Es la más simple e ineficiente. En ella todo el polígono presenta el mismo
color pues OpenGL evalúa sólo un color para todos sus puntos. Puede activarse
mediante:
glShadeModel(GL_FLAT );

No es muy recomendable para aplicaciones dónde el realismo sea importante. Por


otra parte es muy eficiente dado que los cálculos son mínimos.

• Iluminación suave o SMOOTH / GOURAUD.


Se activará así:
glShadeModel(GL_SMOOTH );

En este caso OpenGL si efectúa cálculos de color para cada uno de los puntos del
polígono. Se asocian las normales a los vértices, OpenGL calcula los colores que
éstos deben tener e implementa una interpolación de colores para el resto de puntos.
De esta forma ya empezamos a presenciar escenas granuladas, con degradados en la
geometría. La calidad ya empieza a ser notable.

• Iluminación PHONG.
Es la mejor de todas y por supuesto la que requiere de más cálculos. En el
modelo de PHONG se utiliza una interpolación bilineal para calcular la normal de
cada punto del polígono. A diferencia del caso anterior, no se evalúan las normales
sólo en los vértices y luego se interpolan colores sino que a cada punto del polígono
se le asocia una normal distinta (se interpolan las normales) con lo cuál su color
asociado será muy cercano a la realidad.
OpenGL no implementa PHONG directamente. Así pues, deberíamos de ser
nosotros los que interpoláramos normales y las asociáramos a todos los puntos.

6.2. CARACTERISTICAS DE LAS FUENTES DE LUZ.

OpenGL soporta en principio hasta 8 luces simultáneas en un escenario. Esto


también depende de la máquina que poseamos y de la RAM que usemos
Las luces cuentan con nombre propio del estilo GL_LIGHT0, GL_LIGHT1, GL_LIGHT2,
etc.
Para activar / desactivar una de ellas se hace lo siguiente:
glEnable(GL_LIGHT3);
glDisable(GL_LIGHT3);
También podemos activar y desactivar todo el cálculo de iluminación con:
glEnable(GL_LIGHTING);

23
Luces y lámparas

glDisable(GL_LIGHTING);

Para definir las fuentes de luz tenemos que decirle a OpenGL cuáles son las propiedades de
cada una de nuestras luces.
En la figura 7.29 podemos ver algunos ejemplos de objetos iluminados usando OpenGL:

Figura 8.26

Para ello utilizaremos la función:

GLvoid glLightfv(GLenum light, GLenum pname, const GLfloat *params);

El valor de light será siempre la luz a la que nos estemos refiriendo (GL_LIGHT0,
GL_LIGHT1,GL_LIGHT2, etc.). En cuanto a *params, le pasamos un array de valores
RGBA reales que definen la característica en concreto. Estos valores RGBA definen el
porcentaje de intensidad de cada color que tiene la luz. Si los tres valores RGB valen 1.0 la
luz es sumamente brillante; si valen 0.5 la luz es aún brillante pero empieza a parecer
oscura, gris.

6.3. VECTORES NORMALES A UNA SUPERFICIE

Para iluminar una superficie (plano) necesitamos información sobre su vector


normal asociado.
La normal de un plano es un vector perpendicular a este. Necesitamos saber como calcular
ese vector y como especificárselo a OpenGL. De hecho en el caso de OpenGL, es necesaria
la definición de un vector normal para cada uno de los vértices de nuestra geometría. Por
ejemplo, en el caso de la figura 7.30:

24
Luces y lámparas

Figura 8.27: Para


obtener la normal
de la superficie
ABCD buscamos
dos vectores
pertenecientes a
esta y realizamos
su producto
vectorial.

Supongamos que tenemos un objeto 3D como el de la figura 7.30. Vamos a


situarnos en su cara superior, la formada por los vértices A, B, C y D. Queremos encontrar
la normal de esta cara, que por lo tanto es la asociada a cada uno de los vértices que la
forman. Sólo tenemos que calcular dos vectores pertenecientes a la cara y hacer su producto
vectorial (el resultado será un vector perpendicular a ambos y por lo tanto una normal del
plano).
Lo podéis ver en la figura. A partir de tres vértices (A, B, C) creo dos vectores que tras su
producto vectorial me generan el vector normal. Este vector ya puede asociarse a la
correspondiente cara en 1.
Una vez calculada la normal tenemos que normalizar, es decir, dividir ese vector por su
propio módulo para que sea unitario. De esta forma tenemos un vector normal de módulo
igual a la unidad que es lo que OpenGL necesita.
Hay que tener cuidado con el orden en que se multiplica porque de esto depende que el
vector normal apunte hacia fuera o hacia dentro de la cara. En nuestro caso, queremos que
nuestras normales apunten hacia fuera de la cara visible (FRONT).
OpenGL utilizará la normal asociada a cada vértice para evaluar la luz que incide sobre
éste. Si un vértice pertenece a más de una cara (en la figura anterior, el vértice A, por
ejemplo, pertenece a tres áreas distintas), en este caso hay que promediar para obtener unos
cálculos correctos por parte de OpenGL. Tendremos que calcular la normal de cada una de
las caras a las que pertenece el vértice, promediarlas y después normalizar el resultado con
lo cuál ese vértice presentará un vector normal al cuál han contribuido todas las caras a las
que pertenece. Para definir normales con OpenGL:

glBegin(GL_POLYGON );
glNormal3f(CoordX, CoordY, CoordZ);
glVertex3f ( ... ) ;
glVertex3f ( ... ) ;
glVertex3f ( ... ) ;
glVertex3f ( ... ) ;
...
glEnd( ) ;

25
Luces y lámparas

En este caso estamos definiendo un polígono de N vértices que comparten la


normal, es decir, todos tienen la misma. Si no fuera el caso lo podríamos hacer así:
glBegin ( GL_POLYGON ) ;
glNormal3f ( CoordX, CoordY, CoordZ ) ;
glVertex3f ( ... ) ;
glNormal3f ( CoordX, CoordY, CoordZ ) ;
glVertex3f ( ... ) ;
glNormal3f ( CoordX, CoordY, CoordZ ) ;
glVertex3f ( ... ) ;
glNormal3f ( CoordX, CoordY, CoordZ ) ;
glVertex3f ( ... ) ;
...
glEnd( ) ;

y entonces cada vértice tendría su propia normal asociada.


A la función le pasamos las tres coordenadas XYZ del vector en cuestión. Como siempre
hay variaciones sobre la función dado que es del tipo glNormal*.
En el caso de que no normalicéis los vectores normales, podéis utilizar:

glEnable(GL_NORMALIZE);
glDisable(GL_NORMALIZE);

Para que OpenGL lo haga automáticamente por nosotros. No es para nada recomendable
pues se carga al sistema con cálculos innecesarios que ralentizarán aún más lo que ya de
por sí es computacionalmente exigente, es decir, el cálculo automático de la iluminación.

6.4. COLOCAR LAS LUCES

Tenemos que especificar dónde queremos colocar cada una de las fuentes de luz.
Para ello utilizamos la siguiente función:
GLvoid glLightfv (GLenum light, GL_POSITION, const GLfloat *params);

Notar el uso de la constante GL_POSITION. En este caso *params se corresponde con el


valor de la coordenada homogénea (X, Y, Z, W) dónde colocar la luz. Si w = 0.0 se
considerará que la luz se encuentra infinitamente lejos de nosotros. En ese caso su dirección
se deduce del vector que pasa por el origen y por el punto (X, Y, Z). Si w = 1.0 se considera
su posición con toda normalidad.
Por defecto la luz se encuentra en (0.0, 0.0, 1.0, 0.0) iluminando en la dirección negativa de
las Z's.
Los rayos de la luz se asumen paralelos.
Podemos mover una luz a gusto por una escena. Incluso podemos movernos con ella como
si fuera una linterna. Para ello tan sólo tenemos que considerarla como un objeto 3D más
que se ve afectado por cambios en la matriz de transformación "MODEL-VIEW" de
OpenGL. Podemos rotarla, trasladarla, escalar su posición como si de un polígono se
tratara.

26
Luces y lámparas

6.5. ATENUACION CON LA DISTANCIA

La atenuación con la distancia hace referencia a la atenuación que sufre la luz a


medida que se desplaza. Está claro que a más lejos esté un objeto de una fuente luminosa,
menos iluminado resultará. Para modelar esto contamos con tres parámetros a definir:
• GL_CONSTANT_ATTENUATION (por defecto igual a 1.0). En la formula es "a".
• GL_LINEAR_ATTENUATION (por defecto igual a 0.0). En la formula es "b".
• GL_QUADRATIC_ATTENUATION (por defecto igual a 0.0). En la formula es
"c".
La función que atenúa la iluminación con la distancia es:

Es decir que se reduce la intensidad de la luz que llega a un determinado lugar con esta
fracción, evidentemente inversamente proporcional a la distancia. Los valores los pasamos
a OpenGL usando la función de siempre. Por ejemplo:
GLvoid glLightfv ( GL_LIGHT5, GL_CONSTANT_ATTENUATION, 0.8 ) ;
GLvoid glLightfv ( GL_LIGHT5, GL_LINEAR_ATTENUATION, 0.5 ) ;
GLvoid glLightfv ( GL_LIGHT5, GL_QUADRATIC_ATTENUATION, 0.1 ) ;

En este caso hemos dado más importancia a los coeficientes a y b de la función. Los hemos
aplicado a la sexta de las luces.

6.6. AREA DE COBERTURA.

El área de cobertura hace referencia al área que abarca el haz de luz que surge de la
fuente.
Podemos definir los siguientes parámetros:

• GL_SPOT_CUTOFF para definir un "cono" de luz. Podemos especificar el ángulo


de abertura del cono con un valor de 0.0 a 90.0 grados. Si optamos por el valor
180.0º estaremos desactivando esta opción.
• GL_SPOT_DIRECTION para restringir la dirección de la luz emitida. Es un vector
de tres valores reales XYZ. Por defecto la dirección es la de las Z's negativas.
• GL_SPOT_EXPONENT que regula la pérdida de intensidad de la luz a medida que
nos alejamos del centro del cono. Valores entre 0.0 y 128.0.
Para más claridad veamos la figura:

27
Luces y lámparas

Figura 8.28

28
Luces y lámparas

7. LOS MATERIALES EN OPENGL

Todos los materiales tienen color por si mismos. Por ejemplo, un objeto de color verde
refleja mayoritariamente los fotones verdes y absorbe la mayoría de los demás. Por eso
decimos que la luz que brilla sobre el objeto tiene fotones verdes reflejados que el
observador puede detectar.
La mayoría de las escenas que se nos pueden presentar, están iluminadas por una luz blanca
que contiene una mezcla de todos los colores. De esta forma, casi todos los objetos bajo una
luz blanca aparecen con sus colores naturales.
Pero si ponemos un objeto verde en una sala oscura, iluminada solamente por una luz
amarilla, el objeto aparecerá negro para el observador. Esto es debido a que el objeto
absorberá toda la luz amarilla y no habrá ninguna luz verde que reflejar.

7.1. LAS PROPIEDADES DE LOS MATERIALES

Cuando se usa iluminación, al describir un objeto no se dice que se objeto sea de un


color en particular. Se describe el objeto indicando que esta hecho de un material que tiene
ciertas propiedades reflectivas. Por ejemplo, en vez de decir que un objeto es verde,
deberíamos decir que el objeto esta hecho de un material que mayoritariamente refleja la
luz verde. Dicho de otra manera mas formal, podemos decir que la superficie del objeto es
verde, pero también debemos especificar las propiedades reflectivas del material del que
esta compuesto el objeto para las fuentes de luz ambiental, difusa y especular.
Un material puede ser brillante y reflejar muy bien la luz especular, al mismo tiempo que
absorbe la mayor parte de la luz ambiente y difusa. Pero también puede ocurrir que un
objeto pueda absorber toda la luz especular y no ser brillante.

7.2. LA LUZ EN LOS MATERIALES

Nuestra percepción del modelo se ve influenciada por los distintos tipos de


superficies que tiene el modelo. Una superficie transparente permitirá que la mayor parte de
los rayos penetren la superficie. El cristal, las láminas de plástico, las superficies acrílicas
claras y el agua son ejemplos de superficies relativamente transparentes. Por otro lado, una
superficie traslúcida solo permite el paso de algunos rayos de luz, y reflejar los otros. El
plástico coloreado que cubre las luces de freno de la mayoría de los automóviles, y el cristal
esmerilado, son ejemplos de superficies traslúcidas.
Una superficie opaca reflejara algunos de los rayos y absorberá otros, pero no permitirá que
pase ningún rayo a través del objeto. Un ladrillo es un ejemplo de superficie opaca.

29
Luces y lámparas

Superficie transparente Superficie translúcida Superficie opaca


Figura 8.29

La luz pura es la blanca, compuesta de todos los colores. Los colores que son absorbidos
por las superficies traslúcidas y las superficies opacas se pierden para el ojo humano; los
colores que son reflejados por las superficies traslúcidas y las superficies opacas son los
colores que llegan al ojo humano. Estos colores que se reflejan son el color del objeto, por
decirlo de otra manera.

7.3. ESPECIFICACIÓN DE MATERIALES EN OPENGL

Antes de empezar a activar luces hay que definir nuestros materiales. Para cada
polígono de la escena hay que definir un material de forma que su respuesta a la incidencia
de luz varíe según sea el caso. Está claro que no se refleja igual la luz en un pedazo de oro
que en una manzana. Por tanto tenemos que decirle a OpenGL de que forma tendrá que
tratar a cada geometría. Se definen cinco características fundamentales para un material.
Estas componentes son:

• Reflexión difusa (diffuse) o color de base que reflejaría el objeto si incidiera sobre
él una luz pura blanca.
• Reflexión especular (specular), que se refiere a los puntos brillantes de los objetos
iluminados.
• Reflexión ambiental (ambient), define como un objeto (polígono) determinado
refleja la luz que no viene directamente de una fuente luminosa sino de la escena en
sí.
• Coeficiente de brillo o "shininess". Define la cantidad de puntos luminosos y su
concentración. Digamos que variando este parámetro podemos conseguir un objeto
más o menos cercano al metal por ejemplo.
• Coeficiente de emisión (emission) o color de la luz que emite el objeto.

Las componentes ambiental y difusa son típicamente iguales o muy semejantes. La


componente especular suele ser gris o blanca. El brillo nos determinará el tamaño del punto
de máxima reflexión de luz.
Se pueden especificar diferentes parámetros en cuanto a material para cada polígono. Es
una tarea ardua pero lógicamente a más variedad de comportamientos más real será la
escena. El funcionamiento es el normal en OpenGL. Cada vez que se llama a la
correspondiente función se activan esos valores que no cambiarán hasta llamarla de nuevo

30
Luces y lámparas

con otros. Por tanto todo lo que se "renderice" a partir de una llamada heredará esas
características. La función es:
GLvoid glMaterialfv(GLenum face, GLenum pname, const GLfloat *params);

Glenum face Glenum pname const GLfloat *params


GL_FRONT GL_DIFFUSE ( R, G, B, 1.0 )
GL_BACK GL_AMBIENT ( R, G, B, 1.0 )
GL_FRONT_AN GL_AMBIENT_AND_ ( R, G, B, 1.0 )
D_BACK DIFFUSE
GL_EMISSION ( R, G, B, 1.0 )
GL_SPECULAR ( R, G, B, 1.0 )
GL_SHININESS [ 0, 128 ]

En la tabla se observan los valores que pueden adoptar los parámetros de la función. En el
caso de face tenemos tres posibilidades dependiendo de si la característica en cuestión debe
aplicarse al lado visible (FRONT), al no visible (BACK) o a ambos. En cuanto a pname se
define aquí cuál es la característica que vamos a definir en concreto. Las posibles son las
que hemos comentado para un material. Por último *params, donde damos los valores
concretos de la característica. Son tres valores, de hecho tres números reales que
especifican un color RGB. Ese color define exactamente como debe verse el objeto que se
renderice después en cuanto a color ambiente, difusión, componente especular, etc...
Hay una excepción en el caso de GL_SHININESS. Si usamos esta constante como segundo
parámetro, el tercero tendrá que ser un número entre 0 y 128 que controlará la
concentración del brillo. Por defecto este valor vale 0.
La misma función tiene también las formas glMaterialf, glMateriali y glMaterialiv. No
suelen usarse por eso las versiones llamadas escalares (enteras) ya que sólo son útiles para
definir GL_SHININESS.
Valores típicos, son los usados por defecto, son de 0.8 para las tres componentes en
GL_DIFFUSE, de 0.2 para GL_AMBIENT y de 0.0 en GL_EMISSION y
GL_SPECULAR. Por supuesto tendremos que retocar estos valores hasta conseguir el
efecto deseado. El cuarto valor, es decir el 1.0, se refiere al valor del canal alfa del color
RGB.

31
Luces y lámparas

8. RENDER ÓPTIMO EN OPENGL


8.1. Z-BUFFER Y SUPERFÍCIES OCULTAS

Los polígonos más alejados de la cámara pueden estar parcial o totalmente ocultos
debido a la geometría más cercana. Eso es totalmente intuitivo y obvio para nosotros pero
no para un ordenador. Al hacer el render tendremos que tener en cuenta el orden en que
proyectamos la geometría. Por ejemplo, si tenemos un árbol a 100 unidades de distancia y
un coche a tan sólo 10, tenemos que ver el coche delante del árbol, literalmente encima, en
el plano de proyección.
Para evitar esto tenemos dos opciones fundamentales:
• Algoritmo del pintor (Painter's algorithm). Este algoritmo es tan simple como
ordenar los objetos según su distancia a la cámara para después hacer el render de
los más alejados primero y de los más cercanos después. Seria un render "Back to
Front", desde atrás hacia adelante.
• Algoritmo del Z-Buffer que OpenGL ya implementa automáticamente y que
solventa los problemas del anterior.

El algoritmo del pintor presenta problemas cuando hay polígonos que se interceptan entre
ellos.
Siempre pone uno totalmente delante del otro sin respetar esos casos en que se ve un
pedazo de cada uno. Como he dicho esto lo solventa la segunda opción.
El Z-Buffer opera de la siguiente manera. Tenemos un nuevo buffer que no almacenará
colores, sino valores de profundidad, o distancias Z, respecto de la cámara.

Figura 8.30

En este caso tenemos 3 polígonos a distintas profundidades. Queda claro que el pixel P sólo
puede ser de un color, o bien es rojo o amarillo o azul. El Z-Buffer analiza polígono a
polígono de la siguiente manera:

32
Luces y lámparas

• Mirará el cuadro azul y decidirá que P tiene que ser azul. En ese momento guardará
el valor de profundidad Z3 asociándolo al pixel.
• Más tarde encontrará el polígono amarillo y se dará cuenta de que este también
contribuye coloreando a P. Dado que Z2 < Z3 decidirá que realmente P es amarillo
ya que el segundo polígono está más cerca de la cámara. Almacenará Z2 para P en
el Z-buffer.
• De nuevo encontrará otro polígono que también colorea a P, el rojo, y como Z1 <
Z2, finalmente almacenará Z1 y pintará al pixel de rojo.
El algoritmo es muy simple e inteligente a la vez. De esta forma se tiene control a nivel de
cada pixel individual de forma que seguro que acabará siendo coloreado de su color real sin
fallo alguno.
Para activar el Z-Buffer en OpenGL tenéis que añadir un parámetro a la función
glutInitDisplayMode del main, dejándola así:

GLvoid glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

De forma que habilitáis a la librería para que reserve memoria RAM para guardar los reales
de profundidad. Por otra parte y si utilizáis doble buffer, cosa altamente probable, tendréis
que limpiar el Z-Buffer además del frame buffer. Lo podéis hacer con el glClear de siempre
en el callback de display:
GLvoid glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Por cierto que podéis activar y desactivar el Z-Buffer a gusto según os convenga dejando
las definiciones que os acabo de comentar de forma permanente y tan sólo llamando a:
GLvoid glEnable(GL_DEPTH_TEST);
GLvoid glDisable(GL_DEPTH_TEST);

También podéis definir cual es el valor de profundidad que se almacena en el Z-Buffer al


limpiarlo. Por defecto este valor es 1.0. Para cambiarlo:
GLvoid glClearDepth(GLclampd profundidad);

No suele cambiarse nunca este valor pero si se hace debe estar entre 0.0 y 1.0.
Hay ciertos objetos que contienen caras que nunca serán visibles. Por ejemplo una esfera.
¿El interior hace falta renderizarlo?...pues la verdad es que no si nadie va a mirarlo. Si
utilizamos GLUT para llamar a:
GLvoid GLUTSolidSphere(GLdouble radio);
Nos pintará una esfera sólida del radio deseado. El problema radica en que también estará
pintando todas las caras interiores que no se ven, ralentizando así al sistema. Tenemos una
función que optimiza en este sentido, es:
GLvoid glCullFace(GLenum modo);
Donde el modo puede ser:
• GL_FRONT, que implica no pintar las caras frontales.
• GL_BACK, que implica no pintar las caras traseras.
• GL_FRONT_AND_BACK, que implica no pintar caras. Sólo se pintaran puntos y
líneas.
Activaremos este proceso de "Culling" mediante la función:

33
Luces y lámparas

GLvoid glEnable(GL_CULL_FACE);

8.2. EL CANAL ALFA

El modelo RGBA de color dota a cada punto de una cuarta componente llamada
canal alfa. El canal alfa sirve para decidir que debe hacerse con ese punto si contribuye
junto con otros a colorear un pixel. Hasta ahora el citado pixel se pintaría del color del
polígono más cercano pero si activamos el canal alfa obtendremos "mezclas de colores"
para el pixel. Cada polígono contribuirá en un cierto tanto por ciento a colorear el pixel de
forma que podemos obtener interesantes efectos como emular un cristal tintado o un papel
de celofán rojo, por ejemplo.

Figura 8.31

En esta imagen se observa que mezclando dos colores generamos un tercero o lo que es lo
mismo, que si tengo un objeto de color rojo y le pongo delante un papel translúcido de
color azul, la intersección de ambos se verá de color lila.
Eso ocurre porque el polígono que está más cerca tiene un cierto grado de transparencia por
lo cuál nos deja ver lo que tiene detrás. A esto le llaman los anglosajones "Blending".
Siempre se habla de una fuente (source) y de un destino (destination). El destino es el valor
de color que un pixel ya tiene asignado en el frame buffer. La fuente es el color que viene,
el color que se mezclará con el que ya tiene.
Se entiende que un objeto es totalmente opaco si está al 100% de alfa o lo que es lo mismo,
ésta vale 1.0. Si alfa vale 0.0 quiere decir un 0% de opacidad, o sea un 100% de
transparencia.
Se combinan los colores de la fuente y del destino según el valor de alfa que tiene cada uno
de ellos. Se define una función de mezclado, o de "blending" que, según sea, aplicará de
una forma o de otra el canal alfa de cada color. Para que quede claro vamonos directamente
a OpenGL.
Utilizaremos la función:
GLvoid glBlendFunc(GLenum factorFuente, GLenum factorDestino);

Dos ejemplos:

34
Luces y lámparas

1. glBlendFunc(GL_ONE, GL_ZERO);
2. glBlendFunc(GL_SRC_ALPHA, GL_ONE);

En el primer caso estamos dando una importancia de 1 (máxima) al canal alfa de la fuente y
de 0 (nula) al canal alfa del destino. Eso equivale a decir que el color final se compone de
un 100% del de la fuente y de un 0% del color destino por lo cual el pixel acaba siendo del
color de la fuente.
En el segundo caso le decimos a OpenGL que multiplique a la fuente por su valor de alfa y
sume el resultado al color destino. En este caso y asumiendo un valor de alfa igual a 0.75
para la fuente, podríamos decir que:
Color Resultante = (Color de la fuente x 0.75) + Color del Destino

O sea un color que tiene un 75% del color fuente y un 100% del color destino. Por supuesto
también podemos activar o desactivar el mezclado de colores con:
GLvoid glEnable(GL_BLEND);
GLvoid glDisable(GL_BLEND);
Hay un problema y consiste en lo siguiente. Digamos que el Z-Buffer no sabe
absolutamente nada de los valores de alfa y se dedica a eliminar polígonos ocultos, no a
mezclarlos. Esto hay que solucionarlo con ingenio y no a base de funciones de OpenGL. Se
puede seguir una secuencia de este estilo:
1. Dibujar los objetos opacos con el Z-Buffer activo.
2. Utilizar la función glDepthMask(GL_FALSE); para desactivar la escritura en el
ZBuffer. Se siguen consultando valores pero no se re-escriben.
3. Dibujar todos los polígonos transparentes.
4. Reactivar la escritura en el Z-Buffer con glDepthMask(GL_TRUE);.
Esto no es una solución definitiva ya que muchas veces se nos plantean nuevas situaciones
difíciles de arreglar, según sea la escena. Soluciones más robustas ya son más complicadas
e implican usar estructuras de datos como los árboles BSP o dibujar siempre en orden
"Back to Front".

8.3. EFECTO DE NIEBLA

Podemos añadir niebla a nuestras escenas de una forma sencilla. El realismo


aumenta considerablemente si además tenemos luces.
Se puede producir la ilusión de distancia pintando aquello lejano de un color más tenue que
lo cercano. Esta idea es ya muy antigua y se aplicaba en los primeros sistemas gráficos,
aquellos que sólo pintaban líneas y además en un sólo color. Disminuían la intensidad del
color de la línea a medida que ésta se alejaba del punto de vista dando una clara sensación
de profundidad aún sin tener Z-Buffer ni polígonos con color de relleno. A esto se le llama
"Depth Cueing".
Se puede emplear el mismo paradigma para crear niebla. La niebla no es más que un
espacio parcialmente opaco entre un objeto y la cámara. Podemos hacerla más espesa cerca
de nosotros y menos lejos. Si partimos de tener un cierto factor de niebla F podemos hablar
de una relación así:

35
Luces y lámparas

ColorFinalObjeto = F * ColorInicialObjeto + ( 1 - F ) * ColorNiebla

Modificamos el color del objeto al hacer el render. Lo alteramos con el color y el factor de
la niebla. Se observa que esta relación nos permite crear un nuevo color para el objeto que
está formado por un determinado tanto por ciento del original al que se le suma algo del
color de la niebla. La idea tiene una relación clara con el canal alfa.
Para complicar un poco el tema podemos hacer que el factor F varíe linealmente entre un
valor máximo y otro mínimo según la distancia del objeto a la cámara. Así añadimos el
efecto "Depth Cue" al sistema y "espesamos" más o menos la niebla según la distancia. El
factor también puede variar de forma exponencial y es en este caso en el que se obtienen las
más altas cotas de realismo.
Veamos un ejemplo:

Figura 8.32

Fijarse como la densidad de la niebla va disminuyendo a medida que crece la distancia del
objeto al observador. Esa disminución puede ser lineal, exponencial o Gausiana si es
OpenGL quien se encarga de ello. En casos distintos tendremos que ser nosotros los que
implementemos el efecto.
Es increíblemente fácil añadir niebla con OpenGL:
GLfloat colorNiebla[4] = { ... };
...
glEnable(GL_FOG);
...
glFogf(GL_FOG_MODE, GL_EXP);
glFogf(GL_FOG_DENSITY, 0.75);
glFogfv(GL_FOG_COLOR, colorNiebla);

Fijarse que definimos un color para la niebla y un tipo de función para F (exponencial en
este caso y de expresión e^exp donde exp = -0.75*z^2).

36
Luces y lámparas

9. EFECTOS DE ILUMINACIÓN

Dependiendo del tipo de material con el que esté hecho el objeto que estamos
modelando, será suficiente o no con aplicar sólo las componentes de luz difusa y ambiente
para darnos la ilusión de tener nuestro objeto iluminado. Por ejemplo, si estamos
modelando un objeto de arcilla cuyo color es plano, con esto será suficiente.
Pero para dotar de verdadero realismo a una escena, es necesario introducir la componente
especular de la luz. Basándonos en ella, conseguiremos importantes efectos sobre nuestros
objetos, como por ejemplo difuminar la composición de polígonos de nuestra escena, dotar
de mayor realismo al desplazamiento de los objetos, o bien, aportar los efectos de brillo de
los diferentes materiales, para distinguir por ejemplo un objeto metálico de uno que no lo
es.
Además debemos hablar de algunos efectos importantes de la iluminación como son las
sombras, y algunos que aunque menos importantes si son muy vistosos, como la niebla.

9.1. COMPONENTE ESPECULAR

Dependiendo de cómo apliquemos la componente especular en una escena, la


sensación de realismo será mayor o menor. El principal problema es que esta componente
la debemos calcular en tiempo real, lo cuál nos lleva a la eterna contradicción entre calidad
y rendimiento de nuestro ordenador.
Cuando añadimos una componente especular a una escena, esto se va a traducir en un
“blanqueamiento del color” de los objetos, y va a depender mucho del material con que
estemos calculando el objeto. Este “blanqueamiento” se denomina reflejo especular, y va a
depender del punto de vista que tengamos sobre el objeto, por lo que se hace imposible
calcular estos efectos a priori, hay que calcularlos en tiempo real, de ahí que la mayoría de
procesadores gráficos tengan optimizadas las funciones de cálculo de reflejos especulares.
Al introducir estos efectos conseguiremos dos grandes cosas en nuestra escena: dotar de
mayor sensación de movimiento a los objetos, al variar estos efectos junto con el
movimiento de los objetos y dotar de mayor realismo a la apariencia de los objetos,
eliminando ese “efecto sintético” que se produce en las escenas en 3D.
La iluminación especular y las propiedades del material añaden el brillo necesario a la
superficie de nuestros objetos. Este brillo, que, como ya hemos dicho, tiene un efecto
blanqueador sobre el color, produce reflejos especulares cuando el ángulo de reflexión es
nítido con respecto al observador. Un reflejo especular consiste en que casi toda la luz que
incide sobre un material es reflejada, produciendo los famosos puntos blancos de luz sobre
la superficie de los objetos.

37
Luces y lámparas

Figura 8.33

En estas dos imágenes se observa claramente la diferencia entre una escena con
iluminación ambiente y difusa (izquierda) y una escena con reflejos especulares (derecha).
Otro aspecto a tener en cuenta es el tipo de luz que estamos aplicando a nuestra escena.
Podemos aplicar un foco de luz puntual, también llamado “efecto foco”, cuyos rayos de luz
son divergentes, o bien podemos añadir un foco de luz situado en el infinito, en cuyo caso,
los rayos serán paralelos.
En cada caso, el punto brillante obtenido en cada caso será diferente dada la naturaleza
paralela o divergente de los rayos.
Vamos ahora a ver cómo se incluyen todas estas cosas con OpenGl:
En primer lugar hay que aclarar que desde el punto de vista de OpenGl, los efectos de luz
especular se consiguen en dos partes: en primer lugar añadiendo un foco de luz especular, y
luego ajustando el brillo del objeto mediante las propiedades del material con el que está
hecho el mismo.

9.2. LUZ ESPECULAR

Para añadir la componente de luz especular a una escena, solo tenemos que:
• Definir las matrices de los diferentes efectos de luz: ambiente, difusa, especular.
• Ir añadiendo cada una de las componentes al foco de luz mediante la función
glLight.
Estas matrices de efectos de luz contienen cuatro valores RGBA (rojo, verde,azul,alfa), y
dependiendo los valores que seleccionemos, el efecto producido será de una u otra forma de
color.
Así por ejemplo, si queremos una componente de luz blanca muy brillante de luz especular,
la matriz de efectos para esa componente será por ejemplo:
Espec[] = 1.0f,1.0f,1.0f,1.0f};
GlLight(GL_LIGHT0,GL_SPECULAR,Espec);

38
Luces y lámparas

De esta manera ya hemos añadido a muestra fuente de luz la componente especular, que en
este caso, y debido a los valores de la matriz que hemos introducido como último
parámetro, la componente especular es blanca y muy brillante.

9.3. REFLECTANCIA ESPECULAR

Este efecto se refiere a ese “punto brillante” del objeto. Para añadir reflectancia
especular a un objeto, no sólo es suficiente con añadir la componente especular a nuestro
foco de luz, sino que además, hay que modificar las propiedades del material con que está
hecho el objeto para que lo soporte. Así pues, debemos invocar a la función glMaterial en
alguna de sus variantes para que en lo sucesivo, los objetos que se dibujen contengan esta
componente de reflejo especular. Esto tiene su lógica, ya que, por ejemplo, si estamos
representando un objeto hecho de arcilla, la arcilla no es brillante, y apenas tiene
reflectancia especular. Ahora bien, si estamos representando un objeto metálico, el metal es
muy brillante, y por tanto hay que ponerle una reflectancia especular con una componente
de luz muy brillante.
Sirva de ejemplo el siguiente:
Glfloat espec[4] = {1.0f,1.0f, 1.0f,1.0f};
GlEnable(GL_COLOR_MATERIAL),
GlColorMaterial(GL_FRONT,GL_AMNBIENT_AND_DIFFUSE);
GlMaterialfv(GL_FRONT,GL_SPECULAR,espec);
GlMateriali(GL_FRONT,GL_SHININESS,128);
En primer lugar, estamos definiendo la matriz de la componente especular, toda a unos, lo
que indica un reflejo muy brillante de luz blanca.
Posteriormente activamos el seguimiento de color para el material que estamos empleando,
y con la siguiente sentencia selecciona que ese seguimiento se produzca solamente para la
luz difusa y la ambiente, y no para la especular. De esta manera lo que conseguiremos es
“blanquear el color” para las componentes difusa y ambiente.
Luego define las propiedades del material para que contenga esa componente especular, y
con los valores RGBA definidos por la matriz espec[], de tal manera que el material va a
reflejar casi toda la luz que incida de manera directa sobre él, de tal manera que a partir de
ahora, todos los materiales que se dibujen, tendrán esta propiedad.
En definitiva, hemos definido la escena de tal manera que, a partir de ahora, todos los
materiales que se dibujen, sean del color que sean, seguirán a ese color en lo que a
componentes de luz ambiente y difusa se refiere, pero para la componente especular, no hay
seguimiento del color, con lo cual, solo depende de los valores de la matriz de componente
especular.
Por último, queda definir el tamaño del punto de reflexión. La reflexión especular produce
un blanqueamiento del color allá donde incide de manera directa. El tamaño de la superficie
donde queremos que incida de manera directa lo definimos con la última sentencia del
ejemplo. Este tamaño oscila en un rango entre 0 (un punto) y 128 (toda la superficie
expuesta al foco de luz), es decir, cuanto más grande es este valor, más grande y más
brillante es la superficie que brilla. Esto lo conseguimos con la llamada a la función
GlMaterial con el parámetro GL_SHININESS seguido de ese valor entre 0 y 128 que
determina el tamaño del punto brillante.

39
Luces y lámparas

Figura 8.34

En esta imagen hemos seleccionado el valor 128 para el tamaño del punto luminoso.

Figura 8.35

En esta otra hemos seleccionado el valor 0.


Vemos en las figuras, tomadas ambas del mismo programa, cómo difiere el tamaño del
punto brillante sobre la esfera según seleccionamos un valor u otro en la función
anteriormente descrita.

9.4. TÉCNICAS DE ILUMINACIÓN.

Añadir un reflejo especular a un objeto, como hemos visto antes, consiste, a grandes
rasgos, en añadir ese punto brillante cuyas características van a venir dadas por las
propiedades del material y del foco de luz.
Pero esto es solo el principio, ya que la parte más complicada del tema aún no la hemos
abordado, como es el realizar los cálculos para determinar la intensidad del foco luminoso,
calcular normales, sombras, etc. A continuación vamos a ver algunas técnicas relacionadas
con la iluminación de una escena.

9.5. PROMEDIO NORMAL

En otros capítulos, veremos que para modelar un objeto complejo, vamos a utilizar
una serie de polígonos ensamblados, dependiendo la calidad del objeto del número de

40
Luces y lámparas

polígonos utilizados. Para difuminar el efecto que producen las esquinas en las que
estamos juntando los polígonos, y dar la sensación de ser una figura curva, se utiliza la
técnica del promedio normal.
Esta técnica consiste en que dada una superficie quebrada, compuesta por varios polígonos,
cada vértice va a limitar con dos superficies, y se puede calcular la normal en ese vértice
como el promedio de las normales de las superficies que limitan con ese vértice. Si usamos
esta normal en las especificaciones de las superficies, cuando apliquemos el sombreado,
hará que la unión aparezca menos nítida, causando efectos ópticos interesantes, que pueden
hacernos pensar que se trata de superficies curvas en lugar de aristas.

Figura 8.36

La gran problemática de esta técnica es de tipo geométrico, y consiste en calcular para cada
vértice las normales de todas sus caras y promediarlas.

9.6. CUBE ENVIRONMENT MAPIN

Queda claro que si queremos obtener imágenes realistas, lo más parecido a como lo
captaría una cámara de vídeo, no podemos olvidarnos de los reflejos y demás efectos
especulares. Pero este tipo de efectos es muy dependiente del punto de vista y de la
situación de los objetos de tal manera que cualquier cambio en el punto de vista o cualquier
movimiento. Utilizando otras técnicas como el Ray tracing, nos lleva a cálculos muy
costosos y complejos que además han de volver a hacerse cada vez que cambiamos el punto
de vista o movemos el objeto.
El mapeo del entorno, que consiste en mapear el entorno como una imagen predefinida
sobre una figura geométrica que envuelve el objeto, se convierte en una buena alternativa.
Pero el mapeo del entorno utilizado actualmente, basado en una esfera como figura
geométrica envolvente a nuestra escena es muy limitado, es muy costoso de implementar y
solo produce resultados satisfactorios bajo unas condiciones muy determinadas dado la
gran dependencia del punto de vista que tiene.

41
Luces y lámparas

La solución a este problema es el mapeo cúbico del entorno, o cube environment mapping,
que consiste principalmente en la utilización de un cubo como figura geométrica
envolvente de nuestra escena. Esta técnica, está soportada por la mayoría de entornos de
programación gráfica en tres dimensiones como OpenGl o DirectX está ademas
contemplada su aceleración hardware en los procesadores gráficos más conocidos.

Figura 8.37

Como hemos dicho, el mapeo cúbico, consiste en proyectar el entorno en las 6 caras de un
cubo, de tal manera que podemos implementar con exactitud y sin excesivos cálculos las
reflexiones y efectos especulares independientemente del punto de vista utilizado siempre y
cuando nuestra escena tenga un entorno estático. No obstante, como los mapeos son más
sencillos que en el caso del mapeo tradicional, y como además muchos de los procesadores
gráficos ya tienen contemplada la aceleración hardware de esta técnica, los cambios en el
entorno pueden ser captados y mapeados en tiempo real sin mayor problema.
Para el caso que nos concierne, que es la consecución de unos efectos especulares más
realistas, también podemos utilizar esta técnica: si en lugar de aplicar la iluminación con
sus efectos, para cada polígono de nuestra figura, renderizamos la luz especular sobre el
mapa cúbico, y luego lo aplicamos sobre nuestra figura, podemos conseguir mayor
precisión en los efectos, y además la posibilidad de implementar efectos tan interesantes
como ese aura que se forma entorno a los puntos brillantes cuando estamos aplicando
iluminación de gran intensidad.

9.7. BI-DIRECTIONAL REFLECTANCE DISTRIBUTION FUNCTION

A continuación vamos a dar una visión muy general de lo que es la función de


distribución bidireccional de la reflectancia. Para obtener una información más detallada de
cómo trabaja esta técnica, en la sección de bibliografía tenemos referencias a
documentación que amplía todo este tema.

42
Luces y lámparas

Esta es una técnica de iluminación que, para comprenderla, hay que volver al principio. La
luz, cuando interacciona con la materia, producirá una serie de efectos que dependerán
tanto de la naturaleza de la luz como de la naturaleza del material sobre el que incide. Pero
en general, por el principio de conservación, tendremos que:
Luz incidente = luz reflejada + luz absorbida + luz transmitida.

En apartados anteriores hemos hablado de todos estos tipos de luz, pero la parte
complicada, que es el cálculo de la cantidad de luz que refleja un objeto, aún no hemos
profundizado lo suficiente.
La cantidad de luz reflejada por un material va a depender de los siguientes factores:
• Punto de vista desde el que estemos observando la escena,
• Las propiedades de reflexión del material para cada una de las diferentes longitudes
de onda de la luz
• La heterogeneidad de la superficie sobre la que incide, que dependiendo del punto
iluminemos tendrá unas propiedades u otras.
Así pues, tendremos que la cantidad de luz reflejada, sigue la siguiente función:

Donde:
λ= Longitud de onda.
θ y Ф= Luz incidente y reflejada en coordenadas esféricas.
u y v = Coordenadas parametrizadas del plano sobre el que incide.
Esta función se simplifica en su aplicación, ya que en general se van a omitir las dós
últimas variables, y con respecto a la longitud de onda, calcularemos esta función para cada
uno de los canales de color Rojo, Verde y Azul, con lo que tendremos que BDFR es un
vector de tres componentes.
Cálculo de BDRF:

La función BRDF calcula cuanta luz es reflejada para un determinado punto de vista. Pero
para calcular esto, previamente es necesario calcular cuanta es la luz que incide en una
determinada dirección. Cuando hablamos de la cantidad de luz que incide en una
determinada dirección, más bien hay que hablar de la cantidad de luz que atraviesa una
determinada porción de superficie, también conocido como ángulo sólido diferencial. La
siguiente figura lo ilustra claramente:

43
Luces y lámparas

Figura 8.38

Como nosotros estamos trabajando en coordenadas esféricas, básicamente y omitiendo los


cálculos, vamos a considerar como luz incidente aquella que atraviesa una pequeña porción
de esfera cuya superficie viene determinada por las coordenadas esféricas del ángulo de
incidencia de la luz, tal y como se muestra en la siguiente figura:

Figura 8.39

Para nosotros, omitiremos los cálculos matemáticos, y partiremos de un haz de luz entrante
en la dirección de wi cuyo ángulo sólido diferencial será d wi y lo mismo para el haz de luz
reflejado siendo wo y d wo la dirección y ángulo sólido diferencial respectivamente.
Si la cantidad de luz que llega en la dirección wi es Ei y la cantidad de luz reflejada en la
dirección wo es Lo entonces, podemos definir la función de la siguiente forma:

44
Luces y lámparas

Lo
BRDF =
Ei
Esto en general es la descripción teórica, a grandes rasgos, de la función BRDF. Pero a
priori resulta muy engorroso de aplicar, teniendo en cuenta que todos estos cálculos se han
de hacer en tiempo real, cada vez que se modifique el punto de vista, el objeto, etc.
Necesitamos una función más sencilla, para lo cual podemos aproximar la función en una
textura de cuatro dimensiones, que a su vez podemos dividir en dos texturas
bidimensionales, cuyos cálculos pueden ir acelerados por hardware, obteniendo la siguiente
ecuación:
Li = G (θ i , φi )·H (θ o , φ o ) L i ·Cosφi

O aproximando para nosotros:


BDFR = G · H
Observamos que la función BDRF de cuatro dimensiones la hemos descompuesto en dos
funciones de dos dimensiones. Estas dos funciones se corresponden con dos texturas
bidimensionales en las que se descompone BRDF y que luego hay que reconstruir y aplicar
mediante por ejemplo dos mapas cúbicos de los que hemos hablado antes.
Paso 1: separar la función en producto de dos funciones.
Esta es la primera fase, la de separación, y que se puede realizar durante el preproceso de la
escena.
El proceso de separación es bastante complejo, pero podemos interpretar que estamos
intentando mapear una textura de 4 dimensiones en un espacio de dos dimensiones.
Si queremos mapearlo en una textura de 16x16x16x16, debemos samplear cada parámetro
16 veces en cada dominio, que como estamos hablando de coordenadas esféricas tenemos
que el dominio de ? oscila entre 0 y ? ?? y el de ? entre 0 y ?? . Si además almacenamos los
resultados en una matriz N2 x N2, el pseudocódigo podría ser como sigue:

double deltat = (0.5 * M_PI) / (N-1);


double deltap = (2.0 * M_PI) / N;
double theta_i, phi_i;
double theta_o, phi_o;
for ( int h = 0; h < N; h++ )
for ( int i = 0; i < N; i++ )
for ( int j = 0; j < N; j++ )
for ( int k = 0; k < N; k++ )
{
theta_o = h * deltat;
phi_o = i * deltap;
theta_i = j * deltat;
phi_i = k * deltap;
/* Compute or lookup the brdf value. */
val = f( theta_i, phi_i, theta_o, phi_o );
/* Store it in a N2 x N2 matrix. */
BRDFMatrix[h*N+i][j*N+k] = val;
}

45
Luces y lámparas

Ahora, debemos de trabajar con esta matriz, en primer lugar calculando la norma para cada
una de las filas obteniendo así un vector Nx1 que va a ser nuestra función H; en segundo
lugar, para cada columna calculamos la media utilizando los valores del vector normal
obtenido antes proporcionándonos con esto un vector 1xN que consideraremos como
nuestra función G.
Todo este proceso lo tenemos que repetir para cada uno de los canales de color: el rojo, el
verde y el azul, y para el caso de OpenGl que utiliza también el valor alfa, también habría
que calcular las funciones G y H para ese valor.
Una vez calculadas las funciones G y H habrá que crear con ellas la textura de cubo para
aplicar por ejemplo el mapeo cúbico.
En primer lugar debemos samplear el cubo de la misma manera que hemos sampleado la
esfera en N valores. Entonces, para cada segmento, calculamos las coordenadas esféricas
del centro y con ellas obtenemos los valores RGBA mediante las funciones G y H.
Hay que apuntar que en ciertos entornos como OpenGl en los cuales los valores RGB
oscilan entre 0 y 1 habrá que adaptar las funciones G y H para que oscilen entre esos
valores.

46
Luces y lámparas

10. FOCOS DE LUZ


A la hora de definir la iluminación de una escena, uno de los puntos importantes a tener
en cuenta es dónde colocar la fuente o fuentes de luz.
La fuente de luz puede ser de diversas maneras, un punto luminoso que radia por igual en
todas direcciones, un efecto foco, un punto de luz situado en el infinito, y que provoca que
los rayos de luz sean paralelos y no divergentes, etc. La decisión de qué tipo de foco de luz
utilizar dependerá mucho de la escena que estemos modelando, así por ejemplo, si
queremos modelar una escena de iluminación solar, debemos escoger una aproximación a
un foco de luz situado en el infinito y de rayos de luz paralelos o también llamado fuente de
luz direccional. En este caso, desaparecería el efecto del punto de luz sobre los objetos, o
más bien, tendríamos un punto de luz que abarcaría toda la superficie iluminada del objeto.
En general, como hemos dicho antes, tenemos dos tipos de luz: luz propia y luz impropia.
• Luz propia es aquella proporcionada por un foco de luz bien situado, del cual
conocemos su ubicación, y que emite sus rayos de luz de forma radial o divergente
(figura de la izquierda).
• Luz impropia es aquella que emite sus rayos de luz desde una ubicación muy
distante, de forma que podemos considerar sus rayos como paralelos entre si (figura
de la derecha).

Figura 8.40

Ni que decir tiene que los cálculos que implica el uso de un foco de luz propia son mucho
más complejos por lo que aunque proporciona efectos mucho más realistas, en general se
tiene en lo posible al uso de luz impropia.
Veamos un ejemplo de foco de luz en OpenGl:
En primer lugar determinamos la posición y el tipo de foco. Para ello inicializamos un
vector de 4 valores donde tenemos las coordenadas x, y, z y un valor que oscila entre 0 y 1

47
Luces y lámparas

y que nos indica el tipo de foco. Los valores próximos a 0 indican luz impropia y los
próximos a uno luz propia.
GlFloat LightPos [] = {0.0f,150.0f,150.0f,1.0f};
En este caso hemos elegido luz propia. Suponemos que ya lo hemos inicializado con los
valores correctos de luz ambiente, difusa y especular, y ahora inicializamos la posición:
glLightfv (GL_LIGHT0, GL_POSITION,LightPos);
Ahora imaginemos que además de un foco de luz propia queremos darle ese efecto de foco
de luz dirigido, que emite un cono de luz en una determinada dirección:
glLight (GL_LIGHT0, GL_SPOT_CUTOFF, 60.0f);
Además debemos inicializar el brillo del foco mediante la siguiente instrucción:
glLight (GL_LIGHT0, GL_SPOT_EXPONENT, 100.0f);
En este caso hemos elegido un foco de luz muy brillante.
Hasta aquí hemos visto cómo colocar uno o varios focos de luz, pero aún no hemos hablado
de cómo esos focos de luz interaccionan con nuestra escena.
En general, cuando iluminamos una escena aplicamos dos tipos de iluminación, a saber,
iluminación local e iluminación global. La primera, habla de cómo se comporta cada
superficie al ser iluminada de forma individual. La segunda habla de la luz como un todo,
de cómo interacciona esa luz que es reflejada por un objeto sobre el objeto sobre el que es
proyectado ese reflejo.

10.1. ILUMINACIÓN GLOBAL

De iluminación local ya hemos comentado lo que es y como calcularla y aplicarla


utilizando técnicas como BDFR, por tanto vamos ha hablar ahora de lo que es iluminación
global. Podemos hablar de luz como una serie de partículas llamadas fotones que viajan con
una determinada longitud de onda y que, al impactar sobre un objeto, estos son absorbidos,
transmitidos o reflejados dependiendo de la longitud de onda y de las propiedades del
objeto. De esta manera podemos decir que la iluminación global de una escena está
formada por la interacción de billones de fotones viajando por la escena con las diferentes
superficies y objetos que componen la escena.
Así pues tenemos dos posibles técnicas para el modelado de la iluminación global:

Ray tracing
Este algoritmo se basa en la circulación de los fotones a lo largo de una escena,
computando sólo aquellos rayos que llegan a nuestro punto de vista, y siguiéndolos en
sentido inverso. Esta computación se realiza para cada píxel de la siguiente forma:
1.- Para cada píxel trazamos un rayo desde nuestro punto de vista hasta que impacta
con algún objeto.
2.- Desde el punto donde impacta con el objeto se trazan rayos a todos los puntos de
luz de la estancia, y para cada uno, si este no es bloqueado por ningún objeto
intermedio, se calcula el color en función de las propiedades del material y del foco
de luz en cuestión.
3.- Si la superficie sobre la que impacta es un espejo o una superficie transparente,
habrá que aplicar los pasos 1 y 2 siguiendo la dirección en que el rayo es
transmitido o reflejado, teniendo en cuenta la reflexión o refracción del medio. De la
misma manera si el objeto hacia el que es reflejado o transmitido el rayo es a su vez

48
Luces y lámparas

reflectante o transparente, se vuelve a aplicar 1 y 2, y así sucesivamente hasta un


número de iteraciones determinado.
Esta técnica permite crear multitud de efectos como sombras, espejos, transparencias, etc.
Pero tiene el problema del elevado coste computacional que conlleva dado que todos estos
cálculos han de realizarse para cada píxel.

Radiosity.
Esta técnica difiere fundamentalmente de la anterior en que no calcula el color para cada
píxel de la pantalla, sino para una serie de puntos discretos de la misma, y se basa en los
métodos ideados por los ingenieros técnicos para el cálculo del calor transmitido por los
objetos a principios de los 60, eso sí, aplicado a la transmisión de la luz en una estancia.
El funcionamiento de esta técnica es muy sencillo:
• En primer lugar dividimos las superficies originales en un conjunto de superficies
más pequeñas formando con ellas una malla. Durante el proceso de cálculo,
calcularemos la luz transmitida por cada elemento de la malla sobre el resto de
elementos de la malla.
• Mediante este algoritmo, calculamos la transmisión de cada elemento de forma
inicial, sin mostrar ningún resultado válido hasta que no se ha realizado el cálculo
de todos los elementos de la malla, lo cual permitía hacerlo en el preproceso.
• Pero este algoritmo fue sucesivamente refinado hasta obtener el que se muestra a
continuación:
o Cada superficie de divide en elementos relativamente largos, de tal manera
que cada uno se puede subdividir automáticamente si se observa que hay una
gran diferencia de intensidad con los elementos adyacentes si estos son por
ejemplo sombras.
o Cada complejo luminoso (pueden ser lámparas compuestas de diversos
focos) distribuye la luz sobre todas las superficies, pudiendo unos elementos
de la malla bloquear a otros, generando de esta manera las sombras.
o Se asume que unas superficies absorben más luz que otras, pero también que
todas ellas reflejan la luz de forma ideal, es decir, por igual en todas las
direcciones.
o Después de distribuir la luz sobre todas las superficies, tomamos aquel
elemento de superficie que más reflexión produce y lo tomamos a su vez
como otra fuente de luz, realizando los cálculos oportunos sobre el resto de
elementos de superficie.
o Este proceso continúa hasta que al realizar los cálculos obtengamos que la
mayor parte de la energía es absorbida.
Llegados a este punto tenemos que cada fuente de luz y cada superficie son una iteración,
hasta llegar al momento en que la energía absorbida por cada superficie es mayor que la
que le llega, de tal manera que la luz transmitida es imperceptible.

Combinando las dos.


Estas dos técnicas que hemos visto, son diferentes entre sí, cada una con sus ventajas y sus
desventajas, pero en cierto modo complementarias entre si.
• Ray tracing:
o Ventajas:

49
Luces y lámparas

Precisión para modelar la iluminación directa, sombras, espejos y


transparencias.
Bajo consumo de memoria.

o Desventajas:
Computacionalmente caro, con cálculos muy costosos y muy
dependientes del número de focos de luz de la escena.
Dependiente del punto de vista, lo que obliga a realizar de nuevo
todos los cálculos cada vez que este cambia.
Sin precisión al trabajar con las reflexiones difusas.
• Radiosity:
o Ventajas:
Calcula los interreflejos difusos entre superficies.
Independiente de vista, para poder visualizar
rápidamente superficies arbitrarias.
Rápidos resultados, pudiendo ir visualizando los
resultados intermedios e ir refinando estos progresivamente en
exactitud y calidad.
o Desventajas:
El sampleado o división en
superficies pequeñas requiere más memoria que las imágenes
originales.
Este sampleado es a su vez más
propenso a la introducción de errores en la escena.
No hay precisión en imágenes
especulares ni en efectos de transparencia.

Vistas ventajas e inconvenientes de ambas técnicas, la manera de combinar ambos depende


de la decisión del programador y de la composición de la escena, así por ejemplo, si
estamos modelando una habitación llena de espejos utilizaremos Ray tracing como técnica
principal completándola con Radiosity para generar los efectos de las reflexiones difusas.

50
Luces y lámparas

11. SOMBRAS
Añadir sombras a una escena va a redundar en un mayor realismo de la misma, pero va
a implicar una serie de cálculos adicionales, que, dependiendo del realismo que queramos,
serán más o menos complejos.
En general, la forma más sencilla de dibujar una es proyectar el objeto y oscurecer la región
de proyección. Pero tiene sus limitaciones, sobre todo cuando esas proyecciones de sombra
se realizan sobre volúmenes y no sobre el plano que conforma el suelo, lo cual es más
habitual de lo que parece.
Por este motivo se utilizan técnicas más complejas, como la utilización de sombras
volumétricas, para lo cual necesitamos disponer de información adicional, tal y como se
muestra con la técnica que describiremos a continuación.

11.1. SOMBRAS PROYECTADAS

Es la manera más sencilla que hay para dibujar una sombra en OpenGl. La idea consiste
en calcular la proyección del modelo sobre el plano sobre el que queremos calcular la
sombra. Una vez calculada esta matriz, si la multiplicamos por la matriz del modelo vamos
a obtener todo nuestro modelo proyectado sobre ese plano. Ahora solo queda elegir el color
adecuado para nuestra sombra y volver a dibujar aquellas figuras de las que queramos
dibujar su sombra. El pseudocódigo del proceso sería algo así:
• Calculamos la matriz de proyección desde el foco de luz sobre el plano.
• Dibujamos nuestra escena.
• Deshabilitamos la iluminación.
• Guardamos la matriz del modelo.
• Multiplicamos la matriz del modelo por la matriz de proyección.
• Seleccionamos el color adecuado para nuestras sombras.
• Redibujamos aquellas figuras de las que queramos proyectar su sombra.
• Recuperamos la matriz del modelo y activamos la iluminación.
Dependiendo del color que elijamos según para que objetos de los que estamos dibujando
proyectados sobre el plano podemos incluso simular efectos de sombra-penumbra, aunque
no muy realistas.

11.2. STENCIL BUFFER O BUFFER PLANTILLA

El stencil buffer o buffer cliché o buffer plantilla consiste en añadir una serie de
planos de bits con información extra que nos permite en un momento dado aceptar o
rechazar el procesado de un determinado píxel. Es un test soportado por la mayoría de
implementaciones como OpenGL, que está acelerado por hardware, y que es completado
con el test de profundidad. Se trata de evitar en los renderizados el cálculo de aquellos
pixeles que van a ser ocultados en una escena o bien utilizar su valor para aportar
información extra a la escena que estamos modelando.

51
Luces y lámparas

Como trabaja el test de plantilla por píxel.

El funcionamiento del buffer de plantilla es muy similar al de profundidad. Se trata de


añadir unos planos de bits no visibles, donde para cada bit tendremos almacenado un valor
que nos indicará el valor de plantilla del mismo. Este valor será utilizado para aceptar o
rechazar la visualización de un determinado píxel ahorrándonos los cálculos que ello
conlleva. El valor se almacena como un entero sin signo, y la forma de tratarlo será con
operaciones de comparación de tal manera que si su valor iguala o supera al de un
determinado valor de referencia, el píxel es aceptado, y si no lo supera es rechazado. Estas
operaciones consisten en operaciones de comparación y desplazamiento a nivel de bit, por
lo que la carga computacional es muy pequeña y, sin embargo, si el píxel es rechazado, nos
ahorramos el resto de operaciones, con lo cual queda evidente el ahorro computacional que
supone. También se pueden realizar otras operaciones sobre este buffer como resetear su
valor, incrementarlo o decrementarlo lo que nos permitirá ajustar oportunamente este valor
en tiempo de ejecución.

Utilización del buffer plantilla para crear sombras.

Hasta ahora hemos visto a muy grandes rasgos en qué consiste el buffer plantilla, ahora
vamos a ver alguna aplicación práctica, en concreto su aplicación al cálculo de sombras.
Hasta ahora la forma más común de calcular sombras era mediante la proyección de los
objetos sobre el plano. Esta es la forma más conocida y fácil de implementar, pero tiene una
pequeña limitación: todos los polígonos proyectados son coplanares entre si, y al mismo
tiempo, coplanares con el “suelo” que estamos representando, lo cual ocasiona problemas
con el test de profundidad, ya que todos los polígonos proyectados tienen el mismo valor en
el buffer de profundidad. Más limitaciones de esta técnica son que no se pueden proyectar
sombras sobre cualquier objeto, han de ser proyectadas obligatoriamente sobre el suelo; si
queremos utilizar el efecto sombra-penumbra, los bordes nos van a aparecer muy fuertes; se
nos produce un efecto de doble sombra en aquellos lugares donde se superponen varios
polígonos en la proyección; etc.
La utilización del buffer de plantilla, junto con esta técnica de cálculo de sombras, nos va a
solucionar varios de estos problemas, sirvan los siguientes ejemplos:
• Para el problema de limitar la proyección a una determinada superficie, podemos
asignar unos valores a los pixeles que están dentro de la superficie, y otros a los que
quedan fuera, de tal manera que al aplicar el test, los pixeles que quedan fuera serán
rechazados y no se calculará la sombra sobre ellos.
• Para el problema de la doble sombra, podemos, por ejemplo, resetear a cero el valor
de plantilla de cada píxel una vez que ha sido procesado, de tal manera que en las
zonas donde tengamos polígonos superpuestos, sólo se aplicará una vez el
sombreado, ya que cuando se vaya a aplicar por segunda vez, se va a encontrar el
valor de plantilla para ese píxel a cero y no aplicará el sombreado por segunda vez.
Veamos cuál es la secuencia de operaciones a realizar:
1.- En primer lugar, vaciamos el buffer de plantilla, asignándole el valor cero o
cualquier otro valor no utilizado teniendo en cuenta que el siguiente valor
consecutivo también debe estar sin usar.

52
Luces y lámparas

2.- En segundo lugar activamos la iluminación y los focos de luz.


3.- En tercer lugar renderizamos todos los objetos, pero aún no lo hacemos con las
superficies planas sobre las que vamos a proyectar las sombras.
4.- Ahora renderizamos las superficies planas con los focos de luz desactivados
asignándole a los pixeles de dichas superficies los valores de plantilla
correspondientes a una superficie plana.
5.- Ponemos la luz ambiente a valor cero y vamos procesando cada foco de luz de la
siguiente manera:
6.- Para cada superficie plana y cada foco de luz:
• Hacemos un push de la matriz del modelo sobre la pila.
• Renderizamos todas las sombras proyectadas por ese foco de luz. Durante
este proceso, se van a incrementar los valores de plantilla de los pixels
sombreados.
• Hacemos el pop de la pila y ajustamos el test del buffer de plantilla de tal
manera que solo se evalúen aquellos pixels cu yo buffer de plantilla no ha
sido incrementado.
• Debemos de alguna manera hacer un swap de estos valores del buffer
plantilla, ya que en la siguiente pasada del bucle vamos a resetear estos
valores.
Mediante este algoritmo, podemos renderizar las sombras de múltiples objetos sobre
superficies planas, pero no sobre otros objetos.

Sombreado de volúmenes utilizando el buffer plantilla.

Para realizar el sombreado de volúmenes con el buffer plantilla, en primer lugar debemos
escoger otros métodos de proyectar las sombras, como por ejemplo proyectar las mismas
como volúmenes.
Modelar una sombra como un volumen puede resultar a priori imposible dado que la
sombra proyectada por un cuerpo es infinita, pero como lo que a nosotros nos interesa son
las intersecciones de esa sombra con los objetos y con nuestro campo de visión, eso si que
compone una superficie finita.
Por otra parte, nosotros para representar los volúmenes, nosotros estábamos utilizando
composiciones poligonales para representar su superficie, por lo que queda bastante claro
que las sombras las vamos a representar de la misma forma. Con las sombras representadas
de esta forma, podemos utilizar el buffer plantillla para determinar qué pixels y cuales no
quedan dentro del volumen de la sombra.
En primer lugar lo que haremos será resetear todos los búferes, activar los focos de luz y
renderizar la escena para así poder calcular los valores de profundidad, determinando los
objetos más cercanos y, por lo tanto, visibles.
El segundo paso consiste en determinar cuales van a ser los pixeles que estarán dentro de la
sombra, para lo cual, en primer lugar pondremos a uno el bit menos significativo del buffer
plantilla, a continuación pasaremos el test de profundidad, invirtiendo el valor del buffer en
aquellos pixeles en los que se pasa el test, es decir, los visibles, quedando el bit menos
significativo del buffer plantilla a cero. En este momento renderizamos el volumen de la
sombra de tal forma que cada vez que se renderice un polígono de la sombra sobre un píxel
se va a incrementar en uno el valor del buffer plantilla. No debemos olvidar dibujar también

53
Luces y lámparas

las caras ocultas para así poder conseguir determinar basándonos en la paridad del valor del
buffer plantilla, si un píxel está dentro o fuera de este volumen y, por tanto si ha de ser
sombreado o no. El valor par del buffer plantilla corresponderá a un píxel no sombreado si
el punto de vista está fuera de la sombra, y viceversa si está dentro.

12. APÉNDICE A
12.1. EFECTOS DE NIEBLA

La niebla es un efecto especial utilizado para difuminar una escena dando la


impresión de que se halla realmente cubierta por una masa de niebla. En general consiste en
difuminar el color de la escena, oscureciendo los objetos más lejanos llegando incluso a
desaparecer, mientras que los objetos más cercanos aparecen mucho más claros. Es un
efecto interesante, ya que aparte de añadir realismo a la escena nos ayuda a reducir su
complejidad ya que los objetos más lejanos que aparecen ocultos por la niebla no es
necesario renderizarlos. El efecto niebla lo podemos aplicar de dos formas principalmene,
basado en vértices o basado en tablas. La primera forma consiste en calcular el valor de
atenuación de niebla para cada vértice de cada triángulo y luego interpolar para el resto del
triángulo, y en el segundo caso mantendremos tablas con los valores de atenuación para
cada píxel de la pantalla. En cualquier caso, habrá que calcular esos valores de atenuación,
bien para los vértices de cada triángulo, bien para cada píxel. Como el efecto de atenuación
va a depender de la distancia, habrá que calcular la distancia de la niebla. Para ello tenemos
entre otras dos técnicas: basada en planos o basada en rangos, mediante las cuales
determinamos los puntos que aparecerán sin niebla y los que aparecerán totalmente
oscurecidos. En ambos casos tendremos dos límites a tener en cuenta: el límite de inicio de
la niebla, de tal manera que a los objetos que se encuentren más cerca de ese límite no se le
va a aplicar niebla; y el límite de final de la niebla, de tal manera que los objetos que se
encuentren más allá de ese límite serán ocultados.

Niebla basada en planos.

Esta técnica consiste principalmente en considerar tres planos: el plano de visión, el plano
de inicio de la niebla y el de fin de la misma, todos ellos paralelos entre si, de tal manera
que sólo se calculará la niebla para aquellos puntos situados entre los planos de inicio y fin
de niebla, ya que los que están situados antes del plano de inicio no se les aplica niebla, y
los que están más allá aparecen totalmente oscurecidos y no se renderizan. Pero esta técnica
tiene sus inconvenientes, ya que si cambiamos de orientación el plano de visión, puntos que
antes estaban en región de niebla ahora quedan fuera, y viceversa, todo ello sin variar la
distancia. Las siguientes figuras lo ilustran claramente:

54
Luces y lámparas

Plano de visión inicial Plano de visión rota 90º a la izda


Figura 8.41

Niebla basada en rangos.

Esta técnica surge para eliminar el problema anteriormente descrito, y consiste en calcular
los umbrales de niebla de forma radial desde el punto de vista, y no de forma lineal como se
hacía en la técnica anterior, de tal manera que nos queda un aro de niebla en torno al punto
de vista tal y como se muestra en la figura:

Figura 8.42

La desventaja de esta técnica es su mayor coste computacional y que no puede ser utilizada
si estamos mapeando la niebla en tablas de niebla, hay que usarla con niebla basada en
vértices.

55
Luces y lámparas

Por otro lado tenemos que calcular el factor de atenuación para los puntos que se
encuentran dentro del área de niebla. Este factor lo podemos calcular de forma lineal o de
forma exponencial.

Atenuación lineal.
Depende de los umbrales de inicio y final de niebla y se calcula aplicando la siguiente
fórmula:
niebla inicio- niebla fin
f=
observ dist- niebla fin
De esta manera interpolamos los valores de atenuación entre los umbrales de inicio y final
de niebla.
Atenuación exponencial.
Este tipo de atenuación se utiliza para producir transiciones muy rápidas o intensas del
valor de atenuación. Tenemos dos posibilidades:
1 1
f= o bien: f =
densidad dist) densidad dist 2
e( e(

Con la primera fórmula conseguimos una atenuación rápida, dependiendo del valor que le
demos al factor de densidad, y en el segundo caso producimos una atenuación más intensa
dependiendo también del factor de densidad que le demos. En ninguno de los dos casos la
atenuación depende de los umbrales de inicio y fin de la niebla.
De esta forma ya tenemos como calcular los valores de atenuación para cada vértice y
luego poder interpolar para el resto del triángulo si estamos aplicando la niebla basada en
vértices; o bien tenemos el método para calcular la atenuación correspondiente a cada píxel
en el caso de utilizar tablas de niebla.

Nota:
Si estamos aplicando niebla basada en vértices, se nos puede dar el caso de que uno de los
vértices esté dentro de la zona visible y otro fuera, muy alejado del umbral de fin de niebla,
de tal manera que al interpolar nos aparezcan como visibles zonas del objeto que, por
distancia, deberían aparecer ocultas por la niebla, tal y como se muestra en la figura:

56
Luces y lámparas

Figura 8.43

Para solucionarlo, podemos crear nuevos vértices haciéndolos coincidir con los umbrales de
inicio y fin de niebla.

13. CONCLUSIONES
En una primera parte de este capitulo hemos explicado como actúa la luz al chocar
contra un objeto y como OpenGL simula este comportamiento de la luz. Para ello, hemos
hablado de cómo esta formada la luz, que modelos de iluminación existen, que técnicas de
ocultación de superficies se suelen usar, que técnicas de sombreado son las mas usadas.
También hemos hablado de como se comporta la luz ante los diferentes materiales de los
que pueden estar compuestos un objeto. Todo esto lo hemos explicado de una forma teórica
para después ver como OpenGL hace uso de todo eso de una forma muy sencilla. Hemos
nombrado todas las funciones que usa OpenGL para activar la iluminación en una escena,
para representar un foco de luz, para indicar el tipo de material de un objeto y otras
funciones para crear efectos muy interesantes relacionados con la iluminación.
En la segunda parte de este capítulo hemos hablado de algunas de las principales técnicas
que hay para aplicar una iluminación que dote de realismo a nuestras escenas. No hemos
entrado en demasiado detalle al hablar sobre las mismas ya que sobrepasa el carácter
introductorio de este capítulo a lo que es la iluminación de escenas en OpenGL. Algunas de
ellas como el Cube Environment Mapping no son en si una técnica de iluminación, sino
más bien un medio a través del cual aplicar otras como la BRDF. Otras, como el Promedio
Normal nos hablan de cómo jugar con la iluminación para ofrecer efectos ópticos
interesantes.
En general, el capítulo de iluminación es uno de los más interesantes de la programación
gráfica, porque es uno de los que más nos va a permitir dotar de fotorrealismo a las escenas
que estemos modelando, pero exige un gran dominio del resto de temas como el manejo de
texturas, perspectivas, buffers auxiliares, además de un profundo conocimiento matemático
de todo el tema de geografía descriptiva, cálculo de matrices, etc.
Para profundizar más en este tema de efectos de iluminación se pueden ver algunos
ejemplos que hemos escogido de los que hay disponibles en la red, así como algunos muy
sencillos que hemos modificado para demostrar alguno de los efectos de los que estamos
hablando. Por último hemos incluido un apéndice comentando un poco por encima en qué

57
Luces y lámparas

consiste y las diferentes técnicas utilizadas para aplicar la niebla, ya que es un efecto muy a
tener en cuenta ya que del mismo modo que la niebla difumina las figuras más cuanto más
lejanas están, también atenúa la iluminación y los efectos que conlleva, es decir, sombras,
focos de luz, etc.

58

You might also like