diff --git a/Effects/stars.eff b/Effects/stars.eff index 648f3dbd9..e6e950016 100644 --- a/Effects/stars.eff +++ b/Effects/stars.eff @@ -4,7 +4,7 @@ <name>Effects/stars</name> <parameters> - <max-radiance type="float">2.0</max-radiance> + <max-radiance type="float">50.0</max-radiance> </parameters> <!-- Fixed-pipeline fallback --> @@ -20,6 +20,7 @@ <technique n="129"> <scheme>hdr-forward</scheme> <pass> + <!-- Disable depth testing --> <depth> <enabled>false</enabled> </depth> @@ -28,21 +29,44 @@ <function>equal</function> <value>0</value> </stencil> + <!-- Make sure we render after the skydome --> + <render-bin> + <bin-number>-9</bin-number> + <bin-name>RenderBin</bin-name> + </render-bin> <cull-face>off</cull-face> + <!-- Additive blending to add the sky in-scattering from the skydome --> <blend> <active>true</active> - <source>src-alpha</source> - <destination>one-minus-src-alpha</destination> + <source>one</source> + <destination>one</destination> </blend> <program> <vertex-shader>Shaders/HDR/stars.vert</vertex-shader> <fragment-shader>Shaders/HDR/stars.frag</fragment-shader> + <fragment-shader>Shaders/HDR/exposure.glsl</fragment-shader> </program> <uniform> <name>max_radiance</name> <type>float</type> <value><use>max-radiance</use></value> </uniform> + <uniform> + <name>transmittance_tex</name> + <type>sampler-2d</type> + <value type="int">12</value> + </uniform> + <!-- exposure.glsl --> + <uniform> + <name>lum_tex</name> + <type>sampler-2d</type> + <value type="int">14</value> + </uniform> + <uniform> + <name>exposure_compensation</name> + <type>float</type> + <value><use>exposure-compensation</use></value> + </uniform> </pass> </technique> </PropertyList> diff --git a/Shaders/HDR/stars.frag b/Shaders/HDR/stars.frag index ff56fb78b..ed0130ccc 100644 --- a/Shaders/HDR/stars.frag +++ b/Shaders/HDR/stars.frag @@ -4,11 +4,49 @@ layout(location = 0) out vec4 fragColor; in VS_OUT { vec4 color; + vec3 view_vector; } fs_in; +uniform sampler2D transmittance_tex; + uniform float max_radiance; +uniform float fg_CameraDistanceToEarthCenter; +uniform float fg_EarthRadius; +uniform vec3 fg_CameraViewUp; + +const float ATMOSPHERE_RADIUS = 6471e3; + +// exposure.glsl +vec3 apply_exposure(vec3 color); + void main() { - fragColor = vec4(fs_in.color.rgb * max_radiance, fs_in.color.a); + vec3 color = fs_in.color.rgb * fs_in.color.a * max_radiance; + + vec3 V = normalize(fs_in.view_vector); + + // Apply aerial perspective + float normalized_altitude = + (fg_CameraDistanceToEarthCenter - fg_EarthRadius) + / (ATMOSPHERE_RADIUS - fg_EarthRadius); + float cos_theta = dot(-V, fg_CameraViewUp); + + vec2 uv = vec2(cos_theta * 0.5 + 0.5, clamp(normalized_altitude, 0.0, 1.0)); + vec4 transmittance = texture(transmittance_tex, uv); + + // The proper thing would be to have spectral data for the stars' radiance. + // This could be approximated by taking the star's temperature and using + // Plank's law to obtain the spectral radiance for our 4 wavelengths. + // That's too complicated for now, so instead we just average the four + // spectral samples from the atmospheric transmittance. + color *= dot(transmittance, vec4(0.25)); + + // Pre-expose + color = apply_exposure(color); + + // Final color = transmittance * star radiance + sky inscattering + // In this frag shader we output the multiplication part, and the sky + // in-scattering is added by doing additive blending on top of the skydome. + fragColor = vec4(color, 1.0); } diff --git a/Shaders/HDR/stars.vert b/Shaders/HDR/stars.vert index cca905cd2..fa3f02758 100644 --- a/Shaders/HDR/stars.vert +++ b/Shaders/HDR/stars.vert @@ -5,12 +5,15 @@ layout(location = 2) in vec4 vertex_color; out VS_OUT { vec4 color; + vec3 view_vector; } vs_out; +uniform mat4 osg_ModelViewMatrix; uniform mat4 osg_ModelViewProjectionMatrix; void main() { gl_Position = osg_ModelViewProjectionMatrix * pos; vs_out.color = vertex_color; + vs_out.view_vector = (osg_ModelViewMatrix * pos).xyz; }