"Ningún juego dura tanto hasta que te lo terminas como el que te programas tú mismo,
ninguno te absorbe tanto y ninguno te produce tanta satisfacción cuando lo has acabado"
Programacion de videojuegos
Lunes 21 de Agosto del 2017

Menu principal
Colaborar (con PayPal)

Para continuar con el trabajo de esta Web y poder pagar el hosting, viene bien la ayuda que sea. Gracias a todos.

Importe: 

Ultimas descargas
19.Jan

Clase que permite dibujar texto en OpenGL con mucha facilidad.Usa FreeType2.Para ver que hace y c...


8. Iluminacion Imprimir Correo electrónico
Videojuegos - Curso de Programación de juegos
Escrito por Vicengetorix   
Veremos en este capitulo el tema de la iluminacion y como lo trata OpenGL. El aspecto de nuestro programa cambiara de nuevo a mejor, de forma que la impresion de 3D sera total. Veremos como definir luces, sus componentes, una nueva parte del vertice, la normal, y algunas cosas mas.





Lo primero es lo primero. La funcion para habilitar la iluminacion en OpenGL es glEnable(GL_LIGHTING), siguiendo el estilo de hacer las cosas habitual. Antes de esta funcion se pinta solo el color del pixel segun el relleno del poligono, sea color plano o una textura. A partir de esta funcion OpenGL ademas tendra que hacer calculos, partiendo de este color base, teniendo en cuenta las fuentes de luz, su posicion, sus componentes, y el vector normal a la superficie del objeto.... tranquilos, OpenGL hace todos los calculos (para eso esta), pero nosotros entenderemos que hace para poder usarlo a nuestra conveniencia.

A partir de habilitar la iluminacion, si no hacemos mas, veremos como nuestro programa pasa a verse en negro. Eso es porque, como es logico, donde no hay luz no se ve. OpenGL estara haciendo sus calculos pero de momento no hay luces encendidas y el resultado es oscuridad. ¿logico no?.
Para encender una luz basta con la funcion glEnable(GL_LIGHT0) que con la logica habitual de OpenGL, lo que hace es encender la luz 0.
OpenGL dispone de 8 luces, de la 0 a la 7. Al habilitar la luz 0 se encendera con valores por defecto como la posicion (0,0,0).
Cuando habilitemos la luz 0 en nuestro programa y no hacemos mas cosas, veremos de nuevo como tampoco se vera mucho mas claro. Tal vez se adivine la forma del cubo pero nada mas. Eso se debe a que a OpenGL le falta un dato basico para calcular el color, iluminado por nuestra luz 0, los vectores normales a la superficie de nuestro cubo (a partir de ahora "las normales"). Sin estos vectores, no sabe como rebota la luz en la superficie y no puede hacer el calculo.

Veremos ahora pues, las normales:


Como se ve en el dibujo, el vector N es el vector normal (es la normal) del vertice P0 del triangulo. La normal es perpendicular a la superficie del triangulo y hacia fuera del objeto. Ademas OpenGL exige que sea un vector de longitud 1 para hacer el calculo correctamente. Se puede habilitar una funcion de OpenGL que convierte en unitarios (longitud 1) las normales, es glEnable(GL_NORMALIZE), pero nosotros no la vamos a usar porque consume tiempo de computo y porque no lo necesitamos.

Una vez definidas las normales de los vertices de nuestro cubo, si que se vera nuestro objeto.
Asi pues, el proceso sera:
  • Definir las normales de cada vertice o de cada cara en el caso de nuestro cubo ya que las cuatro normales son paralelas nos bastaria con definir una al principio (esto deja claro que lo importante de las normales es la direccion).
  • Definir la o las luces con sus parametros (ya los veremos).
  • Definir los materiales la la superficie de los objetos y sus texturas si las hubiera (material y no solo el color, lo veremos tambien).
Ahora veremos las componentes de la luz que OpenGL tiene encuenta.

