"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
Miércoles 13 de Diciembre 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...


7. Texturas Imprimir Correo electrónico
Videojuegos - Curso de Programación de juegos
Escrito por Vicengetorix   
Introducimos texturas en nuestro programa y el cambio es radical. Ahora cualquier cosa que ponemos en pantalla con una bonita textura luce como nunca. Esto nos obligara a desarrollar nuestra faceta artistica. Veremos como avanza nuestro programa. Veremos tambien otras cosas con las que nos encontraremos, como la pila de matrices y el blending (para transparencias). Todo clarito clarito como siempre.


Por si alguien no lo tiene claro explicaremos lo que es una textura.
Tenemos una imagen digital en el ordenador. Puede ser una foto que nos hemos descargado de nuestra camara, de las ultimas vacaciones, o un dibujo que hemos escaneado o un borratajo que hemos hecho en el Paint de Windows. Esta imagen puede estar en cualquier formato de imagen digital como BMP, GIF, JPG, TGA, PNG, ... (son las extensiones de los archivos).
Pues cualquier imagen asi puede ser una textura y puede ser usada en nuestro programa.
Esta imagen se carga desde el disco (normalmente con una libreria especializada pero podriamos programarlo nosotros), se le da un identificativo y la forma de usarla a OpenGL y se utiliza de relleno de los poligonos que pintamos en OpenGL, en vez de usar un color plano como hemos hecho en anteriores capitulos.
La forma de aplicar las imagenes a los poligonos son muchas: una imagen por cuadrado, una imagen entera que ocupa varios triangulos, una imagen repetida varias veces horizontal y verticalmente a modo de mosaico,...
En este caso usaremos la primera opcion. Mas adelante veremos mas.

Veremos ahora una serie de conceptos sobre texturas y OpenGL.

OpenGL no carga nada desde disco, ni texturas ni modelos 3D hechos con programas de diseño 3D. Por eso usamos Corona para la carga de texturas. Mas adelante veremos carga de modelos.

Las texturas deben tener medidas que sean 16, 32, 64, 128, 256, 512, 1024, ... potencias de 2. ¿Por que? Pues porque OpenGL esta hecho asi, y si no seguimos esta norma los programas no funcionaran o se pararan. Mas tarde se han habilitado extensiones para evitar esto pero no cuesta nada modificar el tamaño de nuestras texturas.
Llegado a este punto pensaras que habra imagenes que esten achatadas por ejemplo. Pues no porque aunque uses una textura achatada si la aplicas a un cuadrado con el tamaño correcto se vera bien.
Las texturas en OpenGL pueden ser de 1 dimension (1D), 2 dimensiones (2D) o 3 dimensiones (3D). Nosotros usaremos las de 2D (una imagen normal con ancho y alto)

Estas son las dos imagenes que vamos a usar en este ejemplo:



Las dos con medidas potencia de 2. El cuadrado decorativo es de la web CGTextures.

Para cargar las imagenes en nuestro programa usaremos la libreria Corona ya que ademas de ser gratuita, es muy facil de usar y carga los tipos de imagen mas importantes.
Para usar Corona copiaremos el fichero corona.lib en el directorio de librerias del Visual C++ y copia el fichero corona.dll en el directorio de tu programa. Puede ser que al linkar de conflicto por que ya estan definidos simbolos. Eso se arrega metiendo "MSVCRT" en el apartado de propiedades del proyecto, en "vinculador-omitir biblioteca especifica". A mi me ha pasado.
En el codigo incluiremos:

1
#pragma comment( lib, "corona.lib" ) // Biblioteca Corona para graficos
y
1
#include "corona/include/corona.h"  

con lo que añadimos la libreria y el fichero de definiciones y ya podemos usar Corona.

Tambien sacaremos de la funcion IniciaGL() la variable RECT rect y la convertimos en global para su uso desde cualquier parte del programa.
Definimos tambien de forma global dos GLuint (tipo unsigned int pero para OpenGL) para los identificativos de nuestras texturas.

1
GLuint tex1, tex2;  // Para los id's de texturas que genera OpenGL.

Empezamos con los cambios en la funcion IniciaGL().
Lo primero es que desaparece la definicion de rect, que habiamos hecho global, el resto lo añadimos al final.

Definimos un puntero a un objeto image de Corona, que nos servira para cargar las texturas desde disco.

1
corona::Image* imagen=NULL; 

Luego cargamos la imagen desde disco indicando a Corona el fichero y el tipo de imagen a la que queremos que la convierta, en nuestro caso R8G8B8A8 que no quiere decir mas que cada pixel de la imagen estara formado por 8 bits de rojo(R), 8 bits de verde(G), 8 bits de azul(B) y 8 bits de canal Alfa que se usa para transparencias. Este formato es usado por OpenGL y por eso lo hacemos.

1
imagen = corona::OpenImage("cuad.png", corona::PF_R8G8B8A8);

