Main Page | Namespace List | Class List | File List | Class Members | File Members

water.cpp

Go to the documentation of this file.
00001 #include <GL/gl.h>
00002 #include <assert.h>
00003 #include <math.h>
00004 #include <string.h>
00005 #include <stdio.h>
00006 #include <complex>
00007 
00008 #include "config.h"
00009 #include "water.h"
00010 //#include "envmap.h"
00011 
00012 using namespace std;
00013 
00014 
00015 
00016 // Water surface data
00017 typedef float normal[3];
00018 static float *g_hf = NULL;
00019 static normal *g_hf_normals = NULL;
00020 static float *g_hf_fc_re = NULL;
00021 static float *g_hf_fc_im = NULL;
00022 static int g_W = 0;
00023 static int g_H = 0;
00024 // Eye position
00025 static float g_xe, g_ye, g_ze;
00026 
00027 
00029 static inline float gethf( int x, int y ) {
00030   while (x<0) x += g_W;
00031   while (y<0) y += g_H;
00032   return g_hf[ (x%g_W) + (y%g_H)*g_W ];
00033 }
00034 
00035 static inline const normal& getnormal( int x, int y )
00036 {
00037   while (x<0) x += g_W;
00038   while (y<0) y += g_H;
00039   return g_hf_normals[ (x%g_W) + (y%g_H)*g_W ];
00040 }
00041 
00042 
00043 
00045 static inline void computeNormal( int x, int y, float &nx, float &ny, float &nz )
00046 {
00047   assert( x>=0 && x<g_W );
00048   assert( y>=0 && y<g_H );
00049 
00050   // Compute normal using forward/backward differences
00051   nx = 0.5f * (gethf( x+1,y ) - gethf( x-1,y )) / g_cellsize;
00052   ny = -1;
00053   nz = 0.5f * (gethf( x,y+1 ) - gethf( x,y-1 )) / g_cellsize;
00054   // Normalize
00055   float len = (float)sqrt( nx*nx + ny*ny + nz*nz );
00056   assert( len != 0 );
00057   nx /= len; ny /= len; nz /= len;
00058 }
00059  
00060 
00061 
00062 
00064 double gauss_rand()
00065 {
00066   int nSum = 0;
00067   for (unsigned i=0; i<100; i++) {
00068     nSum += (rand()%2);
00069   }
00070   return double(nSum-50) / 25.0;
00071 }
00072 
00073 
00074 // Wave field fourier coefficient
00075 complex<float> fourier( float x, float y )
00076 {
00077   const float windx = 1.0;
00078   const float windy = 0.8;
00079   const float gravity = 9.81;
00080   float wind_speed2 = windx*windx + windy*windy;
00081 
00082   float k2 = x*x + y*y;;
00083   float f1 = exp( -0.5*gravity*gravity / (k2 * wind_speed2 * wind_speed2)  );
00084   float f2 = abs(x*windx + y*windy) / k2;
00085   float phillips = f1*f2;
00086 
00087   return float(1.0 / sqrt(2.0)) * complex<float>( gauss_rand(), gauss_rand() ) * phillips;
00088 }
00089 
00090 
00091 
00093 void initWater( int W, int H )
00094 {
00095   // Validate params
00096   assert( W>0 && W*H > 0 );
00097   // Clear old data
00098   delete[] g_hf;
00099   delete[] g_hf_normals;
00100   delete[] g_hf_fc_re;
00101   delete[] g_hf_fc_im;
00102 
00103   // Init new data
00104   g_W = W;
00105   g_H = H;
00106   g_hf = new float[W*H];
00107   g_hf_normals = new normal[W*H];
00108   g_hf_fc_re = new float[W*H];
00109   g_hf_fc_im = new float[W*H];
00110 
00111   for (int x=0; x<g_W; x++) {
00112     for (int y=0; y<g_H; y++) {
00113       complex<float> fc = fourier( x,y );
00114       g_hf_fc_re[x+y*g_W] = real(fc);
00115       g_hf_fc_im[x+y*g_W] = imag(fc);
00116     }
00117   }
00118   g_hf_fc_re[0] = 0;
00119   g_hf_fc_im[0] = 0;
00120 
00121   computeWater( 0.0f );
00122 }
00123 
00125 float computeHeight( int x, int y, float t )
00126 {
00127   float tOff = t*0.1f;
00128   float re = 0.0f;
00129 
00130   const int N = 8;
00131   for (int xc=1; xc<N; xc++) {
00132     for (int yc=1; yc<N; yc++) {
00133       float xp = x/float(g_W);
00134       float yp = y/float(g_H);
00135       float p = 2*M_PI* (xc*(xp+tOff) + yc*(yp+tOff));
00136       int i = xc + yc*g_W;
00137       re += g_hf_fc_re[i]*cos(p) - g_hf_fc_im[i]*sin(p);
00138     }
00139   }
00140   return g_fWaterScale * re / N*N;
00141 }
00142 
00144 
00145 void computeWater( float fTime )
00146 {
00147   // Compute eye position
00148   g_xe = g_CameraX; // cos( g_fCameraX*M_PI/180.0f ) * g_fViewDistance;
00149   g_ze = g_CameraZ; //sin( g_fCameraX*M_PI/180.0f ) * g_fViewDistance;
00150   g_ye = g_CameraY;//cos( g_fCameraY*M_PI/180.0f ) * g_fViewDistance;
00151 
00152   // Init height field
00153   float *p = g_hf;
00154   for (int y=0; y<g_H; y++) {
00155     for (int x=0; x<g_W; x++) {
00156       *p = computeHeight( x,y, fTime );
00157       p++;
00158     }
00159   }
00160 
00161   // Init normals
00162   normal *pN = g_hf_normals;
00163   for (int y=0; y<g_H; y++) {
00164     for (int x=0; x<g_W; x++) {
00165       computeNormal( x,y, (*pN)[0], (*pN)[1], (*pN)[2] );
00166       pN++;
00167     }
00168   }
00169 }
00170 
00171 
00172 // Compute the fresnel term from the angle between eye direction and the normal
00173 inline float fresnelTerm( float a )
00174 {
00175   // Compute angle between normal and incoming ray
00176   float b = 1.0f / (1.0f+a);
00177   return b*b;
00178 }
00179 
00180 // Stream a vertex to the GL
00181 inline void streamVertex( int x, int y, float xp, float yp, float zoff )
00182 {
00183   // Get normal
00184   const normal& n = getnormal( x,y );
00185   // Compute color and fresnel term
00186   float col[4];
00187 /*  if (g_bSkymap) {
00188     col[0] = 0.6;//colorSky[0]; 
00189     col[1] = 0.6;//colorSky[1]; 
00190     col[2] = 0.8;//colorSky[2];
00191   }
00192   else {*/
00193 if (day)
00194     {
00195     col[0] = colorSky[0];//White[0]; 
00196     col[1] = colorSky[1]; 
00197     col[2] = colorSky[2]; 
00198     }
00199 else
00200     {
00201     col[0] = colorWaterGreen[0];//White[0]; 
00202     col[1] = colorWaterGreen[1]; 
00203     col[2] = colorWaterGreen[2]; 
00204     }
00205 
00206   float zp = zoff + gethf(x,y);
00207 
00208   float ex = g_xe-xp; float ez = g_ye-yp; float ey = g_ze-zp;
00209   float l = sqrt( ex*ex + ey*ey + ez*ez );
00210   ex /= l; ey /= l; ez /= l;
00211   float a = ex*n[0] + ey*n[1] + ez*n[2];
00212   if (g_bFresnel) {
00213     col[3] = fresnelTerm( a );
00214   }
00215   else {
00216     col[3] = 0.5f;
00217   }
00218 
00219   // Compute the reflected ray and use as texture coord for
00220   // the sky map.
00221     float rx = -ex + 2*a*n[0];
00222     float ry = -ey + 2*a*n[1];
00223     float rz = -ez + 2*a*n[2];
00224     glTexCoord3f( rx,ry,rz );
00225 
00226   glColor4fv( col );
00227   glNormal3fv( n );
00228   glVertex3f( xp, zp, yp );
00229 }
00230 
00231 
00232 // Draw a quad with multiple textures (via multipass rendering)
00233 void drawWaterQuad( int x, int y, float xp, float yp )
00234 {
00235   // Compute water surface base z coord
00236   float zOff = g_waterlevel * g_fHeightScale;
00237   streamVertex( x  ,y+1, xp           , yp+g_cellsize,zOff );
00238   streamVertex( x+1,y+1, xp+g_cellsize, yp+g_cellsize,zOff );
00239   streamVertex( x+1,y  , xp+g_cellsize, yp           ,zOff );
00240   streamVertex( x  ,y  , xp           , yp           ,zOff );
00241 }
00242 
00243 
00244 void drawWaterQuads( const vector<_S_WaterQuad> &water )
00245 {
00246   /*if (g_bSkymap) {
00247     // Setup sky map as reflection texture
00248     glBindTexture( GL_TEXTURE_CUBE_MAP, cubeMap() );
00249     glEnable( GL_TEXTURE_CUBE_MAP );
00250     
00251     // Texture environment: MODULATE RGB, REPLACE ALPHA
00252     // Set up texture function for RGB and alpha channel
00253     glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
00254     glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE );
00255     glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE );
00256     // Multiply the RGB components of the texture and the primary color
00257     glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT );
00258     glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR );
00259     glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE );
00260     glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR );
00261     // Replace the alpha component
00262     glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PREVIOUS_EXT );
00263     glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA );
00264   }
00265 */
00266   // Enable blending
00267   glEnable( GL_BLEND );
00268 
00269   // Render surface
00270   vector<_S_WaterQuad>::const_iterator it = water.begin();
00271   glBegin( GL_QUADS );
00272   while ( it != water.end() ) {
00273     drawWaterQuad( (*it).x, (*it).y, (*it).xp, (*it).yp );
00274     it++;
00275   }
00276   glEnd();
00277 
00278   // Reset old GL State
00279   glDisable( GL_BLEND );
00280   glDisable( GL_TEXTURE_CUBE_MAP );
00281 }

Generated on Thu Jan 20 02:46:58 2005 for Main_Demo by doxygen 1.3.6