Para OpenGL existen 3 componentes de la luz y son:

Ambiente: La luz que llega rebotada de las paredes, los muebles, ... no se sabe de donde viene. Es una luz mas debil que las otras:


Difusa: La luz que llega directamente desde la fuente de luz pero rebota en todas direcciones (junto con la ambiente definen el color del objeto):


Especular: La luz que llega directamente de la fuente de luz y rebota en una direccion, segun la normal de la superficie (provoca el brillo, por ejemplo, del circulito blanco de la bola de billar negra):


Cada una de estas componentes de la luz se pueden definir para cada fuente de luz de OpenGL, de forma que podemos definir una luz con bombilla de color verde o rojo, o con mas o menos intensidad.

Estos parametros de la fuente de luz se definen con la funcion glLightfv. Veamos un ejemplo:

1
2
GLfloat ambiente[] = { 0.2, 0.2, 0.2, 1.0 };
glLightfv(GL_LIGHT0, GL_AMBIENT, ambiente);

Aqui vemos como definimos los valores de luz ambiente en una matriz de 4 valores, los 3 primeros son las componentes RGB del color en un rango de 0.0 a 1.0 (con punto por que son float's) y el cuarto sera 1.0 (recordad las coordenadas homogeneas pero aplicado a los colores).
Luego en la funcion glLightfv le indico como primer parametro que la funcion es para modificar los valores de la luz 0 ( GL_LIGHT0, GL_LIGHT1, ..., GL_LIGHT7 son las 8 luces de OpenGL). Como segundo parametro le digo que voy a modificar la componente de luz ambiente de esa fuente de luz (GL_AMBIENT, mas adelante veremos mas parametros), y como tercer parametro le paso el puntero a la matriz que contiene los valores de tipo float (de ahi la f -float- del nombre de la funcion y la ultima v de glLightfv -vector-)

De forma analoga modificare los demas parametros de una luz.
En este cuadro se ven las posibilidades del segundo parametro de glLight y sus valores por defecto:


Esto nos lleva a ver los tipos de luces en OpenGL, que son tres:

  • Luz direccional. Es la luz que viene de una direccion y sus "rayos" son paralelos porque vienen de una fuente de luz muuuuuy lejana (infinitamente lejana). En el mundo real lo mas parecido es la luz del sol. A OpenGL le indicamos que es una luz direccional cuando la cuarta coordenada de la posicion de la luz es 0.0 (p.e. "GLfloat posicion[] = { 0.0, -1.0, 0.0, 0.0 };"). Las primeras tres coordenadas seran el vector de direccion hacia donde alumbra (no tiene sentido que sea la posicion si es direccional. El ejemplo alumbra hacia abajo).
  • Luz puntual o punto de luz. Es una luz que viene de un punto concreto e ilumina en todas direcciones. En el mundo real el ejemplo seria una bombilla. A OpenGL le indicamos que es una luz puntual cuando la cuarta coordenada de la posicion de la luz es 1.0 (p.e. "GLfloat posicion[] = { 0.0, 2.0, 0.0, 1.0 };"). Las primeras tres coordenadas son la luz del punto de luz o "bombilla".
  • Luz focal o foco (en ingles spotlight). Es una luz emitida por un foco que solo ilumina en una direccion a partir de la luz y solo un cono de ciertas dimensiones. En el mundo real, una linterna o un flexo. OpenGL sabe si es un foco con el valor del parametro GL_SPOT_CUTOFF de la luz. Si es 180 no es foco (emite en todas direcciones, es puntual), si es un valor entre 0.0 y 90.0 OpenGL lo tratara como un foco y usara ese valor como el angulo entre el eje del cono de luz y el borde de este mismo cono:

El parametro GL_SPOT_EXPONENT se usara solo en caso de ser una luz focal y controla si la luz se concentra mas en el centro del cono de luz o se distribuye. El vector de direccion del foco se indica en GL_SPOT_DIRECTION (estos valores se tienen en cuenta solo si es luz focal -GL_SPOT_CUTOFF no 180.0-)

Los tres ultimas opciones del cuadro, son para controlar la atenuacion de la luz, o como la luz ilumina menos cuanto mas lejos esta. De momento las dejaremos como estan (tu si que puedes probar valores si quieres, como en todo).

Llegado a este punto pensamos que la iluminacion no tiene secretos para nosotros pero... ¡sorpresa! falta la parte de como el material de nuestro objeto refleja la luz.

Ya vimos la necesidad de definir normales a la superficie de nuestro objeto pero no vimos como el material con el que esta "hecho" refleja cada componente de la luz que le llega. Esto se hace con la funcion glMaterial:

1
2
GLfloat mat1_ambiente[] = { 1.0, 1.0, 1.0, 1.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT, mat1_ambiente);

Al igual que con los componentes de la fuente de luz, hemos guardado los 4 valores en coma flotante en una matriz. Estos 4 componentes determinan como refleja la superficie esta componente de la luz (las cuatro 0.0 sera que no refleja y se vera negro, otras combinaciones haran la superficie de otros colores -RGB- ) .
El primer parametro indica a que caras del objeto se aplica, GL_FRONT, GL_BACK y GL_FRONT_AND_BACK. La de delante, la de atras o las dos. Si es un objeto cerrado, con la de delante basta.
El segundo parametro indica la caracteristica del material a cambiar. Puede ser GL_AMBIENT, GL_DIFFUSE y GL_SPECULAR para cada componente de la luz en OpenGL. GL_AMBIENT_AND_DIFFUSE para cambiar los valores de luz ambiente y difusa a la vez (son las que determinan el color del objeto). GL_SHININESS es un parametro que modifica la forma de presentar la luz especular, representa el brillo del objeto y es un valor unico de 0 a 255. Por ultimo GL_EMISSION representa la luz que emite el propio objeto y que normalmente sera 0,0,0 para objetos normales pero, por ejemplo, para representar una bombilla pondriamos una esfera en el mismo lugar que una luz puntual y dariamos valor a este parametro.
Merece la pena hacer un resumen de estas opciones de la funcion glMaterial, ya que seran muy usadas y combinadas podremos emular materiales como el oro, plastico brillante o mate, ...:

  • GL_AMBIENT Cantidad de luz ambiente reflejada.
  • GL_DIFFUSE Cantidad de luz difusa reflejada.
  • GL_SPECULAR Cantidad de luz especular reflejada.
  • GL_AMBIENT_AND_DIFFUSE Modifica como refleja la luz ambiente y difusa a la vez (define el color del objeto)
  • GL_SHININESS Define si la luz especular reflejada se concentra mas o menos.
  • GL_EMISSION Cantidad de luz que emite el objeto.

El tercer parametro sera el puntero a los valores para esa caracteristica del material (en el caso de GL_SHININESS no sera un puntero sino el valor derectamente).

Solo queda por ver algunas funciones que modifican la iluminacion de forma general con glLightModel:

1
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE/GL_FALSE);