Ahora genero el identificativo OpenGL de nuestra pimera textura en una de las variables que defini de forma global como GLuint. El primer parametro es el numero de identificativos de textura a generar. Nosotros lo haremos de una en una. El segundo parametro es la direccion de la variable donde dejara el identificativo.

1
glGenTextures(1, &tex1);

Ahora le digo a OpenGL que voy a usar esta textura cuyo identificativo he creado hasta que no diga lo contrario. A partir de aqui las funciones sobre texturas seran contra ella.
El primer parametro es el tipo de textura (2D) y el segundo la variable donde esta el identificativo.

1
glBindTexture(GL_TEXTURE_2D, tex1);

Ahora debo pasarle a OpenGL la informacion de la imagen a usar como textura, sobre todo los pixels que la forman para que la guarde en la memoria de video (o no, el lo gestionara a partir de aqui).
Lo haremos ahora con la funcion gluBuild2DMipmaps, una funcion de la libreria GLU que nos facilita la vida porque nos hace mipmaps de la imagen automaticamente.

Pero, ¿que son los mipmaps?. Pues cogemos una imagen y hacemos, partiendo de ella, una serie de imagenes iguales pero cada vez mas pequeñas. Y ¿para que? pues para que cuando presentemos esa imagen muy lejana no tengamos que tratar la imagen original entera inutilmente, ya que desde esa distancia no se va apreciar y nos consumira mas tiempo. Es una forma de que nuestro programa vaya mas rapido, y gracias a dios podemos hacer eso solo con una sola funcion.
En este grafico se ve mas claro:



Los parametros de la funcion gluBuild2DMipmaps son:
  1. Es en 2D (GL_TEXTURE_2D).
  2. 4 porque cada pixel ocupa 4 bytes con RGBA;
  3. Ancho de la imagen. Nos lo da una funcion de Corona.
  4. Alto de la imagen. Nos lo da una funcion de Corona.
  5. Tipo de imagen (RGBA);
  6. Como tratar los datos de la imagen (GL_UNSIGNED_BYTE).
  7. Puntero a la imagen en si, los pixels. Nos lo da una funcion de Corona.
El codigo:

1
2
3
gluBuild2DMipmaps( GL_TEXTURE_2D, 4, imagen->getWidth(), 
imagen->getHeight() , GL_RGBA,
GL_UNSIGNED_BYTE, imagen->getPixels() );

Despues van una serie de funciones que definen como se aplicara esa textura a la hora de usarla en poligonos y en pantalla.

La primera es como va a calcular el color de un pixel en funcion de si el pixel correspondiente de la imagen debe cubrir un area mayor en pantalla o si debe cubrir un area menor (por ejemplo: una imagen cargada en disco de 16 x 16 la asignamos a un cuadrado que en pantalla tendra 100 x 100. O al contrario una imagen de disco de 512 x 256 la aplicamos a un cuadrado que en pantalla sera de 20 x 10).
En nuestro programa pondremos:

1
2
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,
GL_NEAREST_MIPMAP_LINEAR );

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,
GL_NEAREST_MIPMAP_LINEAR );

Una funcion para cada caso. Los posibles valores son combinaciones de LINEAR y NEAREST porque en este caso estamos trabajando con mipmap que complica el asunto.
En la siguiente textura lo veremos mas claro, LINEAR suaviza la imagen por que interpola valores de los pixels adyacentes y NEAR la hace mas escalonada.

Solo queda definir el modo en que se aplica la textura sobre el color del poligono.
DECAL y REPLACE simplemente de pone el dibujo en el poligono sin importar el color de este. MODULATE y BLEND se podrian usar con iluminacion uno, ya que modifica la textura segun el color del poligono y para transparencia el otro.
Ahora vamos a usar DECAL:

1
glTexEnvf(GL_TEXTURE_2D,GL_TEXTURE_ENV_MODE,GL_DECAL);

Ya solo queda borrar el objeto imagen de Corona, ya que tenemos cargado en OpenGL la imagen.

1
if(imagen!=NULL) delete imagen

Cargamos despues la segunda imagen con el puntero a imagen Corona que temenos ahora libre y de forma analoga a la primera imagen, generamos identificativo de textura en la otra variable que habiamos definido y la seleccionamos para trabajar con ella:

1
2
3
imagen = corona::OpenImage("uswg.png", corona::PF_R8G8B8A8);
glGenTextures(1, &tex2);
glBindTexture(GL_TEXTURE_2D, tex2);

