Upcoming Events
Southwest Gaming Expo
11/20 - 11/22 @ Dallas, TX

Workshop on Network and Systems Support for Games (NetGames 2009)
11/23 - 11/25 @ Paris, France

ICIDS 2009 Interactive Storytelling
12/9 - 12/11 @ Guimarães, Portugal

Global Game Jam
1/29 - 1/31  

More events...


Quick Stats
6842 people currently visiting GDNet.
2341 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!



Link to us

Link to us

  Intel sponsors gamedev.net search:   

Realistic Natural Effect Rendering: Water I


Putting it all together

As a reminder, the following matrices are used throughout the reflective water algorithm:

Standard camera and view matrices
Mo Local object matrix, transforming local object space to world space
Mc Camera matrix, transforming world space to camera space
Mp Camera projection matrix, transforming camera space to clip space
Mvp Combined view projection matrix, transforming world (or object) space to clip space
Special matrices
Mf Reflection matrix, reflects a world space object around a world space plane
Mr Projective remapping matrix, remaps projected coordinates from clip space to texture space
Combined reflective and projective matrices
Mreflview The reflective view matrix, transforms world (or object) space into reflected camera space
Mprojtex The projective texture matrix, transforms world space into projective texture space

The reflective water is generated in two passes: first the environment around the water surface is reflected into a texture, and then the water mesh is rendered projecting the distorted reflection texture onto its surface:

Pass 1: reflection texture generation
  • Bind a render texture as current render target: this will be the future reflection texture
  • Load Mp as the current projection matrix
  • Mreflview = Mc * Mf (* Mo)
  • Push the model view matrix, load Mreflview as the current modelview matrix
  • Enable a user clip plane at the water surface
  • Invert the primitive culling / winding order
  • Render the entire scene (except the water) to the currently bound render texture
  • Restore the culling / winding order
  • Disable user clip plane
  • Pop the previous model view matrix
  • Bind the framebuffer as render target

At this point, the normal 3D scene can be rendered as usual. The reflection has been saved in the reflection texture for later processing. Pass 2 will be run as soon as the engine decides to render the water surface:

Pass 2: rendering the reflective water surface
  • Bind the reflection texture onto texture unit 0
  • Enable the projective water vertex and fragment shaders (Listing 5)
  • Mvp = Mp * Mc (* Mo)
  • Mprojtex = Mr * Mp * Mc
  • Bind Mvp and Mprojtex to the vertex shader
  • Optionally enable alpha blending for transparent water
  • Render the water grid mesh, supplying vertex positions and vertex normals
  • Disable alpha blending, if applicable
  • Disable both shaders

Only pass 2 requires special shaders in order to render the water surface: a vertex shader to create the distorted projective texture coordinates, and a fragment shader to perform the projective texture lookup. Alpha blending can be used to make the water surface slightly transparent. In this case, additional functionality has to be added to the shaders, in order to pass the transparency into the alpha component of the output colour. A simple example of such a basic water shader combo is given below:

void VP_water_1( float4 inPos : POSITION,
                 float3 inNormal : NORMAL,
                 out float4 outPos : POSITION,
                 out float4 outTexProj : TEXCOORD0,
                 uniform float4x4 Mvp,
                 uniform float4x4 Mprojtex )
{
   // transform vertex position by combined view projection matrix
   outPos = mul(Mvp, inPos);

   // the adjustable displacement factor
   float d = 4.0;
   
   // temporary variable to hold the displaced vertex position
   float4 dPos;
   // displace the xy components of the vertex position
   dPos.xy = inPos.xy + d * inNormal.xy;
   // the original z component is kept
   dPos.z = inPos.z;
   // the w component is always one for a point
   dPos.w = 1.0;

   // transform the displaced vertex position by the projective
   // texture matrix and copy the result into homogeneous
   // texture coordinate set 0
   outTexProj = mul(Mprojtex, dPos);
}

void FP_water_1( float4 inTexProj : TEXCOORD0,
                 out float4 outCol : COLOR,
                 uniform sampler2D ReflectMap )
{
   // projectively sample the 2D reflection texture
   outCol.rgb = tex2Dproj(ReflectMap, inTexProj).rgb;
   // optionally set alpha component to transparency,
   // a constant value in this simple example
   outCol.a = 0.8;
}
Source 4: projective displaced reflective water shader

The planar reflection technique described in this article allows basic water surfaces to reflect their local environment according to the surface dynamics. The next article will describe how to add refractions and account for the Fresnel effect. It will also discuss depth dependent visibility limitation, adding small-scale perpixel turbulences onto the surface, and how to perform basic specular water lighting.

References

[1] nVidia: Cg downloads
[2] Ken Perlin: Improved Noise reference implementation
[3] nVidia: Cube Map tutorial
[4] nVidia paper: Projective texture mapping
[5] Eric Lengyel, Terathon Software: Oblique frustum clipping

Copyright © 2004 by Yann Lombard. All rights reserved.

Images: http://www.freeimages.co.uk



Contents
  Introduction
  Optical properties of real life water
  Planar mirrors for local reflections
  Clipping planes
  Putting it all together

  Printable version
  Discuss this article

The Series
  Water I