GeeXLab
Current version: 0.17.x
»GeeXLab homepage

FurMark
Current version: 1.19.1
»FurMark homepage
»FurMark 1.9.x Submissions

GPU Caps Viewer
Current version: 1.37.0.0
»GPU Caps Viewer homepage
»GPU DB Submissions

GPU Shark
Current version: 0.10.0.4
»GPU Shark homepage


Blogs
»JeGX's HackLab

Geeks3D's Articles
»GPU Memory Speed Demystified

»Multi-Threading Programming Resources

»GeForce and Radeon OpenCL Overview

»How to Get your Multi-core CPU Busy at 100%

»How To Make a VGA Dummy Plug

»Night Vision Post Processing Filter


PhysX FluidMark
Current version: 1.5.2
»FluidMark homepage
»FluidMark 1.4.x Submissions

TessMark
Current version: 0.3.0
»TessMark homepage

ShaderToyMark
Current version: 0.3.0
»ShaderToyMark homepage
»ShaderToyMark Scores

Demoniak3D
Current Version: 1.23.0
»Demoniak3D
»Download
»Libraries and Plugins
»Demos
»Online Help - Reference Guide
»Codes Samples

3D Graphics Search Engine:

The Geeks Of 3D

 
The Art of Texturing Using The OpenGL Shading Language

By Jerome Guinot aka 'JeGX' - jegx [at] ozone3d (dot) net

Initial draft: April 15, 2006


[ Index ]

Introduction | Page 2 | Page 3 | Page 4 | Page 5 | Page 6 | Page 7 | Page 8 | Conclusion

»Next Page



8 - Projective Texture Mapping

The projective texture mapping is a technique allowing a texture to be projected onto the scene's objects like a slide projector would do it.

The secret of texture projection is based on the texture projection matrix initialization also called TexGenMatrix. If your 3D engine already performs projective texturing using the 3D pipeline fixed functions, the texGen matrix may be initialized by the following code:

glActiveTextureARB( GL_TEXTURE0_ARB );
glTexGeni(GL_S, GL_EYE_PLANE, &TexGenMatrix[0]);
glTexGeni(GL_T, GL_EYE_PLANE, &TexGenMatrix[4]);
glTexGeni(GL_R, GL_EYE_PLANE, &TexGenMatrix[8]);
glTexGeni(GL_Q, GL_EYE_PLANE, &TexGenMatrix[12]);	

This matrix is accessible in the vertex shader by the gl_TextureMatrix[tu] variable where tu is the texture unit for which the TexGenMatrix matrix has been initialized (in the example, tu=0).

For those that would like to implement the TexGenMatrix initialization, just understand that this matrix is somewhat equivalent to the camera matrix. Indeed, the texGen matrix defines all transformations (projection matrix, view matrix) of the projector that, in the texture projection context, works like a camera. For more detail on this topic, see the excellent whitepaper by Cass Everitt: Projective Texture Mapping.

The DEMO_Projective_Texture_Mapping.xml demo shows all the stages of the texGen matrix construction for projective texture mapping. The construction of the texGen matrix being done using the great LUA language, the conversion to another language should be a mere formality!

The following image shows the rendering of the DEMO_Projective_Texture_Mapping.xml demo:


Projective Texture Mapping
Fig. 22 - the DEMO_Projective_Texture_Mapping.xml demo

The major advantage of making the texture projection with shaders is that the reverse projection can be solved in a simple and clean way. The following screenshot illustrates the reverse projection:


Reverse Projection Problem
Fig. 23 - the problem of reverse projection

The projected texture coordinates are obtained by multiplying the TexGenMatrix by the vertex position in world space (cf posWorld in the code). These coordinates form a {s, t, r, q} quadruplet. The reverse projection occurs when the {q} coordinate becomes negative. It is not easy to act on the {q} coordinate at the fixed functions level, but in a pixel shader it is really simple as shown by the following shader code (from the DEMO_Projective_Texture_Mapping.xml demo):

[Vertex_Shader]
		
uniform mat4 TexGenMat;
uniform mat4 InvViewMat;
varying vec3 normal, lightDir, eyeVec;

void main()
{	
	normal = gl_NormalMatrix * gl_Normal;
	
	vec4 posEye =  gl_ModelViewMatrix * gl_Vertex;
	vec4 posWorld = InvViewMat * posEye;
	gl_TexCoord[0] = TexGenMat * posWorld;

	lightDir = vec3(gl_LightSource[0].position.xyz - posEye.xyz);
	eyeVec = -posEye.xyz;

	gl_Position = ftransform();		
}


[Pixel_Shader]

uniform sampler2D projMap;
varying vec3 normal, lightDir, eyeVec;

void main (void)
{
  vec4 final_color = 
  (gl_FrontLightModelProduct.sceneColor * gl_FrontMaterial.ambient) + 
  (gl_LightSource[0].ambient * gl_FrontMaterial.ambient);
	
  vec3 N = normalize(normal);
  vec3 L = normalize(lightDir);
	
  float lambertTerm = dot(N,L);
	
  if(lambertTerm > 0.0)
  {	
    final_color += gl_LightSource[0].diffuse * 
	gl_FrontMaterial.diffuse * lambertTerm;	
		
    vec3 E = normalize(eyeVec);
    vec3 R = reflect(-L, N);
    float specular = pow( max(dot(R, E), 0.0), 
	                     gl_FrontMaterial.shininess );
    final_color += gl_LightSource[0].specular * 
	               gl_FrontMaterial.specular * 
				   specular;	
		
		
    // Suppress the reverse projection.
    if( gl_TexCoord[0].q>0.0 )
    {
      vec4 ProjMapColor = texture2DProj(projMap, gl_TexCoord[0]);
      final_color += ProjMapColor*lambertTerm;			
    }
  }
  
  gl_FragColor = final_color;			
}

This pixel shader is a variation of the phong lighting one available in the Point Light tutorial. The projected texture coordinates are calculated by the following code:

vec4 posEye =  gl_ModelViewMatrix * gl_Vertex;
vec4 posWorld = InvViewMat * posEye;
gl_TexCoord[0] = TexGenMat * posWorld;

where TexGenMat is the texture projection matrix and InvViewMat is the inverse view matrix. The goal of this last one is simply to calculate the vertex position in world space. The texture projection is done in the pixel shader by the following code:

if( gl_TexCoord[0].q>0.0 )
{
  vec4 ProjMapColor = texture2DProj(projMap, gl_TexCoord[0]);
  final_color += ProjMapColor*lambertTerm;			
}

The texture2DProj() allows us to directly exploit the projected textures coordinates stored in gl_TexCoord[0]. The call to texture2DProj() could be remplaced by a call to texture2D() but in that case we have to divide the {s, t} coordinates by the {q} one as the following code shows it:

if( gl_TexCoord[0].q>0.0 )
{
  vec2 projCoords = gl_TexCoord[0].st / gl_TexCoord[0].q;
  vec4 ProjMapColor = texture2D(projMap, projCoords);
  final_color += ProjMapColor*lambertTerm;			
}




[ Index ]

Introduction | Page 2 | Page 3 | Page 4 | Page 5 | Page 6 | Page 7 | Page 8 | Conclusion

»Next Page





GeeXLab demos


GLSL - Mesh exploder


PhysX 3 cloth demo


Normal visualizer with GS


Compute Shaders test on Radeon


Raymarching in GLSL



Geeks3D latest news


Geeks3D forum news


Misc
»Texture DataPack #1
»Asus Silent Knight CPU Cooler
Page generated in 0.0099899768829346 seconds.