Esta vez no generamos mipmaps y usaremos el metodo normal de OpenGL, la funcion glTexImage2D que carga la textura desde el puntero que le pasamos y la guarda para su uso posterior.
Los parametros de esta funcion son:
  1. Es de 2D (GL_TEXTURE_2D).
  2. Es para mipmaps manuales y no lo usamos, pondremos 0.
  3. Tipo de imagen, de nuevo RBGA (GL_RGBA).
  4. Ancho de la imagen. Lo cogemos desde el objeto de imagen de Corona.
  5. Alto de la imagen. Lo cogemos desde el objeto de imagen de Corona.
  6. Borde. Nosotros no lo usamos asi que sera 0.
  7. El formato de nuevo (GL_RGBA).
  8. Tipo en que almacena la textura (GL_UNSIGNED_BYTE).
  9. Puntero a los pixels de la imagen. Lo cogemos desde el objeto de imagen de Corona.

1
2
3
4
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imagen->getWidth(),
imagen->getHeight(),
0, GL_RGBA, GL_UNSIGNED_BYTE,
imagen->getPixels());

Ahora, igual que antes, la forma en que aplicara esta textura.

El MIN_FILTER y MAG_FILTER pero esta vez es mas sencillo, solo hay dos opciones: GL_LINEAR, opcion con la que interpola el color con los pixels adyacentes y da un resultado suavizado.
GL_NEAREST, opcion con la que elegira simpemente el color del pixel mas cercano y se vera la imagen escalonada. Es cuestion de probar en cada caso.

1
2
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

Luego, lo mismo que en la textura anterior, la forma en que se aplica el color de cada pixel de la textura sobre el poligono (cuadrado, triangulo, ...), si tiene en cuenta y como el color de fondo del poligono. En nuestro caso solo tendra en cuenta el color de la textura.

1
glTexEnvf(GL_TEXTURE_2D,GL_TEXTURE_ENV_MODE,GL_DECAL)

Para terminar borramos el objeto imagen de Corona que habiamos creado al cargar la textura del disco, y que ya no nos hace falta porque la tenemos cargada y gestionada por OpenGL.

1
if(imagen!=NULL) delete imagen;

Ya hemos terminado con la carga y definicion de las texturas, y estamos preparados para
usarlas, para pintar con ellas. Vamos a modificar la funcion Pinta().

El primer cambio es cambiar la posicion del objeto a pintar (era un cubo) para que quede mejor en pantalla.

1
glTranslatef(1,0,-4.0f);

Despues de mover y rotar el objeto que todavia no hemos pintado le decimos a OpenGL que vamos a usar texturas para aplicarlas a el objeto que dibujemos (podriamos hacerlo antes que mover, rotar y escalar. Da igual).
Activamos el modo textura 2D:

1
glEnable(GL_TEXTURE_2D);

Le decimos cual de las texturas usar:

1
glBindTexture(GL_TEXTURE_2D, tex1);

Ahora le pasamos a OpenGL los datos del cubo como haciamos en el capitulo anterior pero con dos cambios. Quitamos las funciones glColor, ya que no vamos a usar color sino textura, e incluimos la funcion glTexCoord2d o glTexCoord2f antes de cada funcion glVertex. Esto quiere decir que le damos a OpenGL las coordenadas de textura de cada vertice antes de darle las coordenadas del vertice... ¿Coordenadas de textura? pues si. Haremos un parentesis para explicar este concepto, ya que es muy importante.

Una textura (2D) es una imagen formada por un cuadrado de x pixels por y pixels. En el caso de OpenGL x e y se usan para colocar puntos en el espacio 3D junto con z, asi que para no provocar confusiones, en el caso de una textura, diremos que es un cuadrado de s por t pixels (en vez de x por y). Para complicarlo mas y como OpenGL hace continuamente uso masivo de datos float o double (coma flotante) tomaremos como alto y ancho de cualquier textura, sea del tamaño que sea, 1.0 y las coordenadas iran de 0.0 a 1.0 (pasando, por ejemplo, por 0.1, 0.2, 0.345, 0.592235, 0.92934405, ...).
Asi la coordenadas de las esquinas de cualquier textura seran en formato (s, t):

  • Superior derecha    = (0.0, 0.0)
  • Superior izquierda  = (0.0, 1.0)
  • Inferior derecha     = (1.0, 0.0)
  • Inferior izquierda   = (1.0, 1.0)

y el centro de la textura sera (0.5, 0.5).
Graficamente:


Todo esto ¿para que?. Pues para que podamos hacer coincidir nuestro vertice con la parte de la textura que queramos de forma que, jugando con las coordenadas de textura, usar para relleno de un poligono, solo una parte de la imagen de la textura o repetir la imagen n veces dentro del poligono. Mas tarde lo veremos.

