Waterflow
Visualize water in terrain
|
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 void main(void) 00105 { 00106 // eye vector is calculated. 00107 eye = normalize(camPos - out_ObjPos); 00108 00109 // Get the normal 00110 Normal = normalize(out_Normal); 00111 00112 // Incident and reflected light is calculated for the light source. 00113 s = normalize(lights[0].pos - (1 - lights[0].isDir) * out_ObjPos); 00114 r = normalize(2 * Normal * dot(s, Normal) - s); 00115 00116 right = cross(Normal, eye); 00117 // Snell's law 00118 // Since asin is not that cheap, approximations could be made here. 00119 theta1 = asin(length(right)); 00120 theta2 = asin(airRefInd * sin(theta1) / waterRefInd); 00121 00122 // Texture lookup at fragment. 00123 terrainDataUnderSurface = texture(height_texUnit, out_TexCoord); 00124 00125 // Depth at fragment. 00126 depth = out_ObjPos.y - size.y * terrainDataUnderSurface.a; 00127 00128 if (depth < 0 || out_ObjPos.z < 1 || out_ObjPos.x < 1 ) 00129 { 00130 discard; 00131 } 00132 00133 // To find the fragment at the bottom corresponding to what would be seen after refraction 00134 // at the water surface, a crude displacement approximation in the xz-plane from the surface 00135 // fragment to the approximated fragment at the bottom is calculated. 00136 vec3 s2 = airRefInd / waterRefInd * cross(Normal, cross(Normal, eye)) - Normal * sqrt(1 - pow(airRefInd / waterRefInd, 2) * dot(cross(Normal, eye), cross(Normal, eye))); 00137 displacementDirection = normalize(s2 - dot(s2, -up) * -up); 00138 bottomDisplacement1 = tan(theta2) * depth; 00139 displacement1 = bottomDisplacement1 * displacementDirection; 00140 00141 // Texture lookup at approximation. 00142 terrainDataAtDis1 = texture(height_texUnit, out_TexCoord + vec2(displacement1.x / size.x, displacement1.z / size.z)); 00143 00144 // "Depth" at approximation. 00145 depthAtDis1 = out_ObjPos.y - size.y * terrainDataAtDis1.a; 00146 // Height at approximation (y distance from fragment bottom to approximation bottom). 00147 h = depth - depthAtDis1; 00148 // To minimize visual errors caused by irregular terrain, a better approximation is made. 00149 alpha = abs(atan(h / bottomDisplacement1)); 00150 bottomDisplacement2 = cos(alpha) * depth * sin(theta2) / cos(alpha - theta2); 00151 displacement2 = bottomDisplacement2 * displacementDirection; 00152 00153 // Texture lookups at better approximation. 00154 terrainDataAtBottom = texture(height_texUnit, out_TexCoord + vec2(displacement2.x / size.x, displacement2.z / size.z)); 00155 texDataAtBottom = texture(terr_texUnit, out_TexCoord + vec2(displacement2.x / size.x, displacement2.z / size.z)); 00156 // "Depth" at better approximation. 00157 depthAtDis2 = out_ObjPos.y - size.y * terrainDataAtBottom.a; 00158 00159 // Coordinates and normal of seen position of bottom. 00160 bottomPos = out_ObjPos + displacement2 - vec3(0, depthAtDis2, 0); 00161 bottomNormal = normalize(terrainDataAtBottom.rgb); 00162 00163 // Distance from surface to seen position of bottom. 00164 wdist = length(bottomPos - out_ObjPos); 00165 00166 // Skybox reflection. 00167 // Reflected eye vector. 00168 re = 2 * dot(eye, Normal) * Normal - eye; 00169 skyrefl = texture(sky_texUnit, re).rgb; 00170 // Light components, water surface. 00171 kamb = 0.1; 00172 krefl = clamp((1 - eye.y), 0.2, 0.7); 00173 // Ambient light. 00174 ambLight = kamb * vec3(1.0, 1.0, 1.0); 00175 reflLight = vec3(0.0, 0.0, 0.0); 00176 // Reflected light. 00177 reflLight += krefl * skyrefl; 00178 00179 surfaceLight = vec3(0.0, 0.0, 0.0); 00180 // The light components are added to the total surface light. 00181 surfaceLight += ambLight; 00182 surfaceLight += reflLight; 00183 00184 ktransr = clamp((1 - reflLight.r) * pow((1 + wdist), -1.8 * transparency), 0.0, 0.5); 00185 ktransg = clamp((1 - reflLight.g) * pow((1 + wdist), -1.7 * transparency), 0.0, 0.5); 00186 ktransb = clamp((1 - reflLight.b) * pow((1 + wdist), -1.5 * transparency), 0.0, 0.5); 00187 kblue = 1 - eye.y; 00188 00189 // Calculating bottom light. 00190 // Phong shading for the bottom. 00191 s = normalize(lights[1].pos - (1 - lights[1].isDir) * bottomPos); 00192 r = normalize(2 * bottomNormal * dot(s, bottomNormal) - s); 00193 00194 // eye vector is calculated (note: from bottom to surface, not to camera). 00195 eye = normalize(out_ObjPos - bottomPos); 00196 00197 // Light according to the Phong model. 00198 kamb = 0.1; 00199 kdiff = 0.5; 00200 krefl = 0.5; 00201 ambLight = kamb * vec3(1.0, 1.0, 1.0); 00202 diffLight = vec3(0.0, 0.0, 0.0); 00203 specLight = vec3(0.0, 0.0, 0.0); 00204 // Diffuse light. 00205 diffLight += kdiff * lights[1].color * max(0.0, dot(s, bottomNormal)); 00206 // Specular light. 00207 specLight += krefl * lights[1].color * max(0.0, pow(dot(r, eye), lights[1].specExp)); 00208 00209 bottomLight = vec3(0.0, 0.0, 0.0); 00210 // The light components are added to the total bottom light. 00211 bottomLight += ambLight; 00212 bottomLight += diffLight; 00213 bottomLight += specLight; 00214 00215 bottomLight *= texDataAtBottom.rgb; 00216 //Color dependant attenuation. 00217 bottomLight = vec3(bottomLight.r * ktransr, bottomLight.g * ktransg, bottomLight.b * ktransb); 00218 00219 if (out_ObjPos.y > 35.0f || out_ObjPos.y < 0.000000005f) { 00220 vec3 brown = vec3(250, 184,173); 00221 brown = 0.3*normalize(brown); 00222 out_Color = vec4(brown,1); 00223 } 00224 else{ 00225 out_Color = vec4(bottomLight + surfaceLight, 1.0); 00226 } 00227 }