Este parametro modifica la forma de hacer el calculo del brillo de luz especular. En el primero (GL_TRUE) usara para este calculo un punto fijo del mundo OpenGL con lo que el calculo sera mas lento pero mejor el resultado. En el segundo (GL_FALSE) tomara un punto en el infinito para el calculo, lo que es lo mismo que una direccion. Sera menos costoso pero menos vistoso.

1
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE/GL_FALSE);

Este permite que OpenGL dibuje los poligonos por los dos lados correctamente invirtiendo las normales en caso de verlos desde el otro lado, si lo habilitamos (GL_TRUE). En objetos cerrados nunca veremos la cara interior y no sera necesario.

1
2
Glfloat ambiente_general[ ]={0.2, 0.2, 0.2, 1.0};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambiente_general);

Este ejemplo nos permite habilitar una luz ambiente general para todo lo que dibujemos, de forma que se vera con cierta claridad general.

Con todo lo que sabemos, ahora entenderemos mejor la funcion glShadeModel que ya hemos usado, en realidad sin mucha utilidad hasta ahora.
Esta funcion tiene un parametro que puede ser:

  • GL_FLAT. Lo que hace es que usa el color del primer vertice para cada cara del objeto.
  • GL_SMOOTH. Lo que hace es que interpola el color de cada punto de la cara con el color de los vertices.