Asi quedaria el codigo que envia las coordenadas de nuestro cubo a OpenGL:

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
// 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);
// Ahora la coordenada del vertice.
glVertex3f( 1.0f, 1.0f,-1.0f);
// Repetimos operacion. Para cada vertice una funcion
// glTexCoor y una glVertex ...
glTexCoord2d(0.0,0.0);
glVertex3f(-1.0f, 1.0f,-1.0f);
glTexCoord2d(0.0,1.0);
glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2d(1.0,1.0);
glVertex3f( 1.0f, 1.0f, 1.0f);
 
 
// Cara de abajo
//glColor3f(1,0,0); // rojo
glTexCoord2d(1.0,0.0);
glVertex3f( 1.0f,-1.0f, 1.0f);
glTexCoord2d(0.0,0.0);
glVertex3f(-1.0f,-1.0f, 1.0f);
glTexCoord2d(0.0,1.0);
glVertex3f(-1.0f,-1.0f,-1.0f);
glTexCoord2d(1.0,1.0);
glVertex3f( 1.0f,-1.0f,-1.0f);
// Cara frontal
//glColor3f(0,0,1); // azul
glTexCoord2d(1.0,0.0);
glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2d(0.0,0.0);
glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2d(0.0,1.0);
glVertex3f(-1.0f,-1.0f, 1.0f);
glTexCoord2d(1.0,1.0);
glVertex3f( 1.0f,-1.0f, 1.0f);
// Cara trasera
//glColor3f(0,0,1); // azul
glTexCoord2d(1.0,0.0);
glVertex3f( 1.0f,-1.0f,-1.0f);
glTexCoord2d(0.0,0.0);
glVertex3f(-1.0f,-1.0f,-1.0f);
glTexCoord2d(0.0,1.0);
glVertex3f(-1.0f, 1.0f,-1.0f);
glTexCoord2d(1.0,1.0);
glVertex3f( 1.0f, 1.0f,-1.0f);
// Cara izquierda
//glColor3f(0,1,0); // verde
glTexCoord2d(1.0,0.0);
glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2d(0.0,0.0);
glVertex3f(-1.0f, 1.0f,-1.0f);
glTexCoord2d(0.0,1.0);
glVertex3f(-1.0f,-1.0f,-1.0f);
glTexCoord2d(1.0,1.0);
glVertex3f(-1.0f,-1.0f, 1.0f);
// Cara derecha
//glColor3f(0,1,0); // verde
glTexCoord2d(1.0,0.0);
glVertex3f( 1.0f, 1.0f,-1.0f);
glTexCoord2d(0.0,0.0);
glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2d(0.0,1.0);
glVertex3f( 1.0f,-1.0f, 1.0f);
glTexCoord2d(1.0,1.0);
glVertex3f( 1.0f,-1.0f,-1.0f);
glEnd();

Con esto ya habremos puesto en pantalla un bonito cubo pintado con nuestra textura.

Ahora vamos a poner un cartel a modo de titulo en 2D, tal y como vimos en el capitulo 5, pero con textura. Pondremos el logo de UnSitioWeb.

Para ello, despues de pintar el cubo, cambiamos la perspectiva para pintar en ortogonal.
Cambiamos a la matriz de proyeccion:

1
glMatrixMode(GL_PROJECTION);

y para no tener que definir mas tarde la proyeccion en perspectiva otra vez, guardamos la matriz actual de proyeccion... si, si esto es nuevo tambien. Habra que explicarlo.

OpenGL permite guardar matrices en una pila. Si en una pila igual que la programacion en codigo maquina (ensamblador). Por culturilla explicare que es una pila para quien no lo sepa.

Una pila es una estructura de datos de tipo LIFO (Last In, First Out), que no es otra cosa que el ultimo dato guardado es el primero que podemos sacar. De forma figurada es como un tubo de patatas fritas (no voy a decir la marca que no me pagan). Lo vamos llenando de patatas, pero cuando nos las comemos, lo hacemos en orden inverso a como las metimos.

Bien; OpenGL tiene pila para las matrices y hay dos importantisimas funciones para gestionarla. glPushMatrix() que "empuja" la matriz que tenemos seleccionada (glMatrixMode) a la pila de matrices (en realidad la copia), y glPopMatrix() que recupera de la pila una matriz y la carga en la matriz que tenemos seleccionada para trabajar con ella.
Esto nos permite guardar temporalmente el contenido, por ejemplo, de la matriz de proyeccion, modificarla para pintar de otra forma, y cuando hemos terminado, recuperarla y seguir pintando como si no la hubieramos modificado. Esto es lo que vamos ha hacer en este capitulo del curso.

Lo que haremos sera:
  1. Cambiar a la matriz de proyeccion
  2. Guardar la actual matriz de proyeccion en la pila.
  3. Cargamos la matiz identidad (inicializamos) la matriz actual (la de proyeccion).
  4. Definimos la proyeccion ortogonal para pintar nuestro cartel.
  5. Cambiamos a la matriz de modelo.
  6. Cargamos la matiz identidad (inicializamos) la matriz actual (la de modelo).
