17. OpenGL Texture Coordinate Generation (Version 2.0)

Introduction

Texture coordinate generation in OpenGL allows you to automatically calculate texture coordinates, eliminating the need for manual computation. This feature is particularly useful for creating effects like environment mapping and reflection mapping, where calculating coordinates manually would be too complex or time-consuming.

In this tutorial, we’ll discuss how to enable texture coordinate generation, the available modes, and how to implement it in a practical OpenGL example. By the end, you’ll understand how to use this feature effectively and where it can be applied.

What is Texture Coordinate Generation?

Texture coordinate generation automatically computes texture coordinates based on predefined rules. It is especially useful in cases where:

  • Manual computation of texture coordinates is impractical.
  • Real-time effects like reflections or environment mapping are needed.

Enabling Texture Coordinate Generation

OpenGL supports four types of texture coordinates that can be generated:

GL_TEXTURE_GEN_S // Horizontal texture coordinate
GL_TEXTURE_GEN_T // Vertical texture coordinate
GL_TEXTURE_GEN_R // 3D texture coordinate
GL_TEXTURE_GEN_Q // Perspective correction coordinate

To enable automatic generation for a specific axis, use the following commands:

glEnable(GL_TEXTURE_GEN_S); // Enable S coordinate generation
glEnable(GL_TEXTURE_GEN_T); // Enable T coordinate generation

You can enable any combination of these depending on your application.

Configuring the Generation Mode

The generation mode determines how OpenGL calculates the texture coordinates. Common modes include:

  • GL_OBJECT_LINEAR: Generates coordinates based on the object’s local space.
  • GL_EYE_LINEAR: Generates coordinates relative to the viewer’s perspective.
  • GL_SPHERE_MAP: Calculates coordinates for spherical environment mapping.
  • GL_REFLECTION_MAP: Ideal for dynamic reflections.

To set a mode for a specific axis, use:

glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); // Set mode for S
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); // Set mode for T

Practical Example

Let’s implement texture coordinate generation to create an environment-mapped rotating cube. The code below demonstrates how to enable and configure the generation mode.

Tutorial Code

// Include necessary libraries
#include <GL/gl.h>
#include <GL/glut.h>
#include <stdio.h>

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

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

    // Load the texture data
    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 texture
    glBindTexture(GL_TEXTURE_2D, texture); // Bind texture
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    // Set texture 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);

    // Set texture wrapping
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

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

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

// Draw a textured cube
void cube(void) {
    glBindTexture(GL_TEXTURE_2D, texture);
    glRotatef(angle, 1.0f, 1.0f, 1.0f);
    glutSolidCube(2);
}

// Display callback
void display(void) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

    texture = LoadTexture("texture.raw", 256, 256); // Load texture
    glEnable(GL_TEXTURE_2D); // Enable 2D texturing
    glEnable(GL_TEXTURE_GEN_S); // Enable S coordinate generation
    glEnable(GL_TEXTURE_GEN_T); // Enable T coordinate generation
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);

    cube(); // Draw cube
    FreeTexture(texture);

    glutSwapBuffers();
    angle++;
}

// Reshape callback
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);
}

// Main function
int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize(500, 500);
    glutCreateWindow("Texture Coordinate Generation");
    glutDisplayFunc(display);
    glutIdleFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoop();
    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
  • 11