Waterflow
Visualize water in terrain
src/shaders/watershader.frag
Go to the documentation of this file.
00001 
00002 
00003 
00004 #version 430
00005 
00006 // ===== Uniform Buffers =====
00007 
00013 struct LightParam {
00014     vec3 pos;       
00015     float isDir;    
00016     vec3 color;     
00017     float specExp;  
00018 };
00019 
00020 layout(std140, binding = 0) uniform LightInfo 
00021 {
00022     LightParam lights[2];
00023 };
00024 
00025 
00026 // ===== Uniforms =====
00027 
00028 uniform vec3 camPos;                
00029 uniform vec3 size;                  
00030 uniform float time;                 
00031 uniform float transparency;         
00032 uniform sampler2D terr_texUnit;     
00033 uniform sampler2D height_texUnit;   
00034 uniform samplerCube sky_texUnit;    
00035 
00036 
00037 // ===== In/Out params =====
00038 
00039 in vec3 out_Normal;                 
00040 in vec2 out_TexCoord;               
00041 in vec3 out_ObjPos;                 
00042 
00043 out vec4 out_Color;                 
00044 
00045 
00046 // ===== Variables needed =====
00047 
00048 // Light vectors
00049 vec3 r;                             
00050 vec3 s;                             
00051 vec3 eye;                           
00052 vec3 Normal;                        
00053 vec3 re;                            
00054 vec3 right;                         
00055 
00056 // Lighting (the Phong model with extras).
00057 float kamb;                         
00058 float kdiff;                        
00059 float ktransr;                      
00060 float ktransg;                      
00061 float ktransb;                      
00062 float krefl;                        
00063 float kblue;                        
00064 
00065 vec3 ambLight;                      
00066 vec3 diffLight;                     
00067 vec3 specLight;                     
00068 vec3 reflLight;                     
00069 vec3 surfaceLight;                  
00070 vec3 bottomLight;                   
00071 
00072 // Snell's law angles.
00073 float theta1;                       
00074 float theta2;                       
00075 
00076 // Underwater triangulation components.
00077 float depth;                        
00078 vec3 displacementDirection;         
00079 float bottomDisplacement1;          
00080 vec3 displacement1;                 
00081 float depthAtDis1;                  
00082 float h;                            
00083 float alpha;                        
00084 float bottomDisplacement2;          
00085 vec3 displacement2;                 
00086 float depthAtDis2;                  
00087 float wdist;                        
00088 
00089 vec3 bottomPos;                     
00090 vec3 bottomNormal;                  
00091 
00092 // Texture lookups.
00093 vec4 terrainDataUnderSurface;       
00094 vec4 terrainDataAtDis1;             
00095 vec4 terrainDataAtBottom;           
00096 vec4 texDataAtBottom;               
00097 vec3 skyrefl;                       
00098 
00099 // Constants
00100 const float waterRefInd = 1.34451;  
00101 const float airRefInd = 1.0;        
00102 const vec3 up = vec3(0.0, 1.0, 0.0);
00103 
00104 
00105 void main(void)
00106 {
00107     // eye vector is calculated.
00108     eye = normalize(camPos - out_ObjPos);
00109         
00110     // Modelling surface waves.
00111     float rho1 = sqrt(pow(out_ObjPos.x, 2) + pow(out_ObjPos.z, 2));
00112     float rho2 = sqrt(pow((size.x - float(out_ObjPos.x)), 2) + pow(out_ObjPos.z, 2));
00113     float xwave = sin(0.1 * time + out_ObjPos.x) + sin(-0.01 * time + out_ObjPos.x);
00114     float ywave = sin(0.2 * time + out_ObjPos.z) + sin(-0.3 * time + out_ObjPos.z);
00115     float rhowave1 = sin(0.05 * time + 0.5 + rho1) + 0.2 * sin(-0.01 * time + rho1);
00116     float rhowave2 = sin(-0.05 * time + 0.5 + rho2/10.0f) + 0.2 * sin(-0.01 * time + rho2 / 10.0f);
00117     float rand = 1;
00118     rand = fract(sin(dot(vec2(out_ObjPos.x + time, out_ObjPos.z), vec2(12.9898, 78.233))) * 43758.5453);
00119 
00120     // Perturbing surface normals.
00121     Normal = vec3(0.1 * (0.1 * xwave + 0.1 * rhowave1 + rhowave2), out_Normal.y, 0.1 * 0.1 * ywave);
00122     Normal = normalize(0.5 * out_Normal + 0.5 * Normal);
00123 
00124     // Incident and reflected light is calculated for the light source.
00125     s = normalize(lights[0].pos - (1 - lights[0].isDir) * out_ObjPos);
00126     r = normalize(2 * Normal * dot(s, Normal) - s);
00127 
00128     right = cross(Normal, eye);
00129     // Snell's law
00130     // Since asin is not that cheap, approximations could be made here.
00131     theta1 = asin(length(right));
00132     theta2 = asin(airRefInd * sin(theta1) / waterRefInd);
00133 
00134     // Texture lookup at fragment.
00135     terrainDataUnderSurface = texture(height_texUnit, out_TexCoord);
00136 
00137     // Depth at fragment.
00138     depth = out_ObjPos.y - size.y * terrainDataUnderSurface.a;
00139     
00140     if (depth < 0 || out_ObjPos.z < 1 || out_ObjPos.x < 1 )
00141     {
00142         discard;
00143     }
00144 
00145     // To find the fragment at the bottom corresponding to what would be seen after refraction
00146     // at the water surface, a crude displacement approximation in the xz-plane from the surface
00147     // fragment to the approximated fragment at the bottom is calculated.
00148     vec3 s2 = airRefInd / waterRefInd * cross(Normal, cross(Normal, eye)) - Normal * sqrt(1 - pow(airRefInd / waterRefInd, 2) * dot(cross(Normal, eye), cross(Normal, eye)));
00149     displacementDirection = normalize(s2 - dot(s2, -up) * -up);
00150     bottomDisplacement1 = tan(theta2) * depth;
00151     displacement1 = bottomDisplacement1 * displacementDirection;
00152 
00153     // Texture lookup at approximation.
00154     terrainDataAtDis1 = texture(height_texUnit, out_TexCoord + vec2(displacement1.x / size.x, displacement1.z / size.z));
00155 
00156     // "Depth" at approximation.
00157     depthAtDis1 = out_ObjPos.y - size.y * terrainDataAtDis1.a;
00158     // Height at approximation (y distance from fragment bottom to approximation bottom).
00159     h = depth - depthAtDis1;
00160     // To minimize visual errors caused by irregular terrain, a better approximation is made.
00161     alpha = abs(atan(h / bottomDisplacement1));
00162     bottomDisplacement2 = cos(alpha) * depth * sin(theta2) / cos(alpha - theta2);
00163     displacement2 = bottomDisplacement2 * displacementDirection;
00164 
00165     // Texture lookups at better approximation.
00166     terrainDataAtBottom = texture(height_texUnit, out_TexCoord + vec2(displacement2.x / size.x, displacement2.z / size.z));
00167     texDataAtBottom = texture(terr_texUnit, out_TexCoord + vec2(displacement2.x / size.x, displacement2.z / size.z));
00168     // "Depth" at better approximation.
00169     depthAtDis2 = out_ObjPos.y - size.y * terrainDataAtBottom.a;
00170 
00171     // Coordinates and normal of seen position of bottom.
00172     bottomPos = out_ObjPos + displacement2 - vec3(0, depthAtDis2, 0);
00173     bottomNormal = normalize(terrainDataAtBottom.rgb);
00174 
00175     // Distance from surface to seen position of bottom.
00176     wdist = length(bottomPos - out_ObjPos);
00177     
00178     // Skybox reflection.
00179     // Reflected eye vector.
00180     re = 2 * dot(eye, Normal) * Normal - eye;
00181     skyrefl = texture(sky_texUnit, re).rgb;
00182     // Light components, water surface.
00183     kamb = 0.1;
00184     krefl = clamp((1 - eye.y), 0.2, 0.7);
00185     // Ambient light.
00186     ambLight = kamb * vec3(1.0, 1.0, 1.0);
00187     reflLight = vec3(0.0, 0.0, 0.0);
00188     // Reflected light.
00189     reflLight += krefl * skyrefl;
00190     
00191     surfaceLight = vec3(0.0, 0.0, 0.0);
00192     // The light components are added to the total surface light.
00193     surfaceLight += ambLight;
00194     surfaceLight += reflLight;
00195 
00196     ktransr = clamp((1 - reflLight.r) * pow((1 + wdist), -1.8 * transparency), 0.0, 0.5);
00197     ktransg = clamp((1 - reflLight.g) * pow((1 + wdist), -1.7 * transparency), 0.0, 0.5);
00198     ktransb = clamp((1 - reflLight.b) * pow((1 + wdist), -1.5 * transparency), 0.0, 0.5);
00199     kblue = 1 - eye.y;
00200 
00201     // Calculating bottom light.
00202     // Phong shading for the bottom.
00203     s = normalize(lights[1].pos - (1 - lights[1].isDir) * bottomPos);
00204     r = normalize(2 * bottomNormal * dot(s, bottomNormal) - s);
00205 
00206     // eye vector is calculated (note: from bottom to surface, not to camera).
00207     eye = normalize(out_ObjPos - bottomPos);
00208 
00209     // Light according to the Phong model.
00210     kamb = 0.1;
00211     kdiff = 0.5;
00212     krefl = 0.5;
00213     ambLight = kamb * vec3(1.0, 1.0, 1.0);
00214     diffLight = vec3(0.0, 0.0, 0.0);
00215     specLight = vec3(0.0, 0.0, 0.0);
00216     // Diffuse light.
00217     diffLight += kdiff * lights[1].color * max(0.0, dot(s, bottomNormal));
00218     // Specular light.
00219     specLight += krefl * lights[1].color * max(0.0, pow(dot(r, eye), lights[1].specExp));
00220 
00221     bottomLight = vec3(0.0, 0.0, 0.0);
00222     // The light components are added to the total bottom light.
00223     bottomLight += ambLight;
00224     bottomLight += diffLight;
00225     bottomLight += specLight;
00226     
00227     bottomLight *= texDataAtBottom.rgb;
00228     //Color dependant attenuation.
00229     bottomLight = vec3(bottomLight.r * ktransr, bottomLight.g * ktransg, bottomLight.b * ktransb);
00230     
00231     out_Color = vec4(bottomLight + surfaceLight, 1.0);
00232 }
 All Classes Files Functions Variables Enumerations