Y este orden. En OpenGL el orden de hacer las cosas SI importa.
Este es el codigo correspondiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Le digo a OpenGL que voy a trabajar con la matriz
// de proyeccion.
glMatrixMode(GL_PROJECTION);
// Guardo la actual matriz de proyeccion en la pila de matrices
// para volver a la proyeccion actual cuando termine.
glPushMatrix();
// Cargo la matriz identidad (inicializo).
glLoadIdentity();
// Defino la proyeccion ortogonal, tal y como vimos en capitulos
// anteriores
glOrtho(0,rect.right,rect.bottom,0,-1,1);
// Una vez puesta la proyeccion regreso a la matriz de modelo,
// con la que pinto los objetos.
glMatrixMode(GL_MODELVIEW);
// Inicializo la matriz de modelo con la matriz identidad.
glLoadIdentity();

Seleccionamos la textura que vamos a usar ahora:

1
glBindTexture(GL_TEXTURE_2D, tex2);

y habilitamos el blending ... Si otra explicacion de algo nuevo.

El blending es una funcionalidad de OpenGL que permite una serie de operaciones usando el color que ya esta en el pixel de pantalla que se va a pintar (destino) y el color del pixel de nuestro objeto que estamos pintando. Lo mas interesante para nosotros es que permite usar el canal Alfa de nuestra textura. (recordad el formato de cada pixel - RGBA).

Si hemos cargado una textura con canal Alfa (no todos los formatos graficos lo permiten, nosotros usamos PNG que si lo usa), lo usaremos para hacer transparente el fondo de la imagen (el logo de UnSitioWeb). Asi no veremos todas las imagenes como rectangulos (no se ve igual USW que USW ).
Las combinaciones son muchas pero a nosotros solo nos interesa por ahora el tema de la transparencia.
En nuestro codigo, primero habilitamos el blending:

1
glEnable(GL_BLEND);

y luego le decimos a OpenGL como lo queremos hacer. Para las transparencias usaremos una opcion que usa el canal Alfa para indicar el grado de transparencia del pixel, de forma que podemos hacerlo totalmente transparente hasta totalmente opaco, pasando por 255 grados de transparencia. Esta opcion va bien con los PNGs de fondo transparente que crean los programas de graficos:

1
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

A partir de ahora todas las texturas que pintemos se veran afectadas por el canal Alfa, si lo tuvieran (una imagen sin canal Alfa de origen, un JPG por ejemplo, al cargarla con la opcion de R8G8B8A8 de Corona, le crea un canal Alfa sin ninguna transparencia).

Despues pintaremos un cuadrado con la textura que habiamos cargado con el logo (ya habiamos indicado a OpenGL que la textura tex2 pasaba a ser la activa antes de lo del blending)

Trasladamos 10 pixels abajo y 10 pixels a la derecha para que no este muy pegado al borde:

1
glTranslatef(10,10,0);

y pintamos el cuadrado con sus coordenadas de textura y de vertices:

1
2
3
4
5
6
7
8
9
10
11
glBegin(GL_QUADS);
glTexCoord2d(0.0,0.0);
glVertex3i( 0, 0,0);
glTexCoord2d(0.0,1.0);
glVertex3f( 0, 100,0);
glTexCoord2d(1.0,1.0);
glVertex3f( 400,100,0);
glTexCoord2d(1.0,0.0);
glVertex3f( 400,0,0);
glEnd();
 
Una vez pintado:
  1. Desabilito el blending,
  2. Selecciono la matriz de proyeccion
  3. Recupero de la pila la matriz con la proyeccion anterior (en perspectiva)
  4. Selecciono la matriz de modelo.
Y en este orden, claro.
En resumen, dejo todo como antes de pintar el cartel:

1
2
3
4
5
6
7
8
9
10
11
// Desabilito el blending para que lo que haga despues 
// no me haga raros y me vuelva loco para saber porque.
glDisable(GL_BLEND);
// Cambio a la matriz de proyeccion
glMatrixMode(GL_PROJECTION);
// Recupero de la pila, la matriz de proyeccion original
// asi no tengo que volver a indicar a OpenGL como quiero
// la proyeccion. Sencillamente la restablezco.
glPopMatrix();
// Cambio de nuevo a la matriz de modelo.
glMatrixMode(GL_MODELVIEW);

Termino la funcion Pinta() presentando lo pintado en pantalla como siempre.

Ya solo nos queda un pequeño detalle pero no por eso deja de ser importante.

Habiamos borrado ya de memoria las imagenes cargadas por Corona porque no hacian falta pero nos quedan por borrar el espacio de memoria que ocupan nuestras texturas OpenGL cuando salgamos del programa.
En la funcion ProcesaMensajes(...) dentro de la opcion que trata el mensaje WM_DESTROY (destruccion de la ventana) antes de terminar el programa con PostQuitMessage(0) incluyo el borrado de mis texturas:

1
2
3
// Borro las texturas de memoria. No hay que dejar basura.
glDeleteTextures( 1, &tex1 );
glDeleteTextures( 1, &tex2 );

Al final el trabajo se ve recompensado al ejecutar nuestro programa:



El codigo completo seria:  usw7.cpp


