Mathematics of glTexGen

From OpenGL Wiki
Jump to navigation Jump to search

glTexGen is a function available in "old OpenGL" (before shader capable GPUs came along). The purpose of this page is to show you how the coordinates are computed so that you can implement it yourself in your own shaders. The code shows how it would be done on the CPU. It is left up to you as an exercise to do the same with shaders.

glTexGen was an operation that was performed for each vertex so you might want to code it inside your vertex shader if you want to simulate "old OpenGL".

glTexGen is explained in the "old OpenGL" specification, although it is not exactly in code form. They present to you the mathematics and explain it. You might want to have a look at the "old OpenGL" specification. Version 1.2 of the specification will do. You can also find it in the Red Book (also called the OpenGL programming guide).

Calculating for GL_OBJECT_LINEAR on the CPU[edit]

OpenGL takes the vertex and does a 4D dot product with the plane equation. Each component has its own plane equation.
GL_S has its own plane equation.
GL_R has its own plane equation.
GL_T has its own plane equation.
Your code would look something like this

  for(i = 0; i < total; i++)
  {
    myTexCoord[i].s = dot4D(myVertex[i], myPlane_S);
    myTexCoord[i].t = dot4D(myVertex[i], myPlane_T);
  }

Calculating for GL_EYE_LINEAR on the CPU[edit]

In this case, you need to transform each vertex to eye space and then do the 4D dot product.
You need to transform the planes to eye space as well. Your code would look something like this

  myEyePlane_S = VectorTimesMatrix(myPlane_S, InverseModelviewMatrix);
  myEyePlane_T = VectorTimesMatrix(myPlane_T, InverseModelviewMatrix);
  // Now that we have myEyePlane_S and myEyePlane_T...
  for(i = 0; i < total; i++)
  {
    myEyeVertex = MatrixTimesVector(ModelviewMatrix, myVertex[i]);
    myTexCoord[i].s = dot4D(myEyeVertex, myEyePlane_S);
    myTexCoord[i].t = dot4D(myEyeVertex, myEyePlane_T);
  }

Calculating for GL_SPHERE_MAP on the CPU[edit]

Used for sampling 2D textures.
In this one, we are basically calculating a reflection vector, then offsetting by 0.5 and using these as texcoords.

  for(i = 0; i < total; i++)
  {
    myEyeVertex = MatrixTimesVector(ModelviewMatrix, myVertex[i]);
    myEyeVertex = Normalize(myEyeVertex);
    myEyeNormal = VectorTimesMatrix(myNormal[i], InverseModelviewMatrix);
    reflectionVector = myEyeVertex - myEyeNormal * 2.0 * dot3D(myEyeVertex, myEyeNormal);
    reflectionVector.z += 1.0;
    m = 1.0 / (2.0 * sqrt(dot3D(reflectionVector, reflectionVector)));
    // I am emphasizing that we write to s and t. Used to sample a 2D texture.
    myTexCoord[i].s = reflectionVector.x * m + 0.5;
    myTexCoord[i].t = reflectionVector.y * m + 0.5;
  }

Calculating for GL_REFLECTION_MAP on the CPU[edit]

Used for sampling cubemaps.

  for(i = 0; i < total; i++)
  {
    myEyeVertex = MatrixTimesVector(ModelviewMatrix, myVertex[i]);
    myEyeVertex = Normalize(myEyeVertex);
    myEyeNormal = VectorTimesMatrix(myNormal[i], InverseModelviewMatrix);
    dotResult = 2.0 * dot3D(myEyeVertex, myEyeNormal);
    // I am emphasizing that we write to s and t and r. Used to sample a cubemap.
    myTexCoord[i].s = myEyeVertex.x - myEyeNormal.x * dotResult;
    myTexCoord[i].t = myEyeVertex.y - myEyeNormal.y * dotResult;
    myTexCoord[i].r = myEyeVertex.z - myEyeNormal.z * dotResult;
  }