Reflection using projective textures on the fixed function pipelineBy Rim van Wersch, January 5 2006 |
This tutorial covers redering a reflection of a scene to a texture and mapping this texture to a flat surface. The techniques used are RenderToSurface and setting up a projective texture transformation on the target surface of the reflection. It also uses clip planes to limit the reflection render to the scene above the reflective surface.
How does it work?
Before we render the actual scene, we'll need to render the reflection of the screen to a texture so we have it ready to put it onto our reflective surface in the main scene render. To do this, we call our RenderReflection function below before we start rendering our scene by calling device.BeginScene() (otherwise rendering to the texture will fail).
The code in this method first sets up a render to texture target. After we cleared the device, we'll set the appropriate view matrix for rendering the reflection and we reverse the cullmode to match. Then we set up our clipping plane at the same place where our reflective plane is going to be, so the reflection doesn't appear to stick out of the reflective surface. After all this, we render our scene as normal (without the reflective plane) and finally we reset our renderstates.
private void RenderReflection( Device device ) { ? ?using( Surface surface = reflectionTexture.GetSurfaceLevel(0) ) ? ?{ ? ? ? ?Viewport view = new Viewport(); ? ? ? ?view.Width = refWidth; ? ? ? ?view.Height = refHeight; ? ? ? ?view.MaxZ = 1.0f; ? ? ? ?rts.BeginScene( surface, view ); ? ? ? ?device.Clear( ClearFlags.Target | ClearFlags.ZBuffer, 0x00efefff, 1.0f, 0 ); ? ? ? ?// Do magic reflection stuff ? ? ? ? ? ? ? ? ? ? ? ?reflectViewMatrix = Matrix.Identity; ? ? ? ?reflectViewMatrix.Reflect( reflectPlane ); ? ? ? ?reflectViewMatrix = reflectViewMatrix * camera.ViewMatrix; ? ? ? ?device.Transform.View = reflectViewMatrix; ? ? ? ?device.Transform.Projection = camera.ProjectionMatrix; ? ? ? ? ? ? ? ? ? ? ? ?device.RenderState.CullMode = Cull.Clockwise; ? ? ? ? ? ? ? ?device.ClipPlanes[0].Enabled = true; ? ? ? ?device.ClipPlanes[0].Plane = reflectPlane; ? ? ? ?device.RenderState.Clipping = true; ? ? ? ?// render scene ? ? ? ? ? ? ? ? ? ? ? ?device.Material = mat; ? ? ? ?device.SetTexture(0, null ); ? ? ? ?device.Transform.World = Matrix.RotationYawPitchRoll( angle, angle * 2.0f, angle * 3.0f ) * Matrix.Translation(0, 0.75f, 0); ? ? ? ? ? ? ? ? ? ? ? ?mesh.DrawSubset(0); ? ? ? ?// reset render states ? ? ? ?device.RenderState.Clipping = false; ? ? ? ?device.ClipPlanes[0].Enabled = false; ? ? ? ?// end RTS ? ? ? ?rts.EndScene( Filter.None ); ? ?} }
So, once we have our scene reflection rendered to our texture, it's time to map it onto our reflective surface in our main scene render. In this example I used a little Plane utility class to make rendering our reflective plane a bit easier. The code for that is included in the project. The main point of interest in our actual scene rendering is how to set up the texture states for generating projected texture coordinates on our reflective surface. More information on this can be found in .
// set up scene view & projection ? ? ? ? ? ? ? ? device.Transform.Projection = camera.ProjectionMatrix; device.Transform.View = camera.ViewMatrix; // setup texture projection device.TextureState[0].TextureCoordinateIndex = (int)TextureCoordinateIndex.CameraSpacePosition; device.TextureState[0].TextureTransform = TextureTransform.Count3 | TextureTransform.Projected; Matrix inverseView = camera.ViewMatrix; inverseView.Invert(); device.Transform.Texture0 = inverseView * reflectViewMatrix * camera.ProjectionMatrix * remapMatrix; // draw water geometry device.Transform.World = Matrix.Translation(0, 0, 0); device.Material = waterMat; ? ? ? ? ? ? ? ? device.SetTexture(0, reflectionTexture ); plane.Render( device ); // reset transforms & draw teapot device.Transform.Texture0 = Matrix.Identity; device.TextureState[0].TextureTransform = TextureTransform.Disable; device.Material = mat; device.SetTexture(0, null ); device.RenderState.CullMode = Cull.CounterClockwise; ? ? device.Transform.World = Matrix.RotationYawPitchRoll( angle, angle * 2.0f, angle * 3.0f ) * Matrix.Translation(0, 0.75f, 0); mesh.DrawSubset(0);
Files for this tutorial
Filename | Size |
? Projective reflection project.zip | 197.7 KB |