Aunque este capitulo este terminado, voy a sugerir modificaciones al programa para probar lo que sucede al cambiar cosas.

Lo primero sera eleminar el blending de el cartel de UnSitioWeb para ver que pasa.
Lo unico que habria que hacer es comentar estas lineas (en realidad bastaria con comentar la primera):

1
2
3
//glEnable(GL_BLEND);
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//glDisable(GL_BLEND);

Veremos como lo que no deberia aparecer nos tapa parte del cubo.

Lo segundo sera modificar las coordenadas de textura de dos caras del cubo.
En la cara frontal vamos a hacer un mosaico con la repeticion de la textura dentro de una cara y para ello vamos a incluir dos funciones en IniciaGL() que indican a OpenGL que si las coordenadas de textura son mayores de 1.0 repita la textura en ese eje (si fuera 2.0 la repetiria 2 veces, si fuera 8.0 la repetiria 8 veces, si fuera 1.5 la repetiria 1 vez y media, ...).
Creo que es la opcion por defecto pero yo prefiero no correr riesgos. Lo pondriamos en la parte del programa en que indicamos a la textura como se tiene que comportar:

1
2
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT);

Despues no tendriamos mas que cambiar las coordenadas de textura de una cara para ver el efecto:

1
2
3
4
5
6
7
8
9
10
// Cara frontal
//glColor3f(0,0,1); // azul
glTexCoord2d(3.0,0.0);
glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2d(0.0,0.0);
glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2d(0.0,3.0);
glVertex3f(-1.0f,-1.0f, 1.0f);
glTexCoord2d(3.0,3.0);
glVertex3f( 1.0f,-1.0f, 1.0f);

Observese que en la funcion glTexcoor hemos puesto un 3 donde antes habia un 1.
Tendremos ahora un mosaico de 9 cuadros iguales (3 x 3). Se puede jugar con los numeros para ver otros efectos. Veriamos esa cara asi:



En la cara izquierda vamos a usar solo el centro de la textura para recubrirla y para eso no necesitamos mas que modificar las coordenadas de textura de esta cara:

1
2
3
4
5
6
7
8
9
10
// Cara izquierda
//glColor3f(0,1,0); // verde
glTexCoord2d(0.6,0.4);
glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2d(0.4,0.4);
glVertex3f(-1.0f, 1.0f,-1.0f);
glTexCoord2d(0.4,0.6);
glVertex3f(-1.0f,-1.0f,-1.0f);
glTexCoord2d(0.6,0.6);
glVertex3f(-1.0f,-1.0f, 1.0f);

Como se ve en el codigo solo hemos cambiado el 1.0 por 0.6 y el 0.0 por 0.4; hemos seleccionado un cuadrado del centro de la textura y el resultado sera este:


Y con esto es bastante para este capitulo. El proximo sera de luces.
Por si se nos ha pasado el enlace al codigo ahi va otra vez: usw7.cpp


¡Sólo los usuarios registrados pueden escribir comentarios!
+/- Comentarios
Buscar
Pablo v   |181.28.215.xxx |26-06-2013 21:56:15
La verdad que tus tutoriales son exelentes!! Sigue subiendo :)
Joseba   |85.85.41.xxx |06-11-2011 17:58:39
hola!
me sale este error:1>corona.h(24): error RC2188:
C:\Users\joseba\Documents\Visual Studio
2010\Projects\joseba juego 2\joseba juego
2\Release\RCa04260(150) : fatal error RC1116: RC terminating after
preprocessor errors

salu2 y gracias por los tutos!!
Vicengetorix   |85.53.223.xxx |09-11-2011 14:02:30
Tiene pinta de ser un problema de las opciones del proyecto, ya que es un error
del preprocesador, antes de intentar compilar. ¿el proyecto es C++?.
Bajate el
proyecto de ejemplo de la zona de descargas y compara opciones.
Suerte.
Fernando   |187.139.169.xxx |21-05-2011 03:21:19
Hola tengo el problema de que quiere acceder a la locación de memoria 0x0000
estoy usando visual c++ y no se donde colocar las imagenes ya las e puesto
dentro de debug, afura del proyecto y nada.