En un cubo el tipo de Shademodel no se notara porque cada vertice de una cara tiene la misma normal que las otras y el mismo tono, atendiendo a la luz que le llega, pero una esfera es otra cosa y la diferencia sera patente. Una imagen vale mas que mil palabras:


  • glShadeModel(GL_FLAT);
  • glShadeModel(GL_SMOOTH);
¿Queda claro?.

Ahora lo que apetece es poner manos a la obra y empezar a incluir iluminacion a nuestro programa.

Aprovecho para recordar que la mejor forma de aprender a cocinar es mancharse de harina y huevo, asi que para esto, lo mejor sera que cambiemos de mil formas nuestro programa para ver que hace con cada cambio. Este capitulo es particularmente propicio a probar y ver que pasa.

Tambien aprovecho para colgar en la zona de descargas las librerias de OpenGL que uso con Visual C++ 2005 Express, por si a alguien le hacen falta (incluida glaux.lib y su cabecera). Estas son: LibOpenGLvc2005.zip

Antes de nada vamos a incluir la libreria GLAux a nuestro programa para poder hacer uso de los objetos predefinidos que trae, ya que no podemos de momento cargar nuestro propios modelos. Es una forma de tener rapidamente objetos para ir probando:

1
2
3
4
5
6
// Biblioteca GLAUX de funciones auxiliares. La usaremos solo
// para poder usar objetos que vienen predefinidos, antes de que
// podamos usar los que cargamos nosotros mismos.
#pragma comment( lib, "glaux.lib" )
// Incluimos la cabecera de la lbreria GLAUX.
#include <GL/glaux.h>

