Mathematics of glTexGen: Difference between revisions

From OpenGL Wiki
Jump to navigation Jump to search
No edit summary
 
Flfirsla (talk | contribs)
No edit summary
 
(8 intermediate revisions by 6 users not shown)
Line 1: Line 1:
When you enable one of the glTexGen modes, how are the texcoords computed?<br>
{{deprecated|alternate=[[OpenGL Shading Language|the OpenGL Shading Language]]}}
If you will be using shaders, keep in mind that the vertex shader overrides this functionality, which means you have to do the work yourself.<br>
 
<br>
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 ===
=== Calculating for GL_OBJECT_LINEAR on the CPU ===
OpenGL takes the vertex and does a 4D dot product with the plane equation. Each component has its own plane equation.<br>
OpenGL takes the vertex and does a 4D dot product with the plane equation. Each component has its own plane equation.<br>
Line 8: Line 13:
GL_T has its own plane equation.<br>
GL_T has its own plane equation.<br>
Your code would look something like this
Your code would look something like this
   for(i=0; i<total; i++)
<source lang="c">
   for(i = 0; i < total; i++)
   {
   {
     myTexCoord[i].s = dot4D(myVertex[i], myPlane_S);
     myTexCoord[i].s = dot4D(myVertex[i], myPlane_S);
     myTexCoord[i].t = dot4D(myVertex[i], myPlane_T);
     myTexCoord[i].t = dot4D(myVertex[i], myPlane_T);
   }
   }
 
</source>
=== Calculating for GL_EYE_LINEAR on the CPU ===
=== Calculating for GL_EYE_LINEAR on the CPU ===
In this case, you need to transform each vertex to eye space and then do the 4D dot product.<br>
In this case, you need to transform each vertex to eye space and then do the 4D dot product.<br>
You need to transform the planes to eye space as well.
You need to transform the planes to eye space as well.
Your code would look something like this
Your code would look something like this
<source lang="c">
   myEyePlane_S = VectorTimesMatrix(myPlane_S, InverseModelviewMatrix);
   myEyePlane_S = VectorTimesMatrix(myPlane_S, InverseModelviewMatrix);
   myEyePlane_T = VectorTimesMatrix(myPlane_T, InverseModelviewMatrix);
   myEyePlane_T = VectorTimesMatrix(myPlane_T, InverseModelviewMatrix);
   //Now that we have myEyePlane_S and myEyePlane_T...
   // Now that we have myEyePlane_S and myEyePlane_T...
   for(i=0; i<total; i++)
   for(i = 0; i < total; i++)
   {
   {
     myEyeVertex = MatrixTimesVector(ModelviewMatrix, myVertex[i]);
     myEyeVertex = MatrixTimesVector(ModelviewMatrix, myVertex[i]);
Line 27: Line 34:
     myTexCoord[i].t = dot4D(myEyeVertex, myEyePlane_T);
     myTexCoord[i].t = dot4D(myEyeVertex, myEyePlane_T);
   }
   }
 
</source>
=== Calculating for GL_SPHERE_MAP on the CPU ===
=== Calculating for GL_SPHERE_MAP on the CPU ===
Used for sampling 2D textures.<br>
Used for sampling 2D textures.<br>
In this one, we are basically calculating a reflection vector, then offsetting by 0.5 and using these as texcoords.
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++)
<source lang="c">
   for(i = 0; i < total; i++)
   {
   {
     myEyeVertex = MatrixTimesVector(ModelviewMatrix, myVertex[i]);
     myEyeVertex = MatrixTimesVector(ModelviewMatrix, myVertex[i]);
     myEyeVertex = Normalize(myEyeVertex);
     myEyeVertex = Normalize(myEyeVertex);
     myEyeNormal = VectorTimesMatrix(myNormal[i], InverseModelviewMatrix);
     myEyeNormal = VectorTimesMatrix(myNormal[i], InverseModelviewMatrix);
     reflectionVector = myEyeVertex - myEyeNormal * 2.0 * dot3D(myEyeNormal, myEyeNormal);
     reflectionVector = myEyeVertex - myEyeNormal * 2.0 * dot3D(myEyeVertex, myEyeNormal);
     reflectionVector.z += 1.0;
     reflectionVector.z += 1.0;
     m = 1.0 / 2.0 * sqrt(dot3D(reflectionVector, reflectionVector));
     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.
     // 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].s = reflectionVector.x * m + 0.5;
     myTexCoord[i].t = reflectionVector.y * m + 0.5;
     myTexCoord[i].t = reflectionVector.y * m + 0.5;
   }
   }
 
</source>
=== Calculating for GL_REFLECTION_MAP on the CPU ===
=== Calculating for GL_REFLECTION_MAP on the CPU ===
Used for sampling cubemaps.
Used for sampling cubemaps.
   for(i=0; i<total; i++)
<source lang="c">
   for(i = 0; i < total; i++)
   {
   {
     myEyeVertex = MatrixTimesVector(ModelviewMatrix, myVertex[i]);
     myEyeVertex = MatrixTimesVector(ModelviewMatrix, myVertex[i]);
     myEyeVertex = Normalize(myEyeVertex);
     myEyeVertex = Normalize(myEyeVertex);
     myEyeNormal = VectorTimesMatrix(myNormal[i], InverseModelviewMatrix);
     myEyeNormal = VectorTimesMatrix(myNormal[i], InverseModelviewMatrix);
     dotResult = 2.0 * dot3D(myEyeNormal, myEyeNormal);
     dotResult = 2.0 * dot3D(myEyeVertex, myEyeNormal);
     //I am emphasizing that we write to s and t and r. Used to sample a cubemap.
     // 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].s = myEyeVertex.x - myEyeNormal.x * dotResult;
     myTexCoord[i].t = myEyeVertex.y - myEyeNormal.y * dotResult;
     myTexCoord[i].t = myEyeVertex.y - myEyeNormal.y * dotResult;
     myTexCoord[i].r = myEyeVertex.z - myEyeNormal.z * dotResult;
     myTexCoord[i].r = myEyeVertex.z - myEyeNormal.z * dotResult;
   }
   }
</source>
[[Category:Deprecated]]

Latest revision as of 09:46, 3 January 2018

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

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

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

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

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;
  }