Excelentes tutoriales saludos.
Vicengetorix   |85.53.221.xxx |28-05-2011 00:51:29
El error de acceso a la direccion 0 de memoria es tipico de punteros sin asignar
valor.
Creo entender que tu problema es la localizacion de las
imagenes.
Primero, yo no suelo usar la version degug, uso la release.
Al
ejecutar desde VC el directorio base es donde se encuentra el proyecto, el
superior al debug que dices.
En todo caso, si tienes problemas para encontrar
donde estas, prueba a crearte un ficherito y ver luego donde esta.
pescadilla2008  - ayuda   |89.141.40.xxx |27-09-2011 22:11:23
me da un error de no se que 0.00000 o algo asi y tambien me pasa lo mismo, no se
donde se colocan las imagenes si en la carpeta debuj no se, ayuda
Vicengetorix   |85.53.193.xxx |30-09-2011 23:46:24
Respecto a donde dejar la textura, a mi me busca desde el directorio del
proyecto, fuera de debug o release.
Respecto al error ese ... como no des mas
datos va a ser dificil...
Ricky658  - Error de compilación   |200.24.193.xxx |08-01-2011 15:50:25
Me sale este error: warning C4129: 'p' : secuencia de escape de carácter no
reconocida. Me podrías explicar por que sale
Ricky658   |200.24.193.xxx |08-01-2011 15:56:01
Por cierto estoy en VC++ 2008 con el SDK
Vicengetorix   |85.53.212.xxx |09-01-2011 23:37:34
Esto se produce cuando en una cadena de caracteres introduces una secuencia de
escape no válida.
Las secuencias de escape son una "\" seguida de
un carácter determinado.
Ejemplos: "\t" es un tabulador,
"\n" un retorno de carro (nueva línea) o "\0" fin de
cadena.
Lo más probable sea que al cargar una imagen hayas puesto
"\" como separador del directorio en vez de "/".
Ejemplo:
"directorio\fichero.ext" en vez de "directorio/fichero.ext"
o directorio\\fichero.ext" ("\\" es equivalente a
una sola barra).
cytral  - Problemas con la Profundidad   |87.222.110.xxx |21-03-2010 05:37:09
Buenas! ante todo felicitarte por los tutoriales :)

Mi problema es que lo que
esta delante no siempre se pinta encima... tengo que decir que el
"viewport" lo inicio con funciones de GLUT..


"glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GL UT_DEPTH);"


cuando meto
eso mas las funciones que pusiste:
glClearDepth(1.0f);

glDepthFunc(GL_LEQ
UAL);
glEnable(GL_DEPTH_TEST);


Pues el cubo se me dibuja mal... aveces sale
pintada un cacho de la cara.. luego si lo roto no se pinta nada... a eces solo
se ven las texturas en las aristas.... y esas putadillas :P..

Tonces querria
saber como debo decirle a openGL que quiero profundidad si uso GLUT para iniciar
el viewport...


Gracias!
Vicengetorix   |194.179.126.xxx |22-03-2010 23:00:00
Lo primero, que yo no uso GLUT por lo que no se lo que hace o deja de hacer.
En
todo caso debes definir la perspectiva, supongo que lo haces.
El error que
tienes, asi sin mas datos, parece que puede ser por el orden en que pintas los
vertices de las caras. OpenGL usa el contrario a las agujas del relog por
defecto (si ves el poligono de frente). Puedes intentar cambiarlo con
"glFrontFace(GL_CW)" o hacer que se pinten las caras vistas desde el
frente y desde atras, normalmente las vistas desde atras no las pinta (de hay
viene tu problema, o eso creo) con "glDisable(GL_CULL_FACE)", pero eso
hace que tu programa trabaje un poco mas de lo que debiera.

Prueba el foro para
estas cosas que me resulta mas comodo.
Arzheus  - Principiante   |81.33.184.xxx |27-12-2009 03:10:46
Hola! es un curso estupendo!, pero me surgen varios problemas, yo lo hago
con
Visual Studio 2008, pero mi problema es mas bien de principiante, mas o
menos se pintar primitivas en un solo .cpp pero al llegar al tema de texturas
picho a la hora de cargarlas, entiendo todo el código al respecto, pero no se
donde implementarlo, es decir... las tex1 y 2 se que van fuera, pero el resto
donde va? en main? en otra funcion? he probado estas dos y me da un
error:
error LNK2019: símbolo externo _CorConvertImage@8 sin resolver al
que se hace referencia en la función "class corona::Image * __cdecl
corona::OpenImage(char const *,enum corona::PixelFormat,enum
corona::FileFormat)" (?OpenImage@corona@@YAPAVImage@1&#
64;PBDW4PixelFormat@1@W4FileFormat@1&# 64;@Z)

Gracias de
antemano
Vicengetorix   |85.53.212.xxx |30-12-2009 12:50:30
El error que te da es porque no has incluido en el proyecto (o no encuentra) la
librería corona, así, cuando va a enlazar las funciones que llamas desde el
código, no las encuentra.
Respecto a tex1 y tex2, no se a cual más te
refieres.

Para más aclaraciones es mejor usar el foro, que es más ágil y la
información le sirve a más personas.
Arzheus   |87.218.103.xxx |06-01-2010 13:40:41
Muchas gracias!!
Himura  - Texturas y Colores   |200.13.124.xxx |06-11-2009 21:05:13
Hola,

He estado intentando acceder a los foros para plantear mi duda pero no
puedo, me logeo y no pasa nada.

Estoy desarrollando un sistema de explosiones
para mis juegos con OpenGL y SDL.

