Mapeo de Texturas Mapeo de texturas Texturas 1D • Para definir la textura: void glTexImage1D (GLenum objetivo, GLint nivel, GLint componentes, GLsizei ancho, GLint borde, GLenum formato, GLenum tipo, const GLvoid *pixels) donde: – objetivo vale siempre GL_TEXTURE_1D – nivel indica el nivel de detalle (0 para texturas individuales) – componentes vale 1 (modo índice), 3 (RGB) ó 4 (RGBA) – ancho indica el ancho en pixel del mapa de textura (debe ser potencia de 2) – borde indica el número de pixels que forman el borde de la textura (0, 1 ó 2) – formato indica el formato de los pixels: GL_RED, GL_RGB, GL_LUMINANCE – tipo indica el tipo de dato de los pixels: GL_UNSIGNED_INT, GL_FLOAT – pixels es un puntero a los pixels de la textura Ejemplo • Para activar el mapeo de texturas 1D: void glEnable (GL_TEXTURE_1D) unsigned char ArcoIris[8][3] = { { 0x3f, 0x00, 0x3f }, // Violeta oscuro { 0x7f, 0x00, 0x7f }, // Violeta { 0xbf, 0x00, 0xbf }, // Malva { 0x00, 0x00, 0xff }, // Azul { 0x00, 0xff, 0x00 }, // Verde { 0xff, 0xff, 0x00 }, // Amarillo { 0xff, 0x7f, 0x00 }, // Naranja { 0xff, 0x00, 0x00 } // Rojo }; glTexImage1D (GL_TEXTURE_1D, 0, 3, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, ArcoIris); Coordenadas de la textura • Para hacer corresponder las coordenadas de la textura con las de la superficie: void glTexCoord1f (GLfloat s) S=0.0 S=1.0 glBegin(GL_QUADS); glTexCoord1f (0.0); glVertex3f (0, 0, 0); glTexCoord1f (1.0); glVertex3f (8, 0, 0); (0,8) s=0.0 (8,8) s=1.0 (0,0) s=0.0 (8,0) s=1.0 // glTexCoord1f (1.0); glVertex3f (8, 8, 0); glTexCoord1f (0.0); glVertex3f (0, 8, 0); glEnd(); Variando las coordenadas • Virtualmente la textura se extiende para cualquier valor de s S=-1.0 • S=0.0 S=1.0 S=2.0 S=3.0 Podemos asignar a un vértice cualquier valor de s s=1.0 s=1.0 s=0.0 s=2.0 s=-1.0 s=2.0 s=0.0 s=1.0 s=0.0 s=2.0 s=0.0 s=1.0 Filtrado • Al mapear la imagen de textura sobre una superficie, los texels no se van a corresponder exactamente con los pixels – Si la superficie es mayor que la textura, cada pixel se corresponderá con un trozo pequeño de texel ---> Magnificación – Si la superficie es menor que la textura, cada pixel se corresponderá con una conjunto de texels contiguos ---> Minificación Texels Pixels Pixels Tipos de filtrado void glTexParameteri (GL_TEXTURE_1D, GLenum filtro, GLint valor) GL_NEAREST GL_TEXTURE_MAG_FILTER GL_TEXTURE_MIN_FILTER GL_NEAREST Textura GL_LINEAR GL_LINEAR Ejemplo final con texturas 1D unsigned char Arco[8][3] = {...} // Habilitamos el mapeo de texturas glEnable(GL_TEXTURE_1D); // Indicamos el tipo de filtrado glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Creamos la textura glTexImage1D(GL_TEXTURE_1D,0,3,8,0,GL_RGB,GL_UNSIGNED_BYTE,Arco); // Indicamos el modo de mapeo //(volcar el valor de los texels directamente sobre los pixels) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); // dibujamos el objeto glBegin(...); glTexCoord1f (..); glVertex3f (...); ... glEnd(); Modos de mapeo • Para establecer el modo de mapeo: glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GLint valor) donde valor puede tomar 3 valores: – GL_DECAL: el valor del texel se copia directamente al pixel – GL_MODULATE: el valor del texel se escala por el color del objeto – GL_BLEND: el valor del texel se usa para interpolar entre el color del objeto y un color constante definido para la textura, mediante la función glTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_COLOR,GLfloat color[4]) ENV_COLOR Texturas 2D • Para definir la textura: void glTexImage2D (GLenum objetivo, GLint nivel, GLint componentes, GLsizei ancho, GLsizei alto, GLint borde, GLenum formato, GLenum tipo, const GLvoid *pixels) donde: – objetivo vale siempre GL_TEXTURE_2D – nivel indica el nivel de detalle (0 para texturas individuales) – componentes vale 1 (modo índice o luminancia), 3 (RGB) ó 4 (RGBA) – ancho indica el ancho en pixels del mapa de textura (debe ser potencia de 2) – alto indica el alto en pixels del mapa de textura (debe ser potencia de 2) – borde indica el número de pixels que forman el borde de la textura (0, 1 ó 2) – formato indica el formato de los pixels: GL_RED, GL_RGB, GL_LUMINANCE – tipo indica el tipo de dato de los pixels: GL_UNSIGNED_INT, GL_FLOAT – pixels es un puntero a los pixels de la textura Ejemplo • Para activar el mapeo de texturas 2D: void glEnable (GL_TEXTURE_2D) unsigned char Colores[4][4][3] = { {{64,0,0}, {128,0,0}, {192,0,0}, {{0,64,0}, {0,128,0}, {0,192,0}, {{0,0,64}, {0,0,128}, {0,0,192}, {{64,64,0}, {128,128,0}, {192,192,0}, }; {255,0,0}}, {0,255,0}}, {0,0,255}}, {255,255,0}} glTexImage2D (GL_TEXTURE_2D, 0, 3, 4, 4, 0, GL_RGB, GL_UNSIGNED_BYTE, Colores); // // // // Rojos Verdes Azules Amarillos Coordenadas de la textura • (s,t)=(0,0) (s,t)=(1,0) (s,t)=(0,1) (s,t)=(1,1) Para hacer corresponder las coordenadas de la textura con las de la superficie: void glTexCoord2f (GLfloat s, GLfloat t) glBegin(GL_QUADS); glTexCoord2f (0.0, 0.0); glVertex3f (0, 0, 0); (0,4) (s,t)=(0,0) (4,4) (s,t)=(1,0) (0,0) (s,t)=(0,1) (4,0) (s,t)=(1,1) glTexCoord2f (1.0, 1.0); glVertex3f (4, 0, 0); glTexCoord2f (1.0, 0.0); glVertex3f (4, 4, 0); glTexCoord2f (0.0, 0.0); glVertex3f (0, 4, 0); glEnd(); Variando las coordenadas • Virtualmente la textura se extiende para cualquier valor de s y de t (s,t)=(-1,-1) (s,t)=(1,-1) (s,t)=(0,0) (s,t)=(1,0) (s,t)=(0,1) (s,t)=(1,1) (s,t)=(0.5,2) • Podemos asignar a un vértice cualquier valor de s y de t Leyendo la textura de un fichero (C++ Builder) Graphics::Tbitmap *bitmap; // objeto donde leeremos la imagen unsigned char *textura; // vector donde se leerá la textura TColor tcolor; // variable donde se lee cada pixel unsigned char *color = (unsigned char *) &tcolor; int dimx, dimy, n=0; bitmap = new Graphics::TBitmap; // creamos el objeto bitmap bitmap->LoadFromFile(”textura.bmp"); // volcamos la imagen en él dimx = bitmap->Width; dimy = bitmap->Height; // potencias de 2 textura = (unsigned char *) malloc (dimx*dimy*3); for (int j=0; j<dimy; j++) for (int i=0; i<dimx; i++) { // leemos el color pixel tcolor = bitmap->Canvas->Pixels[i][j]; textura[n++] = color[0]; // leemos la componente roja textura[n++] = color[1]; // leemos la componente verde textura[n++] = color[2]; // leemos la componente azul } delete bitmap; // borramos el objeto bitmap glTexImage2D (GL_TEXTURE_2D, 0, 3, dimx, dimy, 0, GL_RGB, GL_UNSIGNED_BYTE, textura); Texturas sobre una malla de vértices • Al texturar un objeto hay que especificar la coordenada de textura para cada vértice glTexCoord2f (.., ..); glVertex3f (.., .., ..); glTexCoord2f (.., ..); glVertex3f (.., .., ..); glTexCoord2f (.., ..); glVertex3f (.., .., ..); glTexCoord2f (.., ..); glVertex3f (.., .., ..); Generación automática de coordenadas • Podemos decirle a OpenGL que genere automáticamente las coordenadas de textura para cada vértice del objeto void glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GLint param) GL_OBJECT_LINEAR GL_EYE_LINEAR GL_SPHERE_MAP • Para cada vértice, la coordenada de textura vendrá dada por: s = x*plano_s[0] + y*plano_s[1] + z*plano_s[2] + w*plano_s[3] – donde (x,y,z,w) son las coordenadas homogéneas del vértice, – y plano_s viene definido por la llamada a la función: void glTexGenfv (GL_S, GL_OBJECT_PLANE, GLfloat plano_s[4]) Ejemplo con texturas 1D GLfloat plano_s[4] = {1, 0, 0, 0}; // s=x glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGenfv (GL_S, GL_OBJECT_PLANE, plano_s); glEnable (GL_TEXTURE_GEN_S); GL_DECAL y GL_BLEND x z Ejemplo con texturas 2D GLfloat plano_s[4] = {1, 0, 0, 0}; // s=x GLfloat plano_t[4] = {0, 1, 0, 0}; // t=y glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGenfv (GL_S, GL_OBJECT_PLANE, plano_s); glEnable (GL_TEXTURE_GEN_S); glTexGeni (GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGenfv (GL_T, GL_OBJECT_PLANE, plano_t); glEnable (GL_TEXTURE_GEN_T); y textura x z GL_BLEND GL_DECAL Matrices de textura • Las coordenadas de textura también se pueden transformar a través de la matriz de textura. glMatrixMode (GL_TEXTURE) • Las coordenadas de textura se pueden trasladar, escalar y rotar. • Ejemplo: para simular la ondulación del agua podemos trasladar la textura con un timer Problemas con las texturas individuales • Cuando la proyección del objeto con textura ocupa pocos pixels en la pantalla, no tiene sentido trabajar con un mapa de textura grande 8 256 256 64 y 256 z x Texturas multimapa (Mipmaps) • Se generan varias imágenes de la textura con distinta resolución – las resoluciones son siempre potencias de dos – hay que acabar en las imágenes 1x1 glTexImage2D (GL_TEXTURE_2D,0,3,2n,2n,0,GL_RGB,..,imagen_0); glTexImage2D (GL_TEXTURE_2D,1,3,2n-1,2n-1,0,GL_RGB,..,imagen_1); .... glTexImage2D (GL_TEXTURE_2D,n,3,1,1,0,GL_RGB,..,imagen_n); 2 1 • 2n-3 2n 2n-2 2n-1 OpenGL decide qué imagen usar automáticamente, en función del tamaño de la proyección del objeto Filtrado con mipmaps • Para decidir qué texels deben usarse para calcular el color de cada pixel: glTexParameteri(GL_TEXTURE_1D,GL_TEXTURE_MIN_FILTER, GLint valor) GL_NEAREST_MIPMAP_NEAREST GL_NEAREST_MIPMAP_LINEAR GL_LINEAR_MIPMAP_NEAREST GL_LINEAR_MIPMAP_LINEAR Texels de imagen i+1 Filtrado Texels de imagen i Pixels Generación automática de mipmaps • Si queremos que OpenGL calcule automáticamente las imágenes de textura de menor resolución, a partir de la imagen original: void gluBuild2DMipmaps(GL_TEXTURE_2D, GLint componentes, GLsizei ancho, GLsizei alto, GLenum formato, GLenum tipo, const GLvoid *pixels) • La anterior llamada es equivalente a unsigned char imagen_0 [256][256][3] = {....} unsigned char imagen_1 [128][128][3] = {....} .... unsigned char imagen_8 [1][1][3] = {....} glTexImage2D (GL_TEXTURE_2D, 0, 3, 256, 256, GL_RGB, GL_UNSIGNED_BYTE, imagen_0) glTexImage2D (GL_TEXTURE_2D, 1, 3, 128, 128, GL_RGB, GL_UNSIGNED_BYTE, imagen_1) .... glTexImage2D (GL_TEXTURE_2D, 8, 3, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, imagen_8) Objetos de textura • Se usan para acelerar la carga de texturas en memoria. • Para reservar un número de objetos de textura: void glGenTextures (GLsizei num, Gluint *nombres) • Para asociar una textura a cada índice reservado: void glBindTexture (GLenum num, Gluint nombre) – La primera vez que se llama a esta función, se carga la textura en memoria. – Las demás veces, sólo selecciona la textura, por lo que no hace falta cargarla de nuevo • Para liberar memoria, en caso de que dejemos de usar la textura: void glDeleteTextures (GLsizei num, const Gluint *nombres) Ejemplo GLuint texturas[3]; void Init() { glGenTextures (3, texturas); // textura del suelo glBindTexture (GL_TEXTURE_2D, textura[0]); glTexParameteri (…); glTexImage2D (GL_TEXTURE_2D, …); // textura de la pared glBindTexture (GL_TEXTURE_2D, textura[1]); glTexParameteri (…); glTexImage2D (GL_TEXTURE_2D, …); … } void Paint() { // pinto el suelo glBindTexture (GL_TEXTURE_2D, textura[0]); glBegin (…); … glEnd(); // pinto la pared glBindTexture (GL_TEXTURE_2D, textura[1]); glBegin (…); … glEnd(); }