uniform bool osgOcean_EnableReflections; uniform bool osgOcean_EnableRefractions; uniform bool osgOcean_EnableHeightmap; uniform bool osgOcean_EnableCrestFoam; uniform bool osgOcean_EnableUnderwaterScattering; uniform bool osgOcean_EnableDOF; uniform bool osgOcean_EnableGlare; uniform float osgOcean_DOF_Near; uniform float osgOcean_DOF_Focus; uniform float osgOcean_DOF_Far; uniform float osgOcean_DOF_Clamp; uniform float osgOcean_FresnelMul; uniform samplerCube osgOcean_EnvironmentMap; uniform sampler2D osgOcean_ReflectionMap; uniform sampler2D osgOcean_RefractionMap; uniform sampler2D osgOcean_RefractionDepthMap; uniform sampler2D osgOcean_FoamMap; uniform sampler2D osgOcean_NoiseMap; uniform sampler2D osgOcean_Heightmap; uniform float osgOcean_UnderwaterFogDensity; uniform float osgOcean_AboveWaterFogDensity; uniform vec4 osgOcean_UnderwaterFogColor; uniform vec4 osgOcean_AboveWaterFogColor; uniform vec3 osgOcean_UnderwaterAttenuation; uniform vec4 osgOcean_UnderwaterDiffuse; uniform mat4 osg_ViewMatrixInverse; uniform mat4 osgOcean_RefractionInverseTransformation; uniform vec2 osgOcean_ViewportDimensions; uniform float osgOcean_WaterHeight; uniform float osgOcean_FoamCapBottom; uniform float osgOcean_FoamCapTop; varying vec3 vNormal; varying vec3 vViewerDir; varying vec3 vLightDir; varying vec4 vVertex; varying vec4 vWorldVertex; varying vec3 vExtinction; varying vec3 vInScattering; varying vec3 vWorldViewDir; varying vec3 vWorldNormal; varying float height; mat4 worldObjectMatrix; const float shininess = 2000.0; const vec4 BlueEnvColor = vec4(0.75, 0.85, 1.0, 1.0); vec4 distortGen( vec4 v, vec3 N ) { // transposed const mat4 mr = mat4( 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.5, 0.5, 1.0 ); mat4 texgen_matrix = mr * gl_ProjectionMatrix * gl_ModelViewMatrix; //float disp = 8.0; float disp = 4.0; vec4 tempPos; tempPos.xy = v.xy + disp * N.xy; tempPos.z = v.z; tempPos.w = 1.0; return texgen_matrix * tempPos; } vec3 reorientate( vec3 v ) { float y = v.y; v.y = -v.z; v.z = y; return v; } mat3 getLinearPart( mat4 m ) { mat3 result; result[0][0] = m[0][0]; result[0][1] = m[0][1]; result[0][2] = m[0][2]; result[1][0] = m[1][0]; result[1][1] = m[1][1]; result[1][2] = m[1][2]; result[2][0] = m[2][0]; result[2][1] = m[2][1]; result[2][2] = m[2][2]; return result; } float calcFresnel( float dotEN, float mul ) { float fresnel = clamp( dotEN, 0.0, 1.0 ) + 1.0; return pow(fresnel, -8.0) * mul; } float alphaHeight( float min, float max, float val) { if(max-min == 0.0) return 1.0; return (val - min) / (max - min); } float computeDepthBlur(float depth, float focus, float near, float far, float clampval ) { float f; if (depth < focus){ // scale depth value between near blur distance and focal distance to [-1, 0] range f = (depth - focus)/(focus - near); } else{ // scale depth value between focal distance and far blur // distance to [0, 1] range f = (depth - focus)/(far - focus); // clamp the far blur to a maximum blurriness f = clamp(f, 0.0, clampval); } // scale and bias into [0, 1] range return f * 0.5 + 0.5; } float luminance( vec4 color ) { return (0.3*color.r) + (0.59*color.g) + (0.11*color.b); } float computeFogFactor( float density, float fogCoord ) { return exp2(density * fogCoord * fogCoord ); } // ------------------------------- // Main Program // ------------------------------- void main( void ) { vec4 final_color; vec3 noiseNormal = vec3( texture2D( osgOcean_NoiseMap, gl_TexCoord[0].xy ) * 2.0 - 1.0 ); noiseNormal += vec3( texture2D( osgOcean_NoiseMap, gl_TexCoord[0].zw ) * 2.0 - 1.0 ); worldObjectMatrix = osg_ViewMatrixInverse * gl_ModelViewMatrix; if(gl_FrontFacing) { vec3 N = normalize( vNormal + noiseNormal ); vec3 L = normalize( vLightDir ); vec3 E = normalize( vViewerDir ); vec3 R = reflect( -L, N ); vec4 specular_color = vec4(0.0); float lambertTerm = dot(N,L); if( lambertTerm > 0.0 ) { float specCoeff = pow( max( dot(R, E), 0.0 ), shininess ); specular_color = gl_LightSource[osgOcean_LightID].diffuse * specCoeff * 6.0; } float dotEN = dot(E, N); float dotLN = dot(L, N); vec4 distortedVertex = distortGen(vVertex, N); // Calculate the position in world space of the pixel on the ocean floor vec4 refraction_ndc = vec4(gl_FragCoord.xy / osgOcean_ViewportDimensions, texture2DProj(osgOcean_RefractionDepthMap, distortedVertex).x, 1.0); vec4 refraction_screen = refraction_ndc * 2.0 - 1.0; vec4 refraction_world = osgOcean_RefractionInverseTransformation * refraction_screen; refraction_world = refraction_world / refraction_world.w; // The amount of water behind the pixel // (water depth as seen from the camera position) float waterDepth = distance(vWorldVertex, refraction_world); vec4 refraction_dir = refraction_world - vWorldVertex; vec4 env_color; if(osgOcean_EnableReflections) { env_color = texture2DProj( osgOcean_ReflectionMap, distortedVertex ); } else { env_color = BlueEnvColor * gl_LightSource[osgOcean_LightID].diffuse * vec4(vec3(1.25), 1.0); } // Determine refraction color vec4 refraction_color = vec4( gl_Color.rgb, 1.0 ); // Only use refraction for under the ocean surface. if(osgOcean_EnableRefractions) { vec4 refractionmap_color = texture2DProj(osgOcean_RefractionMap, distortedVertex ); if(osgOcean_EnableUnderwaterScattering) { // Compute underwater scattering the same way as when underwater, // see vertex shader computeScattering() function, but a higher // underwater attenuation factor is required so it matches the // underwater look. float depth = max(osgOcean_WaterHeight-vWorldVertex.z, 0.0); vec3 extinction = exp(-osgOcean_UnderwaterAttenuation*waterDepth*4.0); vec3 inScattering = osgOcean_UnderwaterDiffuse.rgb * vec3(0.6, 0.6, 0.5) * (1.0-extinction*exp(-depth*vec3(0.001))); refraction_color.rgb = refractionmap_color.rgb * extinction + inScattering; } else { refraction_color.rgb *= refractionmap_color.rgb; } } float fresnel = calcFresnel(dotEN, osgOcean_FresnelMul ); final_color = mix(refraction_color, env_color, fresnel) + specular_color; // Store the color here to compute luminance later, we don't want // foam or fog to be taken into account for this calculation. vec4 lumColor = final_color; float waterHeight = 0.0; if (osgOcean_EnableHeightmap) { // The vertical distance between the ocean surface and ocean floor, this uses the projected heightmap waterHeight = (texture2DProj(osgOcean_Heightmap, distortedVertex).x) * 500.0; } if(osgOcean_EnableCrestFoam) { if( vVertex.z > osgOcean_FoamCapBottom || (osgOcean_EnableHeightmap && waterHeight < 10.0)) { vec4 foam_color = texture2D( osgOcean_FoamMap, gl_TexCoord[1].st / 10.0); float alpha; if (osgOcean_EnableHeightmap) { alpha = max(alphaHeight( osgOcean_FoamCapBottom, osgOcean_FoamCapTop, vVertex.z ) * (fresnel*2.0), 0.8 - clamp(waterHeight / 10.0, 0.0, 0.8)); } else { alpha = alphaHeight( osgOcean_FoamCapBottom, osgOcean_FoamCapTop, vVertex.z ) * (fresnel*2.0); } final_color = final_color + (foam_color * alpha); } } // exp2 fog float fogFactor = computeFogFactor( osgOcean_AboveWaterFogDensity, gl_FogFragCoord ); final_color = mix( osgOcean_AboveWaterFogColor, final_color, fogFactor ); if(osgOcean_EnableGlare) { float lum = luminance(lumColor); gl_FragData[1] = vec4(lum); } gl_FragData[0] = final_color; } else { vec3 E = normalize( vViewerDir ); vec3 N = -normalize( (vWorldNormal + noiseNormal) ); vec3 incident = normalize( vWorldViewDir ); //------ Find the reflection // not really usable as we would need to use cubemap again.. // the ocean is blue not much to reflect back //vec3 reflected = reflect( incident, -N ); //reflected = reorientate( reflected ); //vec3 reflVec = normalize( reflected ); //------ Find the refraction from cubemap vec3 refracted = refract( incident, N, 1.3333333333 ); // 1.1 looks better? - messes up position of godrays though refracted.z = refracted.z - 0.015; // on the fringes push it down to show base texture color refracted = reorientate( refracted ); vec4 refractColor = textureCube( osgOcean_EnvironmentMap, refracted ); //------ Project texture where the light isn't internally reflected if(osgOcean_EnableRefractions) { // if alpha is 1.0 then it's a sky pixel if(refractColor.a == 1.0 ) { vec4 env_color = texture2DProj( osgOcean_RefractionMap, distortGen(vVertex, N) ); refractColor.rgb = mix( refractColor.rgb, env_color.rgb, env_color.a ); } } // if it's not refracting in, add a bit of highlighting with fresnel if( refractColor.a == 0.0 ) { float fresnel = calcFresnel( dot(E, N), 0.7 ); refractColor.rgb = osgOcean_UnderwaterFogColor.rgb*fresnel + (1.0-fresnel)* refractColor.rgb; } // mix in underwater light if(osgOcean_EnableUnderwaterScattering) { refractColor.rgb = refractColor.rgb * vExtinction + vInScattering; } float fogFactor = computeFogFactor( osgOcean_UnderwaterFogDensity, gl_FogFragCoord ); final_color = mix( osgOcean_UnderwaterFogColor, refractColor, fogFactor ); if(osgOcean_EnableDOF) { float depthBlur = computeDepthBlur( gl_FogFragCoord, osgOcean_DOF_Focus, osgOcean_DOF_Near, osgOcean_DOF_Far, osgOcean_DOF_Clamp ); gl_FragData[1] = vec4(depthBlur); } gl_FragData[0] = final_color; } }