351 lines
11 KiB
GLSL
351 lines
11 KiB
GLSL
|
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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|