Projected Textures May 24, 2006
This is an overview of using projected texures with shaders. I use OpenGL and Cg, but this article should be general enough to be helpful whatever you use. Projected textures are at the base of many rendering techniques, such as spotlights, and shadow mapping and other similar shadowing techniques.
Using texture projection with shaders
First you need to compute a projected matrix for your texture. This is much like computing the view matrix for a camera at the world space location you're projecting the texture from. The MCam matrix is the inverse of the ObjToWorld matrix used to render the camera.
glMatrixMode( GL_TEXTURE ); glLoadIdentity(); // align the center of the view and center of the texture glTranslatef( .5f, .5f, .5f ); glScalef( .5f, .5f, .5f ); // Perspective Matrix gluPerspective( fFOV_y, 1, fNearPlane, fFarPlane ); // Camera Location & Rotation, inverted glMultMatrixf( MCam.mf );
In the vertex shader: float4 ProjectOnOS( float4x4 TextureM, float4x4 ObjToWorldM, float4 PosOS ) { float4 PosWS = mul( ObjToWorldM, PosOS ); return mul(TextureM, PosWS ); }In the pixel shader: We can use tex2Dproj( ProjectedTex, uvProj.xyw ) to get the texel. The calculation done by tex2Dproj is just a divide by w, so it's the equivalent of tex2D( ProjectedTex, uv.xy / uv.w ); Note: Probably you'll want to clamp your ProjectedTex so that it doesn't repeat, and make sure you have a black border, because projection usually doesn't make sense repeating beyond the texture. Reverse Projection
With projected textures you'll get a flipped image in the opposite direction of your projection. It's unlikely that this is desired. The first thing to do is discard any objects behind the projector's plane. However, a single object, or even a single triangle may be on both sides of the plane. So a per-pixel solution will be the most robust. At any point behind the plane of the projector, the w coordinate will be negative. So in the pixel shader you can check for this and return a black color instead of the texel. An if statement should do the trick. Although for older hardware you might want to use the w coordinate as an index into a 1D texture, where negative w is black, positive white, and multiply the projected texture by this lookup result. Shadow Mapping
I figured here is a good place to just give the gist of shadow mapping. Using the shadow map texture is a lot like using a standard projective texture. Except you project a depth texture rendered from the light's point of view. We turn on R compare for this texture, in OpenGL it might look like this:
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);Then in the Cg shader, use tex2Dproj( ProjectedTex, uvProj ); This uses all 4 components of uvProj since the z channel is compared to the texture. You'll get a one dimensional value back that's either 0 or 1, depending on if the comparison passed. Depth compare also supports linear texture filtering, (at least on most video cards,) so it isn't exactly 0 or 1 at boundaries. |