Lo primero sera introducir fuera de toda funcion (declarar como global) algunas matrices con datos que vamos a usar mas tarde:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Datos de las componentes ambiente, difusa y especular
// de nuestra fuente de luz.
GLfloat ambiente[] = { 0.2, 0.2, 0.2, 1.0 };
GLfloat difusa[] = { 0.5, 0.5, 0.5, 1.0 };
GLfloat especular[] = { 0.8, 0.8, 0.8, 1.0 };
// Datos de las componentes ambiente, difusa y especular
// de el primer material. Todo 1.0 en difusa y especular sera blanco,
// la luz ambiente se reflejara poco y la escena sera oscurilla.
GLfloat mat1_ambiente[] = { 0.2, 0.2, 0.2, 1.0 };
GLfloat mat1_difusa[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat1_especular[] = { 1.0, 1.0, 1.0, 1.0 };
// Datos de las componentes ambiente, difusa y especular
// de el segundo material.
GLfloat mat2_ambiente[] = { 0.2, 0.2, 0.2, 1.0 };
GLfloat mat2_difusa[] = { 2.0, 2.0, 1.0, 1.0 };
GLfloat mat2_especular[] = { 1.0, 1.0, 1.0, 1.0 };

Despues añadiremos cosas a la funcion IniciaGL(), al final para no liarnos.

Modificamos la posicion de la luz 0 de OpenGL (GL_LIGHT0). Para ello definimos una matriz con los datos y se la pasamos a la funcion glLightfv con la opcion GL_POSITION:

1
2
3
4
// Modificamos la posicion de la luz 0 de OpenGL. 
// El cuarto parametro es un 1.0 para que sea una luz puntual.
GLfloat posicion[] = { 0.5, 4.0, -3.0, 1.0 };
glLightfv(GL_LIGHT0, GL_POSITION, posicion);

Como pone en el comentario, la cuarta coordenada de la posicion es un 1.0, lo que quiere decir que es un punto de luz.
Lo situamos un poco por encima de los objetos. Cambiando la posicion de la luz, la escena cambia totalmente. Pruebalo.

Habilitamos la iluminacion y encendemos la luz 0 (como poner el interuptor en ON).

1
2
3
4
// Habilitamos el calculo de la iluminacion.
glEnable(GL_LIGHTING);
// Encendemos la luz 0.
glEnable(GL_LIGHT0);

Definimos las componentes de la luz emitida por nuestra fuente de luz (0) pasando los punteros de las matrices que definimos al principio del codigo, para almacenar estos datos.

1
2
3
4
5
// Definimos cada una de las componentes de la luz 
// que emite nuestra bombilla (la luz 0).
glLightfv(GL_LIGHT0, GL_AMBIENT, ambiente);
glLightfv(GL_LIGHT0, GL_DIFFUSE, difusa);
glLightfv(GL_LIGHT0, GL_SPECULAR, especular);

Por ahora dejaremos asi definida nuestra bombilla. Es una luz puntual y la hemos puesto el color, la intensidad y la posicion que hemos querido.

Despues, como siempre, nos vamos a la funcion Pinta().

En un punto, antes de pintar nuestro cubo, definimos el material con el que se pintara. En este momento pensaras ¿para que si le habiamos puesto una textura?. Tiene su explicacion.
En la definicion de la textura pusimos el parametro GL_DECAL (en la funcion IniciaGL() ):
glTexEnvf(GL_TEXTURE_2D,GL_TEXTURE_ENV_MODE,GL_DECAL);
y ahora lo cambiaremos a GL_MODULATE:
glTexEnvf(GL_TEXTURE_2D,GL_TEXTURE_ENV_MODE,GL_MODULATE);
Con esto conseguimos que el color e intensidad del material afecte a como se aplica la textura y asi el efecto de la iluminacion sera completo. Podremos hacer el objeto mas brillante o menos aunque este con textura, o darle color y asi mezclarlo con la textura.

Asi pues, definimos el material del cubo:

1
2
3
4
5
6
7
// Definimos el material del objeto modificando la forma en 
// como refleja cada componente de la luz que le llega.
glMaterialfv(GL_FRONT, GL_AMBIENT, mat1_ambiente);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat1_difusa);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat1_especular);
// El brillo especular pequeño (de 0 a 255).
glMaterialf(GL_FRONT, GL_SHININESS, 20);

Despues nos vamos a la definicion de los vertices y añadimos las normales de cada vertice o de cada cara.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Le digo a OpenGL que voy a pintar y con cuadrados:
glBegin(GL_QUADS);
// Cara de arriba
// Quito (comento) los colores que puse en ejercicios anteriores
// ya que uso texturas.
//glColor3f(1,0,0); // rojo.
 
