VON WEGEN SOLL ICH DAS BENUTZEN!..ABER AHH HIER IST ES>
Previo
1.- Investigue cómo crear y definir una fuente de luz en OpenGL
- Creación de la luz
- Cuántas luces se pueden definir
- Parametrización de la fuente de la luz
- Tipos de luces
- Color de la luz
- Habilitación/deshabilitación de luces
- Luz por default y características por default
Luces
Como se ha dicho, una luz aporta iluminación a una escena, según unas determinadas componentes de color.
A partir de ahora distinguiremos entre fuente de luz, como entidad que proporciona luz a una escena, y luz, como aportación de esa fuente a la iluminación de la escena.
Una fuente puede emitir tipos diferentes de luz, que son complementarias, y pueden darse a la vez para un cierto tipo de luz.
El primer paso para utilizar la iluminación en una aplicación OpenGL es activarla, mediante la llamada
glEnable(GL_LINGHTING);
Una vez activada, hemos de establecer las propiedades de cada luz en la escena, y activarlas. La especificación inicial de OpenGL contempla que, al menos, cada implementación debe de poder definir 8 luces, identificadas por las constantes GL_LIGHTn, dónde 'n' es el número de la luz, comenzando por 0.
Una vez habilitadas las luces, hay que indicar los parámetros de estas. Para hacer esto utilizaremos las siguientes funciones: glLightf, glLighti, glLightfv, glLightiv. A continuación veremos algunos de los parámetros mas importantes de las luces, y como modificarlos:
· Posición y tipo de luz
Obviamente, si hay una luz, hay que indicar en que posición de la escena esta. Esto se consigue llamando a la siguiente función:
void glLightfv( GLenum light, GLenum pname, const GLfloat *params );
donde light es el identificador de la luz (GL_LIGHTi)
pname = GL_POSITION
params es un vector del tipo GLfloat position[4];
Con esta llamada indicamos dos cosas.
* Si params[3] tiene un valor igual a 0.0, entonces indicamos que es una luz direccional. En este caso el vector (params[0], params[1], params[2]), da el vector de la dirección de la luz.
* Si params[3] tiene un valor igual a 1.0, entonces indicamos que es una luz puntual. El vector (params[0], params[1], params[2]) indica la posición de la luz
· Color de la luz
Los colores de las luces en OpenGL tienen tres componentes:
*Ambiente
Esta componente afecta a todos los objetos de la, independientemente de la posición o orientación de estos. Viene a emular la luz que en el mundo real viene dada por la reflexión difusa en las paredes, la luz solar indirecta, etc.
*Difusa
Se puede pensar en ella como en el verdadero color de la luz. Su influencia sobre una superficie de un objeto depende de su orientación y su distancia.
*Especular
Influye en el brillo que va a tener el objeto.
Estas componentes se pueden modificar con la siguiente función :
void glLightfv( GLenum light, GLenum pname, const GLfloat *params );
donde light es el identificador de la luz (GL_LIGHTi)
pname = GL_AMBIENT, GL_DIFFUSE o GL_SPECULAR, dependiendo de que componente se quiere modificar.
params es un vector del tipo GLfloat color[4];
El formato de params debe ser el siguiente:
* color[3] debe valer 1.0
* (color[0], color[1], color[2]) da el vector RGB del color.
Los materiales de los objetos tienen las mismas componentes que la los colores de la luz. Vienen a indicar la reflectancia del material a cada una de las componentes de la luz. Para indicar el material de los objetos que se van a renderizar a continuación se debe utilizar la siguiente función :
void glMaterialfv( GLenum face, GLenum pname, const GLfloat *params );
Donde :
* face indica a que caras se van a modificar. Puede valer GL_FRONT, GL_BACK o GL_FRONT_AND_BACK, pero casi siempre trabajaremos con GL_FRONT.
* pname indica que componente se va a modificar. Puede valer GL_AMBIENT, GL_DIFFUSE o GL_SPECULAR.
* params es un vector de cuatro componentes que indica el nuevo valor del color. (params [0], params [1], params [2]) da el vector RGB del color. params [3] debe valer 1.0.
Para establecer las propiedades de una luz utilizaremos llamadas a las funciones del tipo glLight*(). Las propiedades de toda luz son las siguientes:
- Posición/Dirección:
Indica la posición/dirección de la luz, y especifica si ésta es una luz posicional o direccional. Una luz posicional tiene una posición concreta en el espacio, mientras que una luz direccional consiste en un conjunto de haces de luz paralelos. Un ejemplo de luz posicional es una lámpara, mientras que, debido a su distancia, podríamos considerar al sol como una fuente de luz direccional. Las luces posicionales pueden ser de dos tipos: luces puntuales, que emiten luz a su alrededor de manera radial, y en todas direcciones, y luces focales, que emiten luz en una dirección concreta, en un radio de acción con forma de cono (como un foco).
“Emitted” (emitida): es la luz emitida por un objeto. No se ve afectada por ningún otro tipo de luz. Por ejemplo, un fuego emite una determinada luz, y si lo miramos, lo veremos de ese color, independientemente del color de las luces que estén apuntando al fuego.
“Diffuse” (difusa): es la luz que índice sobre un objeto, y proviene de un determinado punto. La intensidad con la que se refleja en la superficie del objeto puede depender del ángulo de incidencia, dirección, etc. Una vez incide sobre un objeto se refleja en todas direcciones.
“Specular” (especular): es la luz que, al incidir sobre un objeto, se ve reflejada con un ángulo similar al de incidencia. Podemos pensar que es la luz que produce los brillos.
“Ambient” (ambiental): podemos considerarlo como los restos de luz que aparecen defido a la reflexión residual de una luz que ya se ha reflejado sobre muchos objetos, y es imposible determinar su procedencia. Es algo así como la iluminación global de una escena.
Para establecer esta propiedad utilizaremos la llamada:
glLightfv(GL_LIGHTn,GL_POSITION,val_ptr);
“val_prt” es un puntero a un vector de cuatro componentes de tipo float, de la forma (x,y,z,w). En el caso de que w sea 1, estaremos ante una luz posicional, y su posición está determinada por (x,y,z). Si w es 0, la luz es direccional, y su dirección es el vector (x,y,z).
- Dirección del foco:
En el caso de una luz focal, debemos establecer su dirección. Esto lo haremos con la llamada:
glLightfv(GL_LIGHTn,GL_SPOT_DIRECTION,val_prt);
“val_ptr” es un puntero a un vector con la dirección, en formato (x,y,z).
- Apertura del foco:
El ángulo de apertura del foco se define mediante:
glLightf(GL_LIGHTn,GL_SPOT_CUTOFF,val);
“val” expresa en grados la mitad del ángulo de apertura del foco.
- Atenuación del foco:
La atenuación del foco (degradación de la intensidad a medida que nos acercamos al borde) se define mediante:
glLightf(GL_LIGHTn,GL_SPOT_EXPONENT,val);
- Intensidad de la luz:
Define el color ambiental, difuso y especular de la luz. Se define mediante la llamada:
glLightfv(GL_LIGHTn,GL_[AMBIENT|DIFFUSE|SPECULAR],val_ptr);
“val_ptr” es un puntero a un vector de cuatro componentes de color RGBA.
- Atenuación de la luz
Define la pérdida de intensidad de la luz a medida que nos alejamos del foco (no afecta a las luces direccionales). Se establece mediante:
glLightf(GL_LIGHTn,GL_[CONSTANT|LINEAR|QUADRATIC]_ATTENUATION,val);
Una vez establecidas las propiedades de una determinada luz, las activaremos con la llamada:
glEnable(GL_LIGHTn);
Para desactivarla se utiliza:
glDisable (GL_LIGTHn);
2.- Investigue la diferencia entre luz e iluminación (light/lighting)
- Habilitación/deshabilitacion de la iluminación (¿cómo?)
-¿Para qué hay que habilitar o deshabilitar la iluminación?
La iluminación de OpenGL se basa en luces y materiales. Una luz es una fuente de iluminación para la escena. Emite un haz de luz de un color determinado, dividido en las tres componentes de color RGB. Un material determina la cantidad de cada color que refleja un objeto determinado.
Por ejemplo, si un objeto tiene un material de color rojo -RGB(1,0,0)-, es decir, refleja todo el color rojo, y es iluminado por una luz blanca -RGB(1,1,1)-, reflejará toda la componente de color rojo, pero nada de la verde y azul, por lo que se verá de color rojo. Si este mismo objeto fuese iluminado por una luz verde -RGB(0,1,0)-, se vería de color negro, al no tener nada de luz roja que poder reflejar. Además, dependiendo del tipo de luz, el color final con el que se vea el objeto puede verse afectado por el ángulo de incidencia de la luz, la distancia a esta, etc.
Para especificar la iluminación de una escena hay que decidir como seran las luces, y cuales seran los materiales de los objetos de las escenas. Por defecto la iluminación esta deshabilitada. Lo primero que hay que hacer si se desea utilizar luces es habilitarlas.
Para activar y desactivar todo el cálculo de iluminación se utiliza:
glEnable(GL_LIGHTING);
glDisable (GL_LIGTHING);
3.- Investigue la definición de propiedades de material a una superficie
-Características de los materiales (difuso, especular, brillantes, emisividad, etc.)
-Cómo se definen
-Sobre qué cara(s) de un polígono se aplican los materiales.
ESPECIFICACIÓN DE LOS MATERIALES.
Antes de empezar a activar luces como unos cosacos tenemos 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.
Por tanto tenemos que decirle a OpenGL de que forma tendrá que tratar a cada trozo de geometría.
Se definen 5 características fundamentales para u 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 entre si.
- 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 al 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 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 );
n los valores que puedan adoptar los parámetros de la función. En este 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 posibilidades son las que hemos comentado para un material. De hecho son bastante obvias si miramos las constantes que podemos usar. 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 glMateriali y glMaterialiv. No suelen usarse por eso las versiones llamadas escalares (enteral) 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 0.0 en GL_EMISSION y GL_SPECULAR. Por supuesto tendremos que retocar estos valores hasta conseguir el efecto deseado.
4.- Investigue acerca del mapeo de texturas en OpenGL
- Carga/definición del bitmap
- Transformaciones de la textura
- Modos de aplicación de una textura(repeat, wrap, etc.)
- Mapeo de la textura a una superficie
Texturas
Las texturas permiten personalizar aún más el material de un objeto, y nos permiten obtener imágenes mucho más realistas en nuestras escenas. Por ejemplo, si queremos dibujar una pared de ladrillo, tenemos dos opciones: dibujar cada ladrillo, definiendo su material con colores, y dibujar el cemento entre los ladrillos, a base de polígonos, definiendo también su material, o dibujar un único cuadrado con la extensión de la pared, y hacer que su material, sea, por ejemplo, la foto de una pared de ladrillo.
Poner texturas a un objeto es como poner papel pintado en una pared. Cuando se esta dibujando un polígono, es posible indicar que se dibuje este polígono con una imagen, indicándole para cada vértice del polígono, que posición de la imagen le corresponde. Es posible mapear texturas en una, dos y tres dimensiones.
Para dibujar un objeto con texturas hay que seguir los siguientes pasos:
· Habilitar el mapeado de texturas
Esto se hace ejecutando la siguiente instrucción:
glEnable(GL_TEXTURE_2D);
· Especificar que imagen va a ser utilizada como textura
Para ello se utiliza la siguiente función:
void glTexImage2D( GLenum target, GLint level, GLint components, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels );
Donde:
· target debe valer GL_TEXTURE_2D
· level indica el nivel de detalle de la textura. Esto no se explica aquí, y habitualmente tiene un valor 0.
· components indica el nº de componentes del color. Usualmente se usan componentes RGB, y especificaremos 3. Pero también se pueden hacer texturas semitransparentes, con lo que se utiliza un formato RGBA (4 componentes). En ese caso indicaríamos un valor de 4.
· width indica el ancho de la imagen de la textura. Debe ser una potencia de 2.
· height indica el alto de la imagen de la textura. Debe ser una potencia de 2.
· border indica si se utiliza un borde en la textura (1) o no (0). Usualmente es 0.
· format indica el formato del valor de cada pixel. Normalmente se utiliza GL_RGB.
· type indica el tipo de datos usado para cada componente del valor de un pixel. Puede ser uno de los siguientes valores: GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT o GL_FLOAT.
· pixels es un puntero al mapa de valores de los pixels. Es la imagen en si.
La imagen se puede obtener de dos formas. Una, generándola con código del propio programa. Esto es fácil si la textura es sencilla, como puede ser un tablero de ajedrez. Si la imagen es más complicada, hay que cargarla de un archivo. En el ejemplo que damos aquí, se muestra una función para cargar una textura a partir de un archivo BMP de Windows.
· Mapear la textura
Cuando se esta dibujando el objeto, hay que indicar, para cada vértice de este, que posición de la textura le corresponde. Esto se hace mediante la siguiente función:
void glTexCoord2f( GLfloat s, GLfloat t);
Donde (s,t) indica una posición sobre el mapa de la imagen.
Lo que se hace es indicar la coordenada de la textura antes de indicar el vértice del polígono. A continuación vamos a ver dos funciones, donde se dibujan un cuadrado y un triangulo, indicando las posiciones de la textura:
void Cuadrado(void)
{
glBegin(GL_QUADS);
glTexCoord2f(0.0,1.0);glVertex3f(-1.0,1.0,0.0);
glTexCoord2f(1.0,1.0);glVertex3f(1.0,1.0,0.0);
glTexCoord2f(1.0,0.0);glVertex3f(1.0,-1.0,0.0);
glTexCoord2f(0.0,0.0);glVertex3f(-1.0,-1.0,0.0);
glEnd();
}
void Triangulo(void)
{
glBegin(GL_QUADS);
glTexCoord2f(0.0,1.0);glVertex3f(-1.0,1.0,0.0);
glTexCoord2f(1.0,0.0);glVertex3f(1.0,-1.0,0.0);
glTexCoord2f(0.0,0.0);glVertex3f(-1.0,-1.0,0.0);
glEnd();
}
* Indicar como la textura va a ser aplicada a cada pixel
Aquí hay varios puntos que indicar. El primero de ellos es indicar que ocurre con el tamaño de las texturas. Cuando uno referencia las coordenadas de las texturas, se indican valores entre 0 y 1, que dan los límites de las texturas. Cuando uno referencia un valor mayor que 1 o menor que 0, se esta fuera del mapa de la imagen. ¿Que hacer en estos casos?. Hay dos posibilidades. La primera es repetir los píxeles de los bordes de la textura cuando se referencie fuera de ella, lo cual no parece que tenga mucha utilidad. La otra posibilidad es la de repetir la textura. Esto es, en lugar de tener un mapa con solo una imagen, se tiene un mapa donde la imagen de la textura esta repetida infinitas veces, unas contiguas a las otras.
Imaginemos que tenemos que la imagen de la textura es la imagen de una baldosa, y queremos dibujar un suelo que vaya a contener 20x20 baldosas. Entonces, para dibujar este suelo solo tendríamos que poner un código tal que así:
glBegin(GL_QUADS);
glTexCoord2f(0.0,20.0);glVertex3f(-1.0,1.0,0.0);
glTexCoord2f(20.0,20.0);glVertex3f(1.0,1.0,0.0);
glTexCoord2f(20.0,0.0);glVertex3f(1.0,-1.0,0.0);
glTexCoord2f(0.0,0.0);glVertex3f(-1.0,-1.0,0.0);
glEnd();
Para indicar si se quiere repetir el borde de la textura, o se quiere repetir la textura completa se utiliza la siguiente función:
void glTexParameterf( GLenum target, GLenum pname, GLfloat param );
Donde:
* target debe valer GL_TEXTURE_2D.
* pname puede valer GL_TEXTURE_WRAP_S o GL_TEXTURE_WRAP_T, donde el primero indica las coordenadas X de la textura, y el segundo las coordenadas Y.
* param indica si queremos que se repita el borde de la textura (GL_CLAMP) o si queremos que se repita la textura completa (GL_REPEAT).
Otro de los parámetros a tener en cuenta es el filtrado de las texturas. Cuando la cámara esta muy cerca de un objeto con texturas, debido al efecto del mapeado se pueden notar con mucha claridad la diferencia entre los píxeles contiguos de la textura, que se ven como unos cuadrados mas grandes cuanto mas cerca se esta del objeto.
Un efecto desagradable aparece también cuando se esta lejos de las texturas. Si se tiene objeto lejano con una textura del tipo de un tablero de ajedrez, debido a que solo se dibujan algunos de los píxeles de la textura, pueden aparecer formas muy extrañas en la textura.
Si se quiere evitar de forma parcial este efecto, existe la posibilidad de filtrar las texturas. Esto se hace con la siguiente llamada :
void glTexParameterf( GLenum target, GLenum pname, GLfloat param );
Donde:
* target debe valer GL_TEXTURE_2D.
* pname puede valer GL_TEXTURE_MIN_FILTER o GL_TEXTURE_MAG_FILTER, segun se este especificando un filtro para cuando la textura este lejos o cerca.
*param indica el tipo de filtro a aplicar. Puede valer GL_NEAREST o GL_LINEAR. El primero indica que no se filtran las texturas. El segundo indica que se va ha hacer un filtrado lineal de las texturas. Hay que tener en cuenta que aplicar un filtrado a las texturas es muy costoso en tiempo.
Las coordenadas de textura
Para saber qué partes de una imagen se dibujan en un polígono (por ejemplo un triángulo), utilizamos lo que se denominan coordenadas de textura, o coordenadas UV.
De esta manera, si queremos dibujar un triángulo con una textura, y aplicamos a cada vértice las coordenadas de textura indicadas en la figura, tenemos el siguiente resultado:
Aplicar las texturas
Para aplicar una textura tenemos que seguir una serie de pasos muy definidos:
1. Creamos la textura
2. Definimos las condiciones en que se va a aplicar la textura
3. Habilitar la aplicación de texturas
4. Dibujar las escenas, proporcionando las coordenadas de textura
Como ejemplo sencillo, vamos a ir viendo cómo se ha creado el ejemplo del mapeado de texturas:
- Creación de la textura [TEXT]:
Primero hemos de obtener un identificador para la textura. Para ello pedimos a OpenGL que nos devuelva un identificador de textura libre:
int texture;
glGenTextures(1,&texture);
Activamos la textura como textura activa:
glBindTexture(GL_TEXTURE_2D,texture);
Creamos la textura. El modo más sencillo de hacerlo es a través de una función de GLU que crea la textura y sus variaciones a aplicar según la distancia a la que se encuentre:
gluBuild2DMipmaps( GL_TEXTURE_2D, gimp_image.bytes_per_pixel,
gimp_image.width, gimp_image.height,GL_RGB, GL_UNSIGNED_BYTE,
gimp_image.pixel_data );
Con el primer parámetro indicamos el tipo de textura. En este caso (GL_TEXTURE_2D) es una textura 2D. Los siguentes parámetros indican el número de bytes por cada pixel, que dependerán de la imágen (p. ej. 3 para RGB y 4 para RGBA; en este caso, la imágen es de tipo RGB), su anchura y altura (que han de ser pares, y muy recomendable, múltiplos de 2), el formato de los datos (GL_RGB, GL_RGBA,...), el tipo de los datos, que en nuestro caso vendrá dado por bytes sin signo, por lo que usaremos la constante GL_UNSIGNED_BYTE, y finalmente, un puntero a los datos.
En este ejemplo, hemos utilizado una estructura para generar la imagen con el siguiente formato:
static const struct {
unsigned int width;
unsigned int height;
unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */
unsigned char pixel_data[128 * 128 * 3 + 1];
} gimp_image = {
128, 128, 3, [...] }
Este formato de datos es producido de manera automática por el programa “Gimp” al grabar una imágen como un archivo en “c”.
- Definir las condiciones en que se va a aplicar la textura:
Estas condiciones se establecen a través de la función glTexEnvf().
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
En nuestro caso, hemos especificado que la textura se va a fundir con el color de fondo del polígono (GL_MODULATE), aunque bien podría sustituirlo (usando GL_REPLACE).
La fusión con el color de fondo se utiliza para aplicar la iluminación a un objeto con textura. En el ejemplo vemos cómo se visualiza un objeto iluminado, con la textura aplicada mediante GL_MODULATE, y mediante GL_REPLACE:
- Habilitar la aplicación de texturas:
Mediante:
glEnable(GL_TEXTURE_2D);
- Dibujar la geometría proporcionando las coordenadas de textura de cada vértice:
glBegin(GL_TRIANGLES);
glTexCoord2d(0.0,1.0);
glVertex3f(-0.5,-0.5,0.5);
glTexCoord2d(1.0,1.0);
glVertex3f(0.5,-0.5,0.5);
glTexCoord2d(0.5,0.0);
glVertex3f(0.0,0.5,0.5);
glEnd();
Si en algún momento queremos cambiar la textura activa, tan sólo hemos de indicar qué textura queremos activar mediante la llamada:
glBindTexture(GL_TEXTURE_2D,texture);
“texture” es el identificador de la textura que queremos activar.
El código completo de los ejemplos utilizados puede verse en el anexo A.
Repetición de texturas
Imaginemos que queremos dibujar una pared de ladrillos junto a un césped, y tenemos estas dos texturas, para la pared y el suelo:
El suelo va a ser u cuadrado, y la pared un rectángulo, y vamos a mapear las esquinas del suelo y de la pared con las esquinas de de las texturas (código completo en el anexo A):
glBindTexture(GL_TEXTURE_2D,texture_floor);
glBegin(GL_QUADS);
glTexCoord2d(0.0,0.0);
glVertex3f(-6.0,0.0,-6.0);
glTexCoord2d(0.0,1.0);
glVertex3f(-6.0,0.0,6.0);
glTexCoord2d(1.0,1.0);
glVertex3f(6.0,0.0,6.0);
glTexCoord2d(1.0,0.0);
glVertex3f(6.0,0.0,-6.0);
glEnd();
glBindTexture(GL_TEXTURE_2D,texture_wall);
glBegin(GL_QUADS);
glTexCoord2d(0.0,0.0);
glVertex3f(-6.0,4.0,-6.0);
glTexCoord2d(0.0,1.0);
glVertex3f(-6.0,0.0,-6.0);
glTexCoord2d(1.0,1.0);
glVertex3f(6.0,0.0,-6.0);
glTexCoord2d(1.0,0.0);
glVertex3f(6.0,4.0,-6.0);
glEnd();
Un aspecto a resaltar es que la operación glBindTexture, para seleccionar cuál es la textura activa en este momento, tiene que realizarse fuera del contexto de glBegin/glEnd, o de lo contrario no funcionará.
Como podemos observar, los ladrillos de la pared salen demasiado alargados, y el suelo demasiado distorsionado, por el hecho de que estamos agrandando las texturas para acomodarlas al tamaño de los objetos.
Pero, ¿y si repetimos las texturas? Por ejemplo, podríamos repetir la textura de la en 3 divisiones verticales, y la del suelo 36 veces (6 horizontales x 6 verticales).
Para ello, debemos especificar que queremos repetir las texturas con las siguientes llamadas a función:
glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
La primera permite que las texturas se repitan en horizontal, y la segunda, en vertical. Con este cambio, podríamos mapear las texturas con coordenadas mayores a 1, de manera que las texturas se repetirían, de esta manera:
glBindTexture(GL_TEXTURE_2D,texture_floor);
glBegin(GL_QUADS);
glTexCoord2d(0.0,0.0);
glVertex3f(-6.0,0.0,-6.0);
glTexCoord2d(0.0,6.0);
glVertex3f(-6.0,0.0,6.0);
glTexCoord2d(6.0,6.0);
glVertex3f(6.0,0.0,6.0);
glTexCoord2d(6.0,0.0);
glVertex3f(6.0,0.0,-6.0);
glEnd();
glBindTexture(GL_TEXTURE_2D,texture_wall);
glBegin(GL_QUADS);
glTexCoord2d(0.0,0.0);
glVertex3f(-6.0,4.0,-6.0);
glTexCoord2d(0.0,1.0);
glVertex3f(-6.0,0.0,-6.0);
glTexCoord2d(3.0,1.0);
glVertex3f(6.0,0.0,-6.0);
glTexCoord2d(3.0,0.0);
glVertex3f(6.0,4.0,-6.0);
glEnd();
La textura de la pared ha sido mapeada entre (0,0) y (3,1), para repetirla 3 veces horizontalmente, y la textura del suelo entre (0,0) y (6,6). El resultado es sensiblemente distinto:
1 comment:
Muy interesante !!
Estoy aprendiendo OpenGl :D
Post a Comment