Cargo una textura como imagen de background y
al presionar la barra espaciadora la explosion se genera bien pero
inmediatamente despues toda la pantalla se queda en negro supongo porque
selecciona el color para actualizar la particula de la explosion. Para el color
utilizo glColor4f.

Para usar la textura uso GL_REPLACE con el glTextureEnvf
para deshabilitar el color y pinte solo la textura.

Que puede estar pasando
porque la textura ya no se pinta despues de generar la
explosion??

Gracias
Saludos
Vicengetorix   |85.53.194.xxx |06-11-2009 23:37:13
Tu problema de acceso al foro es porque no has confirmado el alta con el mensaje
enviado a tu correo. El mensaje lleva un link de confirmacion de la cuenta. Si
tienes mas problemas de acceso hazmelo saber con el formulario de contacto de a
web.

Respecto al tema de la explosion.
Si he entendido bien, el problema es que
despues de pintar la explosion con puntos de color, ya no se ve la textura de
fondo.
Habria que ver el tema con detalle pero a bote pronto comprobaria si
habilito pintar con texturas "glEnable(GL_TEXTURE_2D)" despues de pintar
la explosion y siempre antes de pintar el fondo.
Comprobaria tambien que la
variable que contiene el identificador de la textura no haya cambiado de valor
al pintar la explosion.
Otra comprobacion seria si la matriz de modelo esta con
su valor o se le han añadido modificaciones al pintar la explosion.

En todo
caso podrian ser mil cosas.
Armando  - Error Runtime   |201.137.198.xxx |23-07-2009 05:59:16
Hola,

Gracias por la respuesta ese error ya lo solucione pero ahora me sale
este en tiempo ejecucion:

First-chance exception at 0x00412598 in
Lesson07_TexOGL.exe: 0xC0000005: Access violation reading location
0x00000000.
Unhandled exception at 0x00412598 in Lesson07_TexOGL.exe:
0xC0000005: Access violation reading location 0x00000000.
The program '[3260]
Lesson07_TexOGL.exe: Native' has exited with code 0 (0x0).

gracias de antemano.
Vicengetorix   |85.53.216.xxx |23-07-2009 12:28:26
Este error se produce al acceder a memoria que no es tuya, que no has reservado.
Si te fijas intenta acceder a la direccion 0x00000000 que es la primera celda de
memoria del PC y jamas podrias acceder a ella. Tu problema es que la carga de
textura no encuentra el fichero y retorna un puntero NULL (0). Al intentar
aceder a la imagen con ese puntero da este error.
Asegurate que pones bien la
ruta de los ficheros de imagen.
enanitos   |83.36.82.xxx |02-10-2009 19:03:42
Hola me parece estupendo el curso, pero tengo un problema, lo estoy haciendo con
dev c++ y ahora me pone esto como error

[Linker error] undefined reference to
`CorOpenImage@8'
[Linker error] undefined reference to
`CorConvertImage@8'
ld returned 1 exit status

A que se puede deber el
error?
Vicengetorix   |194.179.126.xxx |02-10-2009 20:47:58
Corona. Los errores son de la libreria corona. Por desgracia no se puede bajar
compilada para dev-c, solo para VC++.
Tienes 3 opciones:
- Bajar el codigo
fuente y compilarla tu en dev-c.
- Pasarte a VC++.
- Usar otra.

La primera
opcion no te la recomiendo por trabajoso y complicado (si lo haces, mandame la
libreria y la incluyo en las descargas del sitio a tu nombre).
Si optas por la
tercera puedo sugerir SOIL, la que he usado yo para la libreria de UnSitioWeb.
Lo unico es que tendras que acomodar el codigo.
Cuentanos como lo haces.
Armando  - Problemas con Corona   |201.137.127.xxx |18-07-2009 08:37:42
Yo tengo el siguiente problema:

lesson07_texogl.cpp(26) : fatal error C1083:
Cannot open include file: 'corona/include/corona.h': No such file or
directory

He intentado todo y nada hace que funcione, como lo
soluciono??

Gracias de antemano
Un saludo
Vicengetorix   |85.53.212.xxx |18-07-2009 17:11:18
Tu problema es simplemente que no encuentra en fichero "corona.h".

¿Te bajaste la libreria? Deberias bajartela http://corona.sourceforge.net/.
Luego tienes que poner el fichero de cabecera de la libreria,
"corona.h", donde tu programa pueda encontrarlo (por ejemplo en el
directorio "include" de tu instalacion de VC++.
Calantra  - Filecidades!   |80.58.213.xxx |18-05-2009 14:04:05
Hola, me parecen estupendos los tutoriales, muy faciles de entender y bien
explicados. Espero ansioso los proximos capitulos.

Saludos.
Vicengetorix  - Gracias   |85.53.201.xxx |23-05-2009 01:02:49
Gracias, es la filosofia del sitio la facilidad, y la diversion.
Ya esta
publicado el siguiente, iluminacion.
Saludos.

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