// Coordenadas de textura para el primer vertice.
// Le indico que punto de la textura se va a pintar en este
// vertice.
glTexCoord2d(1.0,0.0);
// Por cada vertice o por cada cara, definimos el vector normal
// a la superficie
glNormal3f(0,1,0);
// Ahora la coordenada del vertice.
glVertex3f( 1.0f, 1.0f,-1.0f);
// Repetimos operacion. Para cada vertice una funcion
// glTexCoor, una glNormal y una glVertex ...
glTexCoord2d(0.0,0.0);
glNormal3f(0,1,0);
glVertex3f(-1.0f, 1.0f,-1.0f);
glTexCoord2d(0.0,1.0);
glNormal3f(0,1,0);
glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2d(1.0,1.0);
glNormal3f(0,1,0);
glVertex3f( 1.0f, 1.0f, 1.0f);
// Cara de abajo
//glColor3f(1,0,0); // rojo
glTexCoord2d(1.0,0.0);
glNormal3f(0,-1,0);
glVertex3f( 1.0f,-1.0f, 1.0f);
glTexCoord2d(0.0,0.0);
glNormal3f(0,-1,0);
glVertex3f(-1.0f,-1.0f, 1.0f);
glTexCoord2d(0.0,1.0);
glNormal3f(0,-1,0);
glVertex3f(-1.0f,-1.0f,-1.0f);
glTexCoord2d(1.0,1.0);
glNormal3f(0,-1,0);
glVertex3f( 1.0f,-1.0f,-1.0f);
// Cara frontal
//glColor3f(0,0,1); // azul
glTexCoord2d(1.0,0.0);
// En esta definimos solo la primera normal para probar.
// El resto de vertices usaran la misma.
glNormal3f(0,0,1);
glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2d(0.0,0.0);
//glNormal3f(0,0,1);
glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2d(0.0,1.0);
//glNormal3f(0,0,1);
glVertex3f(-1.0f,-1.0f, 1.0f);
glTexCoord2d(1.0,1.0);
//glNormal3f(0,0,1);
glVertex3f( 1.0f,-1.0f, 1.0f);
// Cara trasera
//glColor3f(0,0,1); // azul
glTexCoord2d(1.0,0.0);
glNormal3f(0,0,-1);
glVertex3f( 1.0f,-1.0f,-1.0f);
glTexCoord2d(0.0,0.0);
glNormal3f(0,0,-1);
glVertex3f(-1.0f,-1.0f,-1.0f);
glTexCoord2d(0.0,1.0);
glNormal3f(0,0,-1);
glVertex3f(-1.0f, 1.0f,-1.0f);
glTexCoord2d(1.0,1.0);
glNormal3f(0,0,-1);
glVertex3f( 1.0f, 1.0f,-1.0f);
// Cara izquierda
//glColor3f(0,1,0); // verde
glTexCoord2d(1.0,0.0);
glNormal3f(-1,0,0);
glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2d(0.0,0.0);
//glNormal3f(-1,0,0);
glVertex3f(-1.0f, 1.0f,-1.0f);
glTexCoord2d(0.0,1.0);
//glNormal3f(-1,0,0);
glVertex3f(-1.0f,-1.0f,-1.0f);
glTexCoord2d(1.0,1.0);
//glNormal3f(-1,0,0);
glVertex3f(-1.0f,-1.0f, 1.0f);
// Cara derecha
//glColor3f(0,1,0); // verde
glTexCoord2d(1.0,0.0);
glNormal3f(1,0,0);
glVertex3f( 1.0f, 1.0f,-1.0f);
glTexCoord2d(0.0,0.0);
glNormal3f(1,0,0);
glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2d(0.0,1.0);
glNormal3f(1,0,0);
glVertex3f( 1.0f,-1.0f, 1.0f);
glTexCoord2d(1.0,1.0);
glNormal3f(1,0,0);
glVertex3f( 1.0f,-1.0f,-1.0f);
glEnd();

Este codigo merece una explicacion mas detallada.

El unico cambio respecto a anteriores programas es la inclusion de buen numero de funciones glNormal3f(...) , la funcion que usaremos para definir las normales (las que explicamos al principio del capitulo).
El calculo de las normales (no el que hace OpenGL para la iluminacion, si no el nuestro para escribirlas en el codigo), es en el caso del cubo es trivial. Por ejemplo la cara frontal, mirando hacia nosotros,  solo tendra una componente en el eje z de 1 y positiva (0.0, 0.0, 1.0). Asi de facil conseguimos un vector perpendicular a la superficie, hacia fuera del objeto y de 1 de longitud (normalizado).
Cuando poner la direccion correcta de la normal, y ademas de modulo (longitud) 1, no sea tan facil, tendremos que programarnos un calculo o cargarlas con nuestros modelos. Con el cubo, de momento, podemos.

Observad como en algunas caras del cubo hemos puesto una funcion glNormal en antes de cada vertice, y en otras hemos puesto una funcion glNormal por cara, antes de los vertices de esa cara. En un cubo las 4 normales de los vertices de una cara son iguales, con lo que al pasar a OpenGL una normal, la usara hasta que le pasemos otra.

