20. OpenGL MipMap Generation (Version 2.0)

Introduction

Mipmaps are a group of scaled-down versions of a texture that OpenGL uses to enhance rendering performance and image quality. Instead of resizing the texture dynamically for each frame, OpenGL selects the mipmap level that best fits the object’s size. This approach smooths out textures, eliminates aliasing, and creates a visually pleasing result.

In this tutorial, you’ll learn how to generate mipmaps in OpenGL, update texture filters to support mipmapping, and integrate mipmaps into your rendering workflow.

Why Use Mipmaps?

Mipmaps improve rendering by:

  • Reducing aliasing and moiré patterns when textures are minified (displayed smaller than their original size).
  • Improving performance by using smaller texture levels when the full resolution is unnecessary.

Generating Mipmaps

To generate mipmaps, replace the typical glTexImage2D call with gluBuild2DMipmaps. Here’s an example:

// Replace this:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);

// With this:
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, data);

In this function:
GL_TEXTURE_2D: Specifies the target texture.
3: Specifies the internal format (e.g., RGB).
width and height: Dimensions of the base texture.
GL_RGB, GL_UNSIGNED_BYTE: Specifies the texture format and data type.
data: The raw texture data.

Configuring Texture Filters

When using mipmaps, the texture filters must also be updated to take advantage of them. Replace the default linear filters with mipmap filters:

// Default filters
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

// Mipmap filters
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);

Tutorial Code

Here is the complete code demonstrating mipmap generation and usage:

#include <GL/gl.h>
#include <GL/glut.h>
#include <stdio.h>

GLuint texture; // The texture object
GLfloat angle = 0.0; // Rotation angle

// Function to load texture with mipmaps
GLuint LoadTexture(const char *filename, int width, int height) {
    GLuint texture;
    unsigned char *data;
    FILE *file;

    // Load the texture data from file
    file = fopen(filename, "rb");
    if (file == NULL) return 0;
    data = (unsigned char *)malloc(width * height * 3);
    fread(data, width * height * 3, 1, file);
    fclose(file);

    glGenTextures(1, &texture); // Generate a texture object
    glBindTexture(GL_TEXTURE_2D, texture); // Bind the texture
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    // Set texture parameters for mipmapping
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    // Generate the mipmaps
    gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, data);
    free(data); // Free the texture data
    return texture;
}

void FreeTexture(GLuint texture) {
    glDeleteTextures(1, &texture); // Delete the texture object
}

void square(void) {
    glBindTexture(GL_TEXTURE_2D, texture); // Bind the texture
    glPushMatrix();
    glRotatef(angle, 1.0f, 1.0f, 1.0f);
    glBegin(GL_QUADS);
    glTexCoord2d(0.0, 0.0); glVertex2d(-1.0, -1.0);
    glTexCoord2d(1.0, 0.0); glVertex2d(1.0, -1.0);
    glTexCoord2d(1.0, 1.0); glVertex2d(1.0, 1.0);
    glTexCoord2d(0.0, 1.0); glVertex2d(-1.0, 1.0);
    glEnd();
    glPopMatrix();
}

void display(void) {
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    glEnable(GL_TEXTURE_2D);
    gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

    square();
    glutSwapBuffers();
    angle++;
}

void reshape(int w, int h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
    glMatrixMode(GL_MODELVIEW);
}

int main(int argc, char **argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowSize(500, 500);
    glutCreateWindow("OpenGL Mipmaps Example");
    glutDisplayFunc(display);
    glutIdleFunc(display);
    glutReshapeFunc(reshape);

    texture = LoadTexture("texture.raw", 256, 256); // Load texture
    glutMainLoop();
    FreeTexture(texture);
    return 0;
}

If you have any questions or run into issues, feel free to email me at swiftless@gmail.com. Happy coding!

  • March 25, 2010
  • 8