Game Development Community

dev|Pro Game Development Curriculum

Rendering Water Under Terrains

by Desmond Fletcher · 10/16/2003 (2:20 pm) · 4 comments

Under terrain water rendering
Desmond Fletcher & Richard O'Brien
Additions in each section below are in bold; code areas deleted for brevity are marked as italic.
//-----------------------------------------------
(fluid.h--->about line 129)
// Setup at initialization (in FluidSupport.cc):
    //
    void SetInfo ( f32& X0,
                   f32& Y0,
                   f32& SizeX,
                   f32& SizeY,
                   f32  SurfaceZ,
                   f32  WaveAmplitude,
                   f32& Opacity,
                   f32& EnvMapIntensity,
                   bool RemoveWetEdges,  //V23
                   [b]bool RenderUnderTerr, //V23 Added for subterranean water render[/b]
		bool UseDepthMap,
		f32  TessellationSurface,
		f32  TessellationShore,
		f32  SurfaceParallax,
		f32  FlowAngle,
		f32  FlowRate,
		f32  DistortGridScale,
	        f32  DistortMagnitude,
	        f32  DistortTime );
//-----------------------------------------------
(fluid.h--->about 215)
//  Private Variables
//
public:
    s32     m_SquareX0,   m_SquareY0;       // Anchor in terrain squares
    s32     m_SquaresInX, m_SquaresInY;     // Number of squares in fluid region
private:
	 f32		m_DepthTexelX, m_DepthTexelY;	  // MM: Added Depth Texel X/Y.
    s32     m_BlocksInX,  m_BlocksInY;      // Number of blocks in fluid region
    f32     m_SurfaceZ;                     // Altitude of fluid surface
    bool    m_RemoveWetEdges;               // Dry fill all edges of the fluid block 
                                            //V23 Convert from S32 to bool
    [b]bool    m_RenderUnderTerr;              //V23 Render water under terrain[/b]