Ahora tenemos una idea clara de los datos que son necesarios para definir un vertice:

  • Color: glColor . Se puede no usar si usamos materiales.
  • Coordenadas de textura: glTexCoord . Solo se tendran en cuenta si ponemos textura al objeto del que forma parte el vertice.
  • Normal: glNormal . La normal a la superficie en ese vertice.
  • Las coordenadas: glVertex. Al final lo mas importante. Se pasara el vertice a la tarjeta grafica con los datos anteriores incluidos.

LLega el momento de usar la libreria GLAux que hemos cargado al principio.
Vamos a pintar con ella una esfera sin textura y con el segundo material que habiamos guardado en matrices globales (material amarillo).
Para ello seguiremos estos pasos.
  1. Desabilitaremos la aplicacion de texturas para que no use la ultima con el siguiente objeto.
  2. Luego definimos el material, tal y como hicimos con el del cubo.
  3. Inicializamos la matrix de modelo cargando la matriz identidad. Si no lo hacemos se sumaran las traslaciones y rotaciones con las anteriores.
  4. Movemos el proximo objeto al punto del espacio de nuestra escena, partiendo ya del eje de coordenadas.
  5. Pinto la esfera con la funcion auxSolidSphere, de la libreria GLAux, que pinta una esfera solida del radio que le digamos.
El codigo sera este:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Desabilito la aplicacion de texturas 2D
glDisable(GL_TEXTURE_2D);
 
// Definimos el material del objeto modificando la forma en
// como refleja cada componente de la luz que le llega.
glMaterialfv(GL_FRONT, GL_AMBIENT, mat2_ambiente);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat2_difusa);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat2_especular);
// El brillo especular pequeño (de 0 a 255).
glMaterialf(GL_FRONT, GL_SHININESS, 20);
 
// Cargo la matriz identidad en la matriz de modelo.
// para colocar desde 0 el proximo objeto.
glLoadIdentity();
// Traslado lo proximo que voy a dibujar
// -2 en al eje X (2 a la izquierda) y -4 en
// el eje Z ( 4 al fondo ).
glTranslatef(-2.0,0,-4.0f);
 
// y dibujo una esfera solida de 1 de radio
// usando la libreria glaux, que para eso la
// hemos cargado.
auxSolidSphere(1);


Para terminar de pintal nuestra escena ponemos el cartel pero esta vez un poco mas pequeño, y como hemos añadido iluminacion, la desabilitaremos para que el cartel se vea tal y como lo hemos cargado de disco.

1
2
3
4
5
// Primero desabilito la iluminacion, para que 
// OpenGL no haga el calculo de luz al pintarlo.
// Queremos simplemente que pinte en pantalla el
// dibujo que hemos cargado de disco, tal cual.
glDisable(GL_LIGHTING);

Tambien habilito la aplicacion de texturas que habia desabilitado para pintar la esfera antes de pintar el cartel:

1
2
// Habilito de nuevo la aplicacion de texturas.
glEnable(GL_TEXTURE_2D);

Y un poco mas pequeño:

1
2
3
4
5
6
7
8
9
10
glBegin(GL_QUADS);
glTexCoord2d(0.0,0.0);
glVertex3i( 0, 0,0);
glTexCoord2d(0.0,1.0);
glVertex3i( 0, 75,0);
glTexCoord2d(1.0,1.0);
glVertex3i( 300,75,0);
glTexCoord2d(1.0,0.0);
glVertex3i( 300,0,0);
glEnd();

Despues habilito de nuevo la iluminacion, que sera la situacion normal en el programa:

1
2
3
4
5
6
7
// Habilito la iluminacion que habia desabilitado
// para pintar el cartel, no sea que lo siguiente
// no se pinte como quiero.
// Lo importante es no perder el control con los
// sucesivos cambios y que en todo momento controlemos
// como se pinta nuestra escena.
glEnable(GL_LIGHTING);

