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 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 }