Monografias.com > Arquitectura y Diseño
Descargar Imprimir Comentar Ver trabajos relacionados

Texture shading. Texturización



    1. Resumen
    2. Introducción
    3. Cargando texturas en
      memoria
    4. Pasando las texturas a
      opengl
    5. Parámetros de las
      texturas
    6. Renderizando con
      texturas
    7. Colores, luces y
      texturas
    8. Algoritmos
    9. Conclusiones
    10. Bibliografía

    RESUMEN

    En este trabajo
    veremos un aspecto básico si queremos que una escena
    contenga un mínimo de realismo: La
    texturización. Por texturización entendemos en el
    proceso de
    asignar una imagen (bitmap) a
    un polígono, de manera que en lugar de ver este de un
    color plano, o un
    gradiente de colores, veremos
    la imagen proyectada en él.

    INTRODUCCION

    Hasta ahora las primitivas se han dibujado en OpenGL con un
    solo color o

    interpolando varios colores entre los vértices de
    una primitiva. OpenGL dispone de funciones
    específicas para el mapeado de texturas (pegar imágenes
    en la superficie de las primitivas dibujadas), añadiendo
    realismo a la escena. En este trabajo se explica el proceso de
    mapeado de texturas a través de un sencillo ejemplo, para
    posteriormente emplear las texturas en la
    aplicación.

    Las texturas en OpenGL pueden ser 1D, 2D o 3D. Las 1D
    tienen anchura pero no altura; las 2D son imágenes que
    tienen una anchura y una altura de más de 1 píxel,
    y son generalmente cargadas a partir de un archivo .bmp
    (aunque puede ser en principio cualquier formato). En este
    trabajo no se hablará de las texturas 3D (volumen). Un
    aspecto muy importante a tener en cuenta es que en OpenGL las
    dimensiones de las imágenes deben ser potencia de
    2.

    Este trabajo se limitara a estudiar la
    texturización 2D, y proponer implementaciones para un
    mejor cargado y rendereado de texturas.

    DESARROLLO

    1.1. Cargando
    texturas en memoria

    El proceso de cargar la textura en memoria, no es
    propio de OpenGL, lo tendremos que hacer nosotros mismos. No
    obstante, hay que tener en cuenta unas ciertas limitaciones que
    la librería nos impone. Primeramente, las dimensiones de
    todas las texturas que carguemos tienen que ser potencias de 2,
    como por ejemplo 64×64, 128×64, etc.

    También hemos de tener en cuenta que si estamos
    dibujando en RGB, sin color indexado, o bien cargamos texturas en
    formato RGB o las convertimos a RGB. Es decir, si cargamos una
    imagen GIF, que tiene color indexado, correrá de nuestra
    cuenta pasarla a RGB. Sea cuál sea el método que
    escojamos, al final tendremos un puntero a un segmento de memoria
    que contiene la imagen:

    unsigned char *textura;

    Es importante también guardar las propiedades de
    la textura, en concreto sus
    dimensiones de ancho y alto, así como su profundidad en
    bits. Si estamos trabajando en RGB, la profundidad será
    24bits.

    1.2. Pasando las
    texturas a OpenGL

    Ahora ya tenemos la textura en la memoria RAM. No
    obstante, OpenGL no puede trabajar directamente con esta memoria,
    ha de usar su propia memoria para guardar las texturas. El se
    encargará de guardarlas en su espacio de memoria RAM o,
    directamente, pasarlas a la tarjeta aceleradora. Una vez le
    pasemos la textura a OpenGL, éste nos devolverá un
    identificador que tendremos de guardar. Cada textura
    tendrá un identificador propio, que tendremos que usar
    después cuando dibujemos. Veamos el proceso de
    obtención de este identificador. Creemos una variable para
    almacenarlo:

    GLuint idTextura;

    A continuación llamaremos a la función
    glGenTextures(…), a la cual le pasamos el numero de texturas
    que queremos generar, y un array de identificadores donde los
    queremos almacenar. En este caso, solo queremos una textura, y
    por lo tanto no hace falta pasarle un array, sino un puntero a
    una variable de tipo GLuint.

    glGenTextures(1, &idTextura);

    Con esto OpenGL mirará cuantas texturas tiene ya
    almacenadas, y en función de esto pondrá en
    idTextura el valor del
    identificador. Seguidamente, usaremos la función
    glBindTexture(…) para asignar el valor de idTextura, a una
    textura de destino. Es como si activáramos la textura
    asignada a idTextura, y todas las propiedades que modifiquemos a
    partir de entonces, serán modificaciones de esa textura
    solamente, y no de las demás, del mismo modo que activamos
    una luz y definimos
    sus propiedades.

    glBindTexture(GL_TEXTURE_2D,
    idTextura);

    Ahora falta el paso más importante, que es
    pasarle la textura a OpenGL. Para ello haremos uso de la
    función glTexImage2D(…)

    GlTexImage2D(GL_TEXTURE_2D, 0, 3, anchoTextura,
    altoTextura, 0,

    GL_RGB, GL_UNSIGNED_BYTE, textura);

    Pero veamos todos los parámetros, viendo los
    parámetros de esta función uno

    por uno:

    void glTexImage2D(

    GLenum tipoTextura,

    GLint nivelMipMap,

    GLint formatoInterno,

    GLsizei ancho,

    GLsizei alto,

    GLint borde,

    GLenum formato,

    GLenum tipo,

    const GLvoid *pixels

    );

    · tipoTextura: El tipo de textura que
    estamos tratando. Tiene que ser

    GL_TEXTURE_2D.

    · NivelMipMap: El nivel de MipMapping que
    deseemos. De momento

    pondremos ‘0’, más adelante veremos
    que significa.

    · FormatoInterno: El numero de componentes
    en la textura. Es decir, si

    estamos trabajando en formato RGB, el numero de
    componentes será 3.

    · Ancho, alto: El ancho y alto de la
    textura. Han de ser potencias de 2.

    · Borde: La anchura del borde. Puede ser
    0.

    · Formato: El formato en que esta
    almacenada la textura en memoria. Nosotros

    usaremos GL_RGB.

    · Tipo: El tipo de variables en
    los que tenemos almacenada la textura. Si la

    hemos almacenado en un unsigned char, usaremos
    GL_UNSIGNED_BYTE.

    · Pixels: El puntero a la región de
    memoria donde esté almacenada la imagen.

    Una observación. Teníamos en memoria RAM
    una textura cargada desde un archivo. Esta textura, se la hemos
    pasado a OpenGL, que se la ha guardado en su propia memoria. Por
    tanto, ahora tenemos dos copias en memoria de la misma textura,
    solo que una ya no es necesaria, la nuestra. Por tanto, es
    recomendable eliminar nuestras texturas de memoria una vez se las
    hemos pasado a OpenGL.

    free(textura);

    1.3.
    Parámetros de las texturas

    A cada textura le podemos asignar unas ciertas
    características. El primero de ellos es el filtro de
    visualización. Una textura es un bitmap, formado por un
    conjunto de píxels, dispuestos de manera regular. Si la
    textura es de 64 x 64 píxel, i la mostramos completa en
    una ventana de resolución 1024×768, OpenGL escalará
    estos pixels, de manera que cada píxel de la textura (de
    ahora en adelante téxel) ocupará 16×12
    píxeles en la pantalla.

    1024 pixels ancho / 64 texels ancho = 16;

    768 pixels alto / 64 texels alto = 12;

    Eso quiere decir que lo que veremos serán
    "cuadrados" de 16×12, representando cada uno un texel de la
    textura. Visualmente queda muy poco realista ver una textura
    ‘pixelizada’, de manera que le aplicamos filtros para
    evitarlo. El más común es el ‘filtro
    lineal’, que se basa en hacer una interpolación en
    cada píxel en pantalla que dibuja. A pesar de que pueda
    parecer costoso a nivel computacional, esto se hace por hardware y no afecta en
    absoluto al rendimiento.

    Veamos como lo podemos implementar:

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,
    GL_LINEAR);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
    GL_LINEAR);

    Con esto estamos parametrizando dos filtros. Uno para
    cuando la textura se representa más grande de lo que es en
    realidad (el ejemplo que hemos comentado) y otro para cuando la
    textura es mas pequeña: GL_TEXTURE_MAG_FILTER y
    GL_TEXTURE_MIN_FILTER, respectivamente. En los dos le decimos que
    haga un filtro lineal. Tambien podriamos decirle que no aplicara
    ningún filtro (GL_NEAREST).

    Generalmente al texturizar una escena, el modelador
    aplica una textura pequeña que se repite a lo largo de una
    superficie, de manera que, sacrificando realismo, usamos
    menos

    memoria. Podemos indicar a OpenGL que prepare la textura
    para ser dibujada a manera

    de ‘tile’ o para ser dibujada solo una vez.
    Por ejemplo, un cartel en una pared. En la pared habría
    una textura pequeña de ladrillo, que se repetiría n
    veces a lo largo de toda la superficie de la pared. En cambio, el
    cartel solo se dibuja una sola vez. La textura de ladrillo
    tendríamos que preparar para que se repitiese, y la del
    cartel no. Realmente lo que hace OpenGL realmente es, al dibujar
    la textura y aplicar el filtro lineal, es, en los bordes,
    interpolar con los texels del borde opuesto, para dar un aspecto
    mas realista.

    Si queremos activar esta opción,
    haríamos:

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
    GL_REPEAT);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
    GL_REPEAT);

    Si no nos interesa este efecto:

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
    GL_CLAMP);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
    GL_CLAMP);

    Por GL_TEXTURE_WRAP_S y GL_TEXTURE_WRAP_T nos referimos
    al

    filtro para las filas y las columnas,
    respectivamente.

    1.4. Renderizando
    con texturas

    Ahora que ya tenemos las texturas cargadas y ajustadas a
    nuestro gusto, veamos ahora cómo podemos dibujar polígonos con texturas aplicadas.
    Supongamos que queremos dibujar un simple cuadrado, con la
    textura que hemos cargado anteriormente.

    Si lo dibujamos sin textura seria:

    glBegin (GL_QUADS);

    glVertex3i (-100, -100, 5);

    glVertex3i (-100, 100, 5);

    glVertex3i (100, 100, 5);

    glVertex3i (100, -100, 5);

    glEnd ();

    Veamos ahora como lo hariamos aplicando una
    textura:

    glEnable(GL_TEXTURE_2D);

    glBindTexture(GL_TEXTURE_2D,
    idTextura);

    glBegin (GL_QUADS);

    glTexCoord2f(0.0f, 0.0f);

    glVertex3i (-100, -100, 5);

    glTexCoord2f(1.0f, 0.0f);

    glVertex3i (-100, 100, 5);

    glTexCoord2f(1.0f, 1.0f);

    glVertex3i (100, 100, 5);

    glTexCoord2f(0.0f, 1.0f);

    glVertex3i (100, -100, 5);

    glEnd ();

    glDisable(GL_TEXTURE_2D);

    Analicemos el código
    paso por paso:

    glEnable(GL_TEXTURE_2D);

    La función glEnable de OpenGL nos permite activar
    y desactivar propiedades que se aplican a la hora de renderizar.
    En este caso, le estamos diciendo que active la
    texturización

    glBindTexture(GL_TEXTURE_2D,
    idTextura);

    Como ya habiamos visto antes, la función
    glBindTexture se encarga de activar la textura que deseemos,
    referenciada por el identificador que habiamos guardado
    previamente en idTextura.

    glBegin (GL_QUADS);

    glTexCoord2f(0.0f, 0.0f);

    glVertex3i (-100, -100, 5);

    Aquí vemos algo que no estaba antes, nos
    referimos a glTexCoord2f(). Esta funcion nos introduce un
    concepto
    nuevo: las coordenadas de textura, y nos referiremos a ellas
    generalmente como ‘s’ y ‘t’, siendo
    ‘s’ el eje horizontal y ‘t’ el vertical.
    Se usan para referirnos a una posición de la textura.
    Generalmente se mueven en el intervalo [0,1].

    La coordenada (0, 0) se refiere a la esquina inferior
    izquierda, y la (1, 1) a la superior derecha. Por lo tanto, si
    nos fijamos en el código, a cada vértice le
    asignamos una coordenada de textura, siempre en orden
    contrario a las agujas del reloj
    , sino la textura se
    vería al revés.

    Hemos comentado que las coordenadas de textura se mueven
    en el intérvalo [0,1], pero OpenGL permite otros valores.
    Podríamos considerar que la textura se repite
    infinitamente en todas las direcciones, de manera que la
    coordenada (1, 0) seria el mismo texel que (2, 0), (3, 0), etc.
    No obstante, si dibujamos un cuadrado y le asignamos a un extremo
    (2, 2) en lugar de (1, 1), dibujara la textura repetida 2 veces
    en cada dirección, en total, 4 veces. Podemos jugar
    y asignar valores de (-1, -1) a (1, 1),etc.

    Una vez hayamos dibujado la geometría que queramos, es importante
    desactivar la texturización, si no lo hacemos, si mas
    adelante queremos dibujar algún objeto sin texturizar,
    OpenGL intentará hacerlo, aunque no le pasemos coordenadas
    de textura, produciendo efectos extraños. Así
    pues:

    glDisable(GL_TEXTURE_2D);

    1.5. Colores,
    luces y texturas

    Hemos estado
    hablando de texturizar una superficie, pero, que pasa con el
    color? Realmente podemos seguir usándolos, es mas, OpenGL
    texturizará y coloreará a la vez. Podemos activar
    el color rojo, y todas las texturas que se dibujen a partir de
    entonces, saldrán tintadas de ese mismo color.

    Del mismo modo con las luces. No hay ningún
    problema en combinar colores, luces y texturas a la vez. Si no
    queremos iluminación alguna, basta con no activar
    las iluminación, y si no queremos que las texturas salgan
    tintadas de algún color, basta con definir el color activo
    como el blanco.

    Algoritmo:

    #include <GL/glut.h>

    #include "bitmap.h"

    BITMAPINFO *TexInfo; /*
    Texture bitmap information */

    GLubyte *TexBits; /*
    Texture bitmap pixel bits */

    void display(void) {

    glClearColor (1.0, 0.0, 0.0, 0.0);

    glClear(GL_COLOR_BUFFER_BIT |
    GL_DEPTH_BUFFER_BIT);

    TexBits = LoadDIBitmap("escudo.bmp",
    &TexInfo);

    glTexImage2D(GL_TEXTURE_2D, 0, 3, TexInfo->
    bmiHeader.biWidth, TexInfo-> bmiHeader.biHeight, 0,
    GL_BGR_EXT,GL_UNSIGNED_BYTE, TexBits);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
    GL_REPEAT);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
    GL_REPEAT);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
    GL_LINEAR);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
    GL_LINEAR);

    glColor3f(1.0, 1.0, 1.0);

    //se activa el mapeado
    detexturas

    glEnable(GL_TEXTURE_2D);

    glBegin(GL_POLYGON);

    glTexCoord2f(0.0, 0.0);

    glVertex2f(-1.0, -1.0);

    glTexCoord2f(1.0, 0.0);

    glVertex2f(1.0, -1.0);

    glTexCoord2f(1.0, 1.0);

    glVertex2f(1.0, 1.0);

    glTexCoord2f(0.0, 1.0);

    glVertex2f(-1.0, 1.0);

    glEnd();

    glDisable(GL_TEXTURE_2D);

    glutSwapBuffers() ;

    }

    void reshape(int width, int height) {

    glViewport(0, 0, width, height);

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    gluPerspective(60.0, (GLfloat)height / (GLfloat)width,
    1.0, 128.0);

    glMatrixMode(GL_MODELVIEW);

    glLoadIdentity();

    gluLookAt(0.0, 1.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0,
    0.0);

    }

    int main(int argc, char** argv)

    {

    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH |
    GLUT_DOUBLE);

    glutInitWindowSize(400, 400);

    glutInitWindowPosition(100, 100);

    glutCreateWindow("tecnunLogo");

    glutReshapeFunc(reshape);

    glutDisplayFunc(display);

    glutMainLoop();

    return 0;

    }

    Cargar textura

    bool CTextura::CargarBMP(char
    *szNombreFichero)

    {

    FILE *hFichero;

    AUX_RGBImageRec *Imagen;

    bool bResultado=false;

    if (szNombreFichero)

    // Comprobamos que el nombre de fichero
    sea correcto

    {

    hFichero=fopen(szNombreFichero,"r");

    // Comprobamos si el fichero existe (Si
    podemos abrirlo)

    if (hFichero) //
    ¿Existe el fichero?

    {

    fclose(hFichero); //
    Cerramos el handle

    Crear(szNombreFichero);

    Imagen=auxDIBImageLoad(szNombreFichero);

    // Cargamos el BMP

    m_nAncho=Imagen->sizeX;

    m_nAlto=Imagen->sizeY;

    glTexImage2D(GL_TEXTURE_2D, 0, 3, m_nAncho, m_nAlto,
    0, GL_RGB, GL_UNSIGNED_BYTE, Imagen->data);

    bResultado=true;

    }

    }

    delete Imagen->data;

    delete Imagen;

    return bResultado;

    }

    CONCLUSIONES

    El mapeado de texturas puede resumirse en cuatro
    pasos:

    1. Se carga una imagen y se define como
    textura.

    2. Se indica cómo va a aplicarse la textura a
    cada píxel de la superficie.

    3. Se activa el mapeado de texturas.

    4. Se dibuja la escena, indicando la correspondencia
    entre las coordenadas

    de la textura y los vértices de la
    superficie.

    Normalmente en una escena suelen haber muchas
    texturas diferentes. Si dibujamos toda la geometría
    desordenadamente, es posible que cada pocos triángulos tengamos que cambiar de textura.
    El proceso de cambio de textura tiene un cierto coste, por eso es
    recomendable organizar nuestra geometría, haciendo
    grupos de
    superficies que tengan la misma textura, de manera que hagamos
    los mínimos cambios posibles. Asimismo, podemos hacer lo
    mismo con los materiales en
    el caso que hagamos uso de ellos.

    Bibliografía

    1. [IPG04]

    Introducción a la Programación Gráfica con
    OpenGL

    (Oscar García y Alex Guevara) La Salle
    2004

    2.[Map01]

    Tutorial Mapeado de textura

    (Fernando Jose Serrano) 25/04/01

    3. [Ham99]

    Hammersley, T., "Texture Shading", GameDev.Net Website
    at http://www.gamedev.net,
    October, 1999.

     

     

     

    Autor:

    Yuri A. Rodrgíuez Cruz

    Nota al lector: es posible que esta página no contenga todos los componentes del trabajo original (pies de página, avanzadas formulas matemáticas, esquemas o tablas complejas, etc.). Recuerde que para ver el trabajo en su versión original completa, puede descargarlo desde el menú superior.

    Todos los documentos disponibles en este sitio expresan los puntos de vista de sus respectivos autores y no de Monografias.com. El objetivo de Monografias.com es poner el conocimiento a disposición de toda su comunidad. Queda bajo la responsabilidad de cada lector el eventual uso que se le de a esta información. Asimismo, es obligatoria la cita del autor del contenido y de Monografias.com como fuentes de información.

    Categorias
    Newsletter