Por fin, depues de todo este trabajo, solo queda compilar y ejecutar para disfrutar de nuestra nueva escena con la iluminacion de una bombilla (luz puntual) sobre los dos objetos:


El codigo completo hasta este punto sera: usw8a.cpp

Pero como el lector atento habra notado, no estaria completo este manual sin comprobar como quedaria nuestra escena con los otros dos tipos de luz alumbrandola, asi que vamos a probar los dos.

El segundo tipo que vamos a probar es la luz direccional y para ello solo hemos de cambiar los parametros de posicion de la luz 0.
Ahora el cuarto componente de la posicion sera un 0.0 para indicarle a OpenGL que se trata de una luz direccional.
Los tres primeros componentes ya no determinan la posicion de la luz en el espacio, si no el vector que indica la direccion hacia donde esta la fuente de luz que nos ilumina.
En nuestro caso la luz vendra de arriba:

1
2
3
4
5
6
7
// Modificamos la posicion de la luz 0 de OpenGL. 
// Para una luz direccional las tres coordenadas definen
// un vector que mara la direccion hacia donde esta la
// fuente de luz.
// El cuarto parametro es un 0.0 para que sea una luz direccional.
GLfloat posicion[] = { 0, 1, 0, 0 };
glLightfv(GL_LIGHT0, GL_POSITION, posicion);

Y el resultado sera este:


El codigo completo hasta este punto sera: usw8b.cpp

Solo queda probar la luz de un foco.
Tendremos que volver a colocar la luz en el espacio de nuestra escena y en el cuarto componente de la posicion poner un 1.0.
Pondremos en el parametro GL_SPOT_CUTOFF un valos distinto a 180, que sera la apertura del cono de luz en grados.
Terminaremos definiendo la direccion hacia la que ilumina el foco con el parametro GL_SPOT_DIRECTION de la funcion glLightfv.
El codigo para definir la luz sera asi:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Modificamos la posicion de la luz 0 de OpenGL. 
// El cuarto parametro es un 1.0 para que sea una luz puntual
// o en este caso, focal.
GLfloat posicion[] = { 0, 4.0, -4.0, 1.0 };
glLightfv(GL_LIGHT0, GL_POSITION, posicion);
 
// Definimos la apertura en grados del cono de luz
// diferente de 180 (seria puntual).
glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 30);
 
// Definimos el vector de direccion hacia donde
// apunta el foco (en este caso abajo).
GLfloat direccion[] = { 0,-1, 0, 0 };
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, direccion);

Y el resultado sera este:


El codigo completo hasta este punto sera: usw8c.cpp

Una sugerencia a modo de practicas de este capitulo es que proveis a poner mas luces y ver como queda.

En el proximo capitulo intentaremos mover un poco la escena, que de momento esta muy parada.




¡Sólo los usuarios registrados pueden escribir comentarios!
+/- Comentarios
Buscar
Fernando Arias  - problemas con glaux   |201.173.218.xxx |11-07-2012 17:47:38
Hola, antes que nada muchas gracias por estos tutoriales e aprendido mucho, lo
siguiente es que no puedo incluir la libreria, ya puse los libs ya los agrege
pero al momento de ponerlo en el programa me marca que no existe nose que
hacer, de antemano gracias
Vicengetorix   |87.221.177.xxx |14-07-2012 18:28:15
En el capitulo, al empezar el codigo, hay un enlace para bajarse las librerias,
los ficheros de cabecera (.h) y las librerias en si (.lib).
Cada uno debe estar
en el directorio adecuado para que VC los encuentre.

3.26 Copyright (C) 2008 Compojoom.com / Copyright (C) 2007 Alain Georgette / Copyright (C) 2006 Frantisek Hliva. All rights reserved."

 


Banner
Spanish Chinese (Simplified) English French German Japanese Portuguese Russian