Mipmapping en OpenGL

El término mipmap fue introducido por Lance Williams en su paper Pyramidal Parametrics presentado en la conferencia SIGGRAPH en el año 1998. Mip viene del latin multim im parvo que significa “muchas cosas en un pequeño lugar”. La técnica de mipmapping es empleada para empacar diversos tamaños de imágenes en memoria y evitar artefactos causados por los cambios de la distancia entre el observador y un objeto texturizado. comparison

Imagen con iluminación y con textura (Extraído del OpenGL Programming Book aka “red book”)


En OpenGL, el almacenamiento de Texturas es una parte de las funcionalidades de los objetos Texturas que contienen los datos (manejados como píxeles) donde se almacena una textura. Este almacenamiento puede contener una o más imágenes de cierta dimensión. Cada tipo de textura (1D, 2D, 3D, Rectangle, Buffer, CubeMap, 1D/2D Array y Multisample) tiene un ordenamiento de las imágenes en su almacenamiento. A su vez, cada textura puede tener mipmaps que son pequeñas versiones de una misma imagen empleadas en el texture sampling y filtering. Cada nivel de un mipmap tiene un conjunto separado de imágenes. Dado que cada textura puede almacenar diversas imágenes, es importante identificar una imagen en particular dentro de la textura. Cada imagen en una textura tiene un identificador único que depende del tipo de textura:

  • Si la textura tiene mipmap(GL_TEXTURE_1DGL_TEXTURE_2DGL_TEXTURE_3DGL_TEXTURE_1D_ARRAYGL_TEXTURE_2D_ARRAYGL_TEXTURE_CUBE_MAPGL_TEXTURE_CUBE_MAP_ARRAY), el valor del level es donde se encuentra una imagen
  • Para las texturas del tipo Array (GL_TEXTURE_1D_LAYERGL_TEXTURE_2D_LAYERGL_TEXTURE_CUBE_MAP_ARRAYGL_TEXTURE_2D_MULTISAMPLE_ARRAY), el valor layer es donde se encuentra una imagen
  • Para las texturas Cubemap, el valor face dentro del array layer y el mipmap level. En el caso de las texturas cubemap array, las capas y las caras son combinadas en layer-faces.

Todas las imágenes que tienen el mismo nivel de mipmap (i.e. todos los array layers ó caras del cubemap en un mipmap) en una textura tendrán el mismo tamaño (existen formas de romper esta regla). Este tamaño depende del tamaño del nivel del mipmap base de la textura: nivel 0. El tamaño del nivel 0 define el tamaño original de la textura. Para cada nivel del mipmap por encima del nivel 0, el tamaño decrece a la mitad redondeando hacia abajo. Por ejemplo, para una 2D textura de tamaño 75×75 píxeles en su nivel 0, la imagen en el nivel 1 tendrá un tamaño de 37×37 píxeles; en el nivel 2 de 18×18 píxeles y así sucesivamente. La cadena del mipmap finaliza cuando todas las dimensiones son 1; ese se considera el máximo nivel del mipmap.

 

Nótese que se representa el nivel máximo como un índice considerando que la base es 0. Existen tres tipos de almacenamiento para las texturas: almacenamiento del tipo mutable, inmutable y buffer. El almacenamiento inmutable asigna el espacio para todas las imágenes de la textura una sola vez al mismo tiempo con una sola invocación a función (niveles de mipmap, array layer y caras del cubemap). El almacenamiento mutable permite hacer modificar completamente el espacio de asignación de memoria de un objeto de textura. El almacenamiento tipo buffer, solo puede ser empleado por Buffer Textures (este tópico y Buffer Object lo explicaré en otro post posterior) y no puede emplear almacenamiento inmutable o mutable. Algo interesante a conocer que el almacenamiento tipo inmutable se refiere al espacio de memoria asignado y no a los valores que contiene, los cuales si se pueden modificar. Así, es posible ver el almacenamiento inmutable como un const pointer en C++.

Generación de Mipmaps

Contando desde las primeras versiones OpenGL hasta la actualidad, existen 3 formas de generar mipmaps: gluBuild2DMipmaps, empleando GL_GENERATE_MIPMAP como parámetro de glTexParameteri y glGenerateMipmap. Para este post, nos concentraremos en esta última.

Tomando como base texturas 2D, la función glTexImage2D es la manera clásica de reservar memoria para el almacenamiento de texturas. Esta función crea almacenamiento mutable. De esta forma, si se desea crear mipmaps se debe asignar memoria para cada nivel del mipmap por separado (distintas invocaciones) y calcular manualmente el tamaño de las imágenes mipmap. Por otro lado, la función glTextStorage2D permite alojar almacenamiento inmutable para las imágenes, permitiendo reservar el espacio para los mipmaps una sola vez. Así, es posible invocar a glTextImage2D en un mismo nivel de mipmap con diferente tamaño (OpenGL destruirá el mipmap original y reservará el espacio para la nueva).

glTexImage2D y glTexStorage2D son como la función malloc del lenguaje C, y glTexSubImage2D actúa como un memcpy. La función glGenerateMipmap es una función que recibe una textura base y genera todos los niveles de mipmap una sola vez. La signatura de la función glTexStorage2D es:

void glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);

El target especifica el destino de la operación, pudiendo tomar valores de GL_TEXTURE2D, GL_PROXY_TEXTURE_2D, GL_TEXTURE_1D_ARRAY, GL_PROXY_TEXTURE_1D_ARRAY, GL_TEXTURE_RECTANGLE, GL_PROXY_TEXTURE_RECTANGLE ó GL_PROXY_TEXTURE_CUBE_MAP.

El internalformat especifica el formato interno de OpenGL para el almacenamiento de los datos.

El valor de width y height representan el ancho y alto de la textura medido en texels respectivamente.

Por ejemplo, glTexStorage2D con target GL_TEXTURE_2D es equivalente a:

for (int i = 0; i < levels; i++)
{
    glTexImage2D(target, i, internalformat, width, height, 0, format, type, NULL);
    width = max(1, (width / 2));
    height = max(1, (height / 2));
}

Su comportamiento es similar al emplear otros target. La función glTexStorage está disponible en el core de OpenGL desde la versión 4.2 y actualmente está disponible para ser empleada  como glTexStorage1d, glTexStorage2dMultisample, glTexStorage3D, glTexStorage3dMultisample.

Por otra parte, la función glGenerateMipmaps está en el core de OpenGL desde la versión 3.0.

Como se ve hasta ahora, no existe una relación entre glTexStorage y glGenerateMipmap, son funcionalidades ortogonales. La función glTexStorage solo reserva el espacio para las texturas sin asignarle datos (se asignan con glTexSubImage), e igualmente crea espacio para las texturas mipmap. Por otro lado, la función glGenerateMipmaps crea los datos de los mipmaps y crea el espacio para los mipmaps en caso de no haber sido asignado aún.

Resumen: Crea el espacio de las texturas en OpenGL con glTexStorage y los mipmaps con glGenerateMipmap 🙂

Anuncios

Acerca de smittynpro

Escribiendo algunas cosas de computación gráfica
Esta entrada fue publicada en Código, Ideas y etiquetada , , . Guarda el enlace permanente.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s