//-----------------------------------------------
(fluidSupport.cc--->about line 21)
fluid::fluid( void )
{
    m_Instances     +=  1;

    // Fill out fields with a stable, if useless, state.
    m_SquareX0        =  0;
    m_SquareY0        =  0;
    m_SquaresInX      =  4;
    m_SquaresInY      =  4;
    m_BlocksInX       =  1;
    m_BlocksInY       =  1;
    m_HighResMode     =  1;
    m_RemoveWetEdges  =  false; //V23
    [b]m_RenderUnderTerr =  false; //V23 Render water under terrain[/b]
//-----------------------------------------------
(fluidSupport.cc--->on down about line 291)
// Classify each point as above or below ground.

    if( m_pTerrain )
    {
    [b]//V23 See if we want to render everything below terrain
    if ( m_RenderUnderTerr )
       {
       pG = pGrid;
       for( Y = 0; Y < m_SquaresInY+1; Y++ )
          for( X = 0; X < m_SquaresInX+1; X++ ) {
             *pG = 1;
             pG++;
          }
       }
    //V23 Nope, so we use original code
    else
       {[/b]
       u16 FluidLevel = (u16)((m_SurfaceZ + (m_WaveAmplitude/2.0f)) * 32.0f);

       pG = pGrid;
       for( Y = 0; Y < m_SquaresInY+1; Y++ )
        for( X = 0; X < m_SquaresInX+1; X++ )
        {
             i = (((m_SquareY0+Y) & 255) << 8) + ((m_SquareX0+X) & 255);
             *pG = (u8)(FluidLevel > m_pTerrain);
             pG++;
          }
       }
    }
    //V23 end
//-----------------------------------------------
(fluidSupport.cc--->on down about line 381)
void fluid::SetInfo( f32& X0,
                     f32& Y0,
                     f32& SizeX,
                     f32& SizeY,
                     f32  SurfaceZ,
                     f32  WaveAmplitude,
                     f32& Opacity,
                     f32& EnvMapIntensity,
                     bool RemoveWetEdges,  //V23
                     [b]bool RenderUnderTerr, //V23[/b]

//-----------------------------------------------
(fluidSupport.cc--->on down in the same function at about line 441)
// Get the easy stuff first.
    m_SurfaceZ        = SurfaceZ;
    m_WaveAmplitude   = WaveAmplitude;
    m_RemoveWetEdges  = RemoveWetEdges;
    [b]m_RenderUnderTerr = RenderUnderTerr; //V23[/b]

//-----------------------------------------------
(waterBlock.cc--->about line 43)
WaterBlock::WaterBlock()
{
    mNetFlags.set(Ghostable | ScopeAlways);
    mTypeMask = WaterObjectType;

    mObjBox.min.set( 0, 0, 0 );
    mObjBox.max.set( 1, 1, 1 );

    mLiquidType           = eOceanWater;
    mDensity              = 1; 
    mViscosity            = 15; 
    mWaveMagnitude        = 1.0f; 
    mSurfaceTexture       = TextureHandle();
    mSurfaceOpacity       = 0.75f; 
    mEnvMapOverTexture    = TextureHandle();	// MM: Added Over/Under Env Texture Support.
    mEnvMapUnderTexture   = TextureHandle();	// MM: Added Over/Under Env Texture Support.
    mEnvMapIntensity      = 0.4f;			   // MM: Added Over/Under Env Texture Support.
	 mShoreTexture         = TextureHandle();	// MM: Added Shore Texture.
    mRemoveWetEdges       = false;
    //V23 mRemoveWetEdges = true;
    [b]mRenderUnderTerr      = false;           //V23 Subterrainean rendering[/b]
//-----------------------------------------------
(waterBlock.cc--->about line 115)
void WaterBlock::UpdateFluidRegion( void )
{
   [i]//<<code not shown>>[/i]

    mFluid.SetInfo( P.x,         P.y,
                    mObjScale.x, mObjScale.y,
                    mSurfaceZ,
                    mWaveMagnitude,
                    mSurfaceOpacity,
                    mEnvMapIntensity,                    
                    mRemoveWetEdges,
		              [b]mRenderUnderTerr,  //V23 Under terrain rendering[/b]


//-----------------------------------------------
(waterBlock.cc--->about line 766)
void WaterBlock::initPersistFields()
{
   [i]//<<code not shown>>[/i]

    addGroup("Misc");	// MM: Added Group Header.
    addField( "audioEnvironment",   TypeAudioEnvironmentPtr, Offset( mAudioEnvironment, WaterBlock ) );
    addField( "removeWetEdges",     TypeBool, Offset( mRemoveWetEdges,	WaterBlock ) );
    [b]addField( "renderUnderTerrain", TypeBool, Offset( mRenderUnderTerr, WaterBlock ) );  //V23[/b]
    endGroup("Misc");	// MM: Added Group Footer.

//-----------------------------------------------
(waterBlock.cc--->about line 864)
U32 WaterBlock::packUpdate( NetConnection* c, U32 mask, BitStream* stream )
{

   [i]//<<code not shown>>[/i]

    [b]stream->write( mRenderUnderTerr );  //V23[/b]
//-----------------------------------------------
(waterBlock.cc--->about line 947)
void WaterBlock::unpackUpdate( NetConnection* c, BitStream* stream )
{
   [i]//<<code not shown>>[/i]

    [b]stream->read( &mRenderUnderTerr );  //V23[/b]
//-----------------------------------------------
(waterBlock.h--->about line 91)
// Fields exposed to the editor.
    EWaterType          mLiquidType;            ///< Type of liquid: Water?  Lava?  What?
    F32                 mDensity;               ///< Density of liquid.
    F32                 mViscosity;             ///< Viscosity of liquid.
    F32                 mWaveMagnitude;         ///< Size of waves.
    StringTableEntry    mSurfaceName;           ///< Surface texture.
    F32                 mSurfaceOpacity;        ///< Opacity of surface texture.
    StringTableEntry    mEnvMapOverName;        ///< Overhead environment map texture name.
    StringTableEntry    mEnvMapUnderName;       ///< Undersea environment maptexture name
    F32                 mEnvMapIntensity;       ///< Intensity of environment maps.
    StringTableEntry    mShoreName;             ///< Shore texture name.
    StringTableEntry    mSubmergeName[WC_NUM_SUBMERGE_TEX]; ///< Name of submerge texture.
    bool                mRemoveWetEdges;        ///< Remove wet edges?
    [b]bool		            mRenderUnderTerr;       ///< V23 Under terrain rendering[/b]

//-----------------------------------------------
In the mission files the following waterBlock parameters may have to be manually added for existing missions or opened with the editor, changed, and saved:

renderUnderTerrain = "0"; //V23 above terrain, or
renderUnderTerrain = "1"; //V23 below terrain


Mission example:
new WaterBlock(bunkerWater01) {
      position = "-176 -344 51.4";
      rotation = "1 0 0 0";
      scale = "64 64 1";
      UseDepthMask = "0";
      surfaceTexture = "~/data/water/wash3";
      ShoreTexture = "~/data/water/wash3";
      envMapOverTexture = "~/data/skies/canyons_up";
      envMapUnderTexture = "~/data/terrains/sand";
      submergeTexture[0] = "~/data/terrains/sand";
      liquidType = "Lava";
      density = "8";
      viscosity = "9";
      waveMagnitude = "0.9";
      surfaceOpacity = "0.6";
      envMapIntensity = "0";
      TessSurface = "30";
      TessShore = "30";
      SurfaceParallax = "0.0001";
      FlowAngle = "0";
      FlowRate = "0";
      DistortGridScale = "0.1";
      DistortMag = "0.1";
      DistortTime = "9";
      ShoreDepth = "6";
      DepthGradient = "1.5";
      MinAlpha = "0.3";
      MaxAlpha = "0.6";
      removeWetEdges = "0";
      [b]renderUnderTerrain = "1";[/b]
   };

About the author

Recent Blogs


#1
10/22/2003 (3:30 pm)
This is useful! Hehe, thanks :)
#2
01/17/2005 (10:26 am)
Is this up to date? Syntax above different than syntax in current "fluid.h" file.

Above:
f32& EnvMapIntensity,                   bool RemoveWetEdges,  //V23                   bool RenderUnderTerr, //V23 Added for subterranean water render      bool UseDepthMap,

Current Fuild.h File:
f32& EnvMapIntensity,
                                  s32  RemoveWetEdges,
								  bool UseDepthMap,
#3
01/21/2005 (6:59 am)
Works like a charm on 1.3

Edit: Actually, there are problems with the player being falsely classified as underwater in other parts of the mission.
#4
06/14/2007 (10:03 am)
Nice fix. Still works for 1.5. Are there any big performance drops in relation to this, because i've just left out the switch part and i'm rendering all the water around the map regardless of whether its under the terrain or not.