HDR pipeline: a lot of improvements to atmospheric scattering
This commit is contained in:
parent
0a9a0527aa
commit
9eaef501c7
13 changed files with 330 additions and 205 deletions
|
@ -6,4 +6,8 @@
|
|||
<!-- Only render the skydome and terrain -->
|
||||
<!-- TODO: Explicitly select the LOD level -->
|
||||
<cull-mask>0x801</cull-mask>
|
||||
<binding>
|
||||
<unit>11</unit>
|
||||
<buffer>sky-view</buffer>
|
||||
</binding>
|
||||
</PropertyList>
|
||||
|
|
|
@ -55,15 +55,6 @@
|
|||
<format>rgb16f</format>
|
||||
</buffer>
|
||||
|
||||
<!-- HDR with rendered atmosphere -->
|
||||
<buffer>
|
||||
<name>hdr-with-atmosphere</name>
|
||||
<type>2d</type>
|
||||
<width>screen</width>
|
||||
<height>screen</height>
|
||||
<format>rgb16f</format>
|
||||
</buffer>
|
||||
|
||||
<!-- Final LDR buffer -->
|
||||
<buffer>
|
||||
<name>final</name>
|
||||
|
@ -73,6 +64,41 @@
|
|||
<format>rgb8</format>
|
||||
</buffer>
|
||||
|
||||
<!-- Atmosphere LUTs -->
|
||||
<buffer>
|
||||
<name>sky-view</name>
|
||||
<type>2d</type>
|
||||
<width>256</width>
|
||||
<height>128</height>
|
||||
<format>rgb16f</format>
|
||||
<min-filter>linear</min-filter>
|
||||
<mag-filter>linear</mag-filter>
|
||||
<wrap-s>repeat</wrap-s>
|
||||
<wrap-t>clamp-to-edge</wrap-t>
|
||||
</buffer>
|
||||
<buffer>
|
||||
<name>aerial-inscatter</name>
|
||||
<type>2d</type>
|
||||
<width>512</width>
|
||||
<height>32</height>
|
||||
<format>rgba16f</format>
|
||||
<min-filter>linear</min-filter>
|
||||
<mag-filter>linear</mag-filter>
|
||||
<wrap-s>clamp-to-edge</wrap-s>
|
||||
<wrap-t>clamp-to-edge</wrap-t>
|
||||
</buffer>
|
||||
<buffer>
|
||||
<name>aerial-transmittance</name>
|
||||
<type>2d</type>
|
||||
<width>512</width>
|
||||
<height>32</height>
|
||||
<format>rgba16f</format>
|
||||
<min-filter>linear</min-filter>
|
||||
<mag-filter>linear</mag-filter>
|
||||
<wrap-s>clamp-to-edge</wrap-s>
|
||||
<wrap-t>clamp-to-edge</wrap-t>
|
||||
</buffer>
|
||||
|
||||
<!-- Environment cubemap -->
|
||||
<buffer>
|
||||
<name>envmap</name>
|
||||
|
@ -187,6 +213,31 @@
|
|||
|
||||
<!--=======================================================================-->
|
||||
|
||||
<!-- Sky-View -->
|
||||
<pass>
|
||||
<name>atmos-sky-view</name>
|
||||
<type>quad</type>
|
||||
<effect>Effects/HDR/atmos-sky-view</effect>
|
||||
<attachment>
|
||||
<component>color</component>
|
||||
<buffer>sky-view</buffer>
|
||||
</attachment>
|
||||
</pass>
|
||||
<!-- Aerial Perspective -->
|
||||
<pass>
|
||||
<name>atmos-aerial-perspective</name>
|
||||
<type>quad</type>
|
||||
<effect>Effects/HDR/atmos-aerial-perspective</effect>
|
||||
<attachment>
|
||||
<component>color0</component>
|
||||
<buffer>aerial-inscatter</buffer>
|
||||
</attachment>
|
||||
<attachment>
|
||||
<component>color1</component>
|
||||
<buffer>aerial-transmittance</buffer>
|
||||
</attachment>
|
||||
</pass>
|
||||
|
||||
<!--
|
||||
Environment capture passes
|
||||
Render to a cubemap using forward rendering. Only render the skydome and
|
||||
|
@ -643,6 +694,14 @@
|
|||
<unit>10</unit>
|
||||
<buffer>sun-shadowmap-atlas</buffer>
|
||||
</binding>
|
||||
<binding>
|
||||
<unit>11</unit>
|
||||
<buffer>aerial-inscatter</buffer>
|
||||
</binding>
|
||||
<binding>
|
||||
<unit>12</unit>
|
||||
<buffer>aerial-transmittance</buffer>
|
||||
</binding>
|
||||
<attachment>
|
||||
<component>color0</component>
|
||||
<buffer>hdr-result</buffer>
|
||||
|
@ -665,6 +724,10 @@
|
|||
<unit>9</unit>
|
||||
<buffer>envmap</buffer>
|
||||
</binding>
|
||||
<binding>
|
||||
<unit>11</unit>
|
||||
<buffer>sky-view</buffer>
|
||||
</binding>
|
||||
<attachment>
|
||||
<component>color</component>
|
||||
<buffer>hdr-result</buffer>
|
||||
|
@ -675,24 +738,6 @@
|
|||
</attachment>
|
||||
</pass>
|
||||
|
||||
<pass>
|
||||
<name>atmosphere</name>
|
||||
<type>quad</type>
|
||||
<effect>Effects/HDR/atmosphere</effect>
|
||||
<binding>
|
||||
<unit>0</unit>
|
||||
<buffer>hdr-result</buffer>
|
||||
</binding>
|
||||
<binding>
|
||||
<unit>1</unit>
|
||||
<buffer>depth</buffer>
|
||||
</binding>
|
||||
<attachment>
|
||||
<component>color0</component>
|
||||
<buffer>hdr-with-atmosphere</buffer>
|
||||
</attachment>
|
||||
</pass>
|
||||
|
||||
<!--
|
||||
Average luminance calculation
|
||||
1. Convert the RGB values to luminance values and store them on a fixed
|
||||
|
@ -710,7 +755,7 @@
|
|||
<effect>Effects/HDR/luminance</effect>
|
||||
<binding>
|
||||
<unit>0</unit>
|
||||
<buffer>hdr-with-atmosphere</buffer>
|
||||
<buffer>hdr-result</buffer>
|
||||
</binding>
|
||||
<attachment>
|
||||
<component>color</component>
|
||||
|
@ -762,7 +807,7 @@
|
|||
<effect>Effects/HDR/bloom-threshold</effect>
|
||||
<binding>
|
||||
<unit>0</unit>
|
||||
<buffer>hdr-with-atmosphere</buffer>
|
||||
<buffer>hdr-result</buffer>
|
||||
</binding>
|
||||
<binding>
|
||||
<unit>1</unit>
|
||||
|
@ -924,7 +969,7 @@
|
|||
<effect>Effects/HDR/postprocess</effect>
|
||||
<binding>
|
||||
<unit>0</unit>
|
||||
<buffer>hdr-with-atmosphere</buffer>
|
||||
<buffer>hdr-result</buffer>
|
||||
</binding>
|
||||
<binding>
|
||||
<unit>1</unit>
|
||||
|
|
|
@ -1,24 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PropertyList>
|
||||
<name>Effects/HDR/atmosphere</name>
|
||||
<name>Effects/HDR/atmos-aerial-perspective</name>
|
||||
<technique n="1">
|
||||
<pass>
|
||||
<program>
|
||||
<vertex-shader>Shaders/HDR/trivial.vert</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/atmosphere.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/HDR/atmos-aerial-perspective.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/HDR/atmosphere-include.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/HDR/gbuffer-include.frag</fragment-shader>
|
||||
</program>
|
||||
<uniform>
|
||||
<name>hdr_tex</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">0</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>depth_tex</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">1</value>
|
||||
</uniform>
|
||||
</pass>
|
||||
</technique>
|
||||
</PropertyList>
|
13
Effects/HDR/atmos-sky-view.eff
Normal file
13
Effects/HDR/atmos-sky-view.eff
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PropertyList>
|
||||
<name>Effects/HDR/atmos-sky-view</name>
|
||||
<technique n="1">
|
||||
<pass>
|
||||
<program>
|
||||
<vertex-shader>Shaders/HDR/trivial.vert</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/atmos-sky-view.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/HDR/atmosphere-include.frag</fragment-shader>
|
||||
</program>
|
||||
</pass>
|
||||
</technique>
|
||||
</PropertyList>
|
|
@ -67,6 +67,16 @@
|
|||
<type>sampler-2d-shadow</type>
|
||||
<value type="int">10</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>aerial_inscatter_lut</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">11</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>aerial_transmittance_lut</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">12</value>
|
||||
</uniform>
|
||||
</pass>
|
||||
</technique>
|
||||
</PropertyList>
|
||||
|
|
|
@ -300,6 +300,27 @@
|
|||
<technique n="109">
|
||||
<scheme>hdr-geometry</scheme>
|
||||
</technique>
|
||||
<technique n="129">
|
||||
<scheme>hdr-forward</scheme>
|
||||
<pass>
|
||||
<cull-face>back</cull-face>
|
||||
<depth>
|
||||
<function>lequal</function>
|
||||
<near>0.0</near>
|
||||
<far>1.0</far>
|
||||
<write-mask>true</write-mask>
|
||||
</depth>
|
||||
<program>
|
||||
<vertex-shader>Shaders/HDR/skydome.vert</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/skydome.frag</fragment-shader>
|
||||
</program>
|
||||
<uniform>
|
||||
<name>sky_view_lut</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">11</value>
|
||||
</uniform>
|
||||
</pass>
|
||||
</technique>
|
||||
<technique n="139">
|
||||
<scheme>hdr-envmap</scheme>
|
||||
<pass>
|
||||
|
@ -313,17 +334,11 @@
|
|||
<program>
|
||||
<vertex-shader>Shaders/HDR/skydome.vert</vertex-shader>
|
||||
<fragment-shader>Shaders/HDR/skydome.frag</fragment-shader>
|
||||
<fragment-shader>Shaders/HDR/atmosphere-include.frag</fragment-shader>
|
||||
</program>
|
||||
<uniform>
|
||||
<name>sun_disk</name>
|
||||
<type>bool</type>
|
||||
<value type="bool">false</value>
|
||||
</uniform>
|
||||
<uniform>
|
||||
<name>num_samples</name>
|
||||
<type>int</type>
|
||||
<value type="int">16</value>
|
||||
<name>sky_view_lut</name>
|
||||
<type>sampler-2d</type>
|
||||
<value type="int">11</value>
|
||||
</uniform>
|
||||
</pass>
|
||||
</technique>
|
||||
|
|
47
Shaders/HDR/atmos-aerial-perspective.frag
Normal file
47
Shaders/HDR/atmos-aerial-perspective.frag
Normal file
|
@ -0,0 +1,47 @@
|
|||
#version 330 core
|
||||
|
||||
layout(location = 0) out vec3 out_inscatter;
|
||||
layout(location = 1) out vec3 out_transmittance;
|
||||
|
||||
in vec2 texCoord;
|
||||
|
||||
uniform mat4 fg_ViewMatrixInverse;
|
||||
uniform vec3 fg_CameraPositionCart;
|
||||
uniform vec3 fg_CameraPositionGeod;
|
||||
uniform vec3 fg_SunDirectionWorld;
|
||||
uniform vec2 fg_NearFar;
|
||||
|
||||
const float TOTAL_SLICES = 16.0;
|
||||
const float DEPTH_RANGE = 32000.0;
|
||||
|
||||
vec3 positionFromDepth(vec2 pos, float depth);
|
||||
void calculateScattering(in vec3 rayOrigin,
|
||||
in vec3 rayDir,
|
||||
in float tmax,
|
||||
in vec3 lightDir,
|
||||
in float earthRadius,
|
||||
out vec3 inscatter,
|
||||
out vec3 transmittance);
|
||||
|
||||
void main()
|
||||
{
|
||||
float x = texCoord.x * TOTAL_SLICES;
|
||||
vec2 coord = vec2(fract(x), texCoord.y);
|
||||
|
||||
float depth = mix(fg_NearFar.x, DEPTH_RANGE, ceil(x) / TOTAL_SLICES);
|
||||
|
||||
vec3 fragPos = positionFromDepth(coord * 2.0 - 1.0, 0.0);
|
||||
vec3 rayDir = vec4(fg_ViewMatrixInverse * vec4(normalize(fragPos), 0.0)).xyz;
|
||||
|
||||
float earthRadius = length(fg_CameraPositionCart) - fg_CameraPositionGeod.z;
|
||||
|
||||
vec3 inscatter, transmittance;
|
||||
calculateScattering(fg_CameraPositionCart,
|
||||
rayDir,
|
||||
depth,
|
||||
fg_SunDirectionWorld,
|
||||
earthRadius,
|
||||
inscatter, transmittance);
|
||||
out_inscatter = inscatter;
|
||||
out_transmittance = transmittance;
|
||||
}
|
51
Shaders/HDR/atmos-sky-view.frag
Normal file
51
Shaders/HDR/atmos-sky-view.frag
Normal file
|
@ -0,0 +1,51 @@
|
|||
#version 330 core
|
||||
|
||||
out vec3 fragColor;
|
||||
|
||||
in vec2 texCoord;
|
||||
|
||||
uniform vec3 fg_CameraPositionCart;
|
||||
uniform vec3 fg_CameraPositionGeod;
|
||||
uniform vec3 fg_SunDirectionWorld;
|
||||
|
||||
const float PI = 3.141592653;
|
||||
|
||||
void calculateScattering(in vec3 rayOrigin,
|
||||
in vec3 rayDir,
|
||||
in float tmax,
|
||||
in vec3 lightDir,
|
||||
in float earthRadius,
|
||||
out vec3 inscatter,
|
||||
out vec3 transmittance);
|
||||
|
||||
void main()
|
||||
{
|
||||
// Always leave the sun right in the middle of the texture as the skydome
|
||||
// model is already being rotated.
|
||||
float sunCosTheta = dot(fg_SunDirectionWorld, normalize(fg_CameraPositionCart));
|
||||
vec3 lightDir = vec3(-sqrt(1.0 - sunCosTheta*sunCosTheta), 0.0, sunCosTheta);
|
||||
|
||||
float azimuth = 2.0 * PI * texCoord.x; // [0, 2pi]
|
||||
// Apply a non-linear transformation to the elevation to dedicate more
|
||||
// texels to the horizon, which is where having more detail matters.
|
||||
float l = texCoord.y * 2.0 - 1.0;
|
||||
float elev = l*l * sign(l) * PI * 0.5; // [-pi/2, pi/2]
|
||||
vec3 rayDir = vec3(cos(elev) * cos(azimuth), cos(elev) * sin(azimuth), sin(elev));
|
||||
|
||||
float cameraPosLength = length(fg_CameraPositionCart);
|
||||
// Since FG internally uses WG84 coordinates, we use the current Earth
|
||||
// radius under the camera, which varies with the latitude. For practical
|
||||
// purposes we model the Earth as a perfect sphere with this radius.
|
||||
float earthRadius = cameraPosLength - fg_CameraPositionGeod.z;
|
||||
|
||||
vec3 rayOrigin = vec3(0.0, 0.0, cameraPosLength);
|
||||
|
||||
vec3 inscatter, transmittance;
|
||||
calculateScattering(rayOrigin,
|
||||
rayDir,
|
||||
9.0e8,
|
||||
lightDir,
|
||||
earthRadius,
|
||||
inscatter, transmittance);
|
||||
fragColor = inscatter;
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
#version 330 core
|
||||
|
||||
uniform bool sun_disk = true;
|
||||
uniform vec3 beta_rayleigh = vec3(5.5e-6, 13.0e-6, 22.4e-6);
|
||||
uniform float beta_mie = 21e-6;
|
||||
uniform vec3 beta_absortion = vec3(2.04e-5, 4.97e-5, 1.95e-6);
|
||||
|
@ -9,54 +8,42 @@ uniform float rayleigh_scale_height = 8e3;
|
|||
uniform float mie_scale_height = 1.2e3;
|
||||
uniform float absortion_scale_height = 30e3;
|
||||
uniform float absortion_falloff = 3e3;
|
||||
uniform int num_samples = 64;
|
||||
uniform int num_samples = 32;
|
||||
uniform int num_light_samples = 4;
|
||||
|
||||
const float PI = 3.141592653;
|
||||
const float ATMOSPHERE_RADIUS = 6471e3;
|
||||
const vec3 SUN_INTENSITY = vec3(20.0);
|
||||
const float COS_SUN_ANGULAR_DIAMETER = 0.999956676946448443553574619906976478926848692873900859324;
|
||||
|
||||
vec2 raySphereIntersection(vec3 r0, vec3 rd, float radius)
|
||||
vec2 raySphereIntersection(vec3 ro, vec3 rd, float radius)
|
||||
{
|
||||
float a = dot(rd, rd);
|
||||
float b = 2.0 * dot(rd, r0);
|
||||
float c = dot(r0, r0) - (radius * radius);
|
||||
float d = (b*b) - 4.0*a*c;
|
||||
if (d < 0.0) return vec2(1e5, -1e5);
|
||||
return vec2((-b - sqrt(d))/(2.0*a), (-b + sqrt(d))/(2.0*a));
|
||||
vec3 tc = -ro;
|
||||
float b = dot(tc, rd);
|
||||
float d = b*b - dot(tc, tc) + radius*radius;
|
||||
if (d < 0.0) return vec2(-1.0);
|
||||
float s = sqrt(d);
|
||||
return vec2(b-s, b+s);
|
||||
}
|
||||
|
||||
vec3 calculateScattering(vec3 rayOrigin,
|
||||
vec3 rayDir,
|
||||
vec3 sceneColor,
|
||||
float depth,
|
||||
float maxDist,
|
||||
float earthRadius,
|
||||
vec3 lightDir)
|
||||
void calculateScattering(in vec3 rayOrigin,
|
||||
in vec3 rayDir,
|
||||
in float tmax,
|
||||
in vec3 lightDir,
|
||||
in float earthRadius,
|
||||
out vec3 inscatter,
|
||||
out vec3 transmittance)
|
||||
{
|
||||
vec2 hit = raySphereIntersection(rayOrigin, rayDir, ATMOSPHERE_RADIUS);
|
||||
if (hit.x > hit.y) {
|
||||
// The ray did not hit the atmosphere, we are in outer space
|
||||
return sceneColor;
|
||||
}
|
||||
hit.x = max(hit.x, 0.0); // Do not sample behind the camera
|
||||
// Avoid clamping the ray to the far plane when there is no geometry in
|
||||
// front of the sky
|
||||
if (depth < 1.0) {
|
||||
// Stop the ray at the geometry
|
||||
hit.y = min(hit.y, maxDist);
|
||||
} else {
|
||||
// If there is no geometry, simulate a collision with the Earth at sea
|
||||
// level. This only happens when FG hasn't loaded any terrain
|
||||
vec2 hitEarth = raySphereIntersection(
|
||||
rayOrigin, rayDir, earthRadius - 1.0);
|
||||
if (hitEarth.x < hitEarth.y && hitEarth.x > 0.0) {
|
||||
hit.y = min(hit.y, hitEarth.x);
|
||||
}
|
||||
}
|
||||
vec2 hitEarth = raySphereIntersection(rayOrigin, rayDir, earthRadius - 1.0);
|
||||
if (hitEarth.y > 0.0)
|
||||
tmax = max(0.0, hitEarth.x);
|
||||
|
||||
float stepSize = (hit.y - hit.x) / float(num_samples);
|
||||
float tmin = max(hit.x, 0.0);
|
||||
tmax = min(hit.y, tmax);
|
||||
if (tmax < 0.0)
|
||||
discard;
|
||||
|
||||
float stepSize = (tmax - tmin) / float(num_samples);
|
||||
|
||||
const float g = 0.758; // Mie scattering direction
|
||||
const float gg = g*g;
|
||||
|
@ -70,7 +57,7 @@ vec3 calculateScattering(vec3 rayOrigin,
|
|||
float opticalDepthMie = 0.0;
|
||||
float opticalDepthAbsortion = 0.0;
|
||||
|
||||
float primaryTime = hit.x;
|
||||
float primaryTime = tmin;
|
||||
|
||||
vec3 extinctionFactor = vec3(0.0);
|
||||
vec3 totalRayleigh = vec3(0.0);
|
||||
|
@ -100,11 +87,14 @@ vec3 calculateScattering(vec3 rayOrigin,
|
|||
|
||||
float secondaryTime = 0.0;
|
||||
|
||||
for (int j = 0; j < num_light_samples; ++j) {
|
||||
int j;
|
||||
for (j = 0; j < num_light_samples; ++j) {
|
||||
vec3 samplePointLight = samplePoint + lightDir *
|
||||
(secondaryTime + stepSizeLight * 0.5);
|
||||
|
||||
float altitudeLight = length(samplePointLight) - earthRadius;
|
||||
if (altitudeLight < 0.0)
|
||||
break;
|
||||
|
||||
float densityLightRayleigh = exp(-altitudeLight / rayleigh_scale_height);
|
||||
float densityLightMie = exp(-altitudeLight / mie_scale_height);
|
||||
|
@ -116,37 +106,28 @@ vec3 calculateScattering(vec3 rayOrigin,
|
|||
secondaryTime += stepSizeLight;
|
||||
}
|
||||
|
||||
vec3 tau =
|
||||
beta_rayleigh * (opticalDepthRayleigh + opticalDepthLightRayleigh) +
|
||||
beta_mie * (opticalDepthMie + opticalDepthLightMie) +
|
||||
beta_absortion * (opticalDepthAbsortion + opticalDepthLightAbsortion);
|
||||
vec3 attenuation = exp(-tau);
|
||||
if (j == num_light_samples) {
|
||||
vec3 tau =
|
||||
beta_rayleigh * (opticalDepthRayleigh + opticalDepthLightRayleigh) +
|
||||
beta_mie * (opticalDepthMie + opticalDepthLightMie) +
|
||||
beta_absortion * (opticalDepthAbsortion + opticalDepthLightAbsortion);
|
||||
vec3 attenuation = exp(-tau);
|
||||
|
||||
extinctionFactor += attenuation;
|
||||
extinctionFactor += attenuation;
|
||||
|
||||
totalRayleigh += stepOpticalDepthRayleigh * attenuation;
|
||||
totalMie += stepOpticalDepthMie * attenuation;
|
||||
totalRayleigh += stepOpticalDepthRayleigh * attenuation;
|
||||
totalMie += stepOpticalDepthMie * attenuation;
|
||||
}
|
||||
|
||||
primaryTime += stepSize;
|
||||
}
|
||||
|
||||
vec3 opacity = exp(-(beta_rayleigh * opticalDepthRayleigh +
|
||||
beta_mie * opticalDepthMie +
|
||||
beta_absortion * opticalDepthAbsortion));
|
||||
transmittance = exp(-(beta_rayleigh * opticalDepthRayleigh +
|
||||
beta_mie * opticalDepthMie +
|
||||
beta_absortion * opticalDepthAbsortion));
|
||||
|
||||
vec3 color = SUN_INTENSITY *
|
||||
inscatter = SUN_INTENSITY *
|
||||
(totalRayleigh * beta_rayleigh * phaseRayleigh +
|
||||
totalMie * beta_mie * phaseMie +
|
||||
opticalDepthRayleigh * beta_ambient)
|
||||
+ sceneColor * opacity;
|
||||
|
||||
if (sun_disk && (depth >= 1.0)) {
|
||||
float costheta = dot(rayDir, lightDir);
|
||||
float sundisk = smoothstep(COS_SUN_ANGULAR_DIAMETER,
|
||||
COS_SUN_ANGULAR_DIAMETER + 0.00002,
|
||||
costheta);
|
||||
color += SUN_INTENSITY * extinctionFactor * sundisk;
|
||||
}
|
||||
|
||||
return color;
|
||||
opticalDepthRayleigh * beta_ambient);
|
||||
}
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
#version 330 core
|
||||
|
||||
out vec3 fragColor;
|
||||
|
||||
in vec2 texCoord;
|
||||
|
||||
uniform mat4 fg_ViewMatrixInverse;
|
||||
uniform mat4 fg_ProjectionMatrixInverse;
|
||||
uniform vec3 fg_CameraPositionCart;
|
||||
uniform vec3 fg_CameraPositionGeod;
|
||||
uniform vec3 fg_SunDirection;
|
||||
uniform vec2 fg_BufferSize;
|
||||
|
||||
uniform sampler2D hdr_tex;
|
||||
uniform sampler2D depth_tex;
|
||||
|
||||
vec3 calculateScattering(vec3 rayOrigin,
|
||||
vec3 rayDir,
|
||||
vec3 sceneColor,
|
||||
float depth,
|
||||
float maxDist,
|
||||
float earthRadius,
|
||||
vec3 lightDir);
|
||||
vec3 positionFromDepth(vec2 pos, float depth);
|
||||
|
||||
void main()
|
||||
{
|
||||
float depth = texture(depth_tex, texCoord).r;
|
||||
vec3 fragPos = positionFromDepth(texCoord * 2.0 - 1.0,
|
||||
depth * 2.0 - 1.0);
|
||||
vec3 rayDir = vec4(fg_ViewMatrixInverse * vec4(normalize(fragPos), 0.0)).xyz;
|
||||
|
||||
// Since FG internally uses WG84 coordinates, we use the current Earth
|
||||
// radius under the camera, which varies with the latitude. For practical
|
||||
// purposes we model the Earth as a perfect sphere with this radius.
|
||||
float earthRadius = length(fg_CameraPositionCart) - fg_CameraPositionGeod.z;
|
||||
|
||||
vec3 sceneColor = texture(hdr_tex, texCoord).rgb;
|
||||
|
||||
vec3 color = calculateScattering(fg_CameraPositionCart,
|
||||
rayDir,
|
||||
sceneColor,
|
||||
depth,
|
||||
length(fragPos),
|
||||
earthRadius,
|
||||
fg_SunDirection);
|
||||
fragColor = color;
|
||||
}
|
|
@ -12,11 +12,14 @@ uniform sampler2D ao_tex;
|
|||
uniform samplerCube prefiltered_envmap;
|
||||
uniform sampler2DShadow shadow_tex;
|
||||
uniform sampler2D dfg_lut;
|
||||
uniform sampler2D aerial_inscatter_lut;
|
||||
uniform sampler2D aerial_transmittance_lut;
|
||||
|
||||
uniform mat4 fg_ViewMatrix;
|
||||
uniform mat4 fg_ViewMatrixInverse;
|
||||
uniform vec3 fg_SunDirection;
|
||||
uniform vec3 fg_CameraPositionCart;
|
||||
uniform vec2 fg_NearFar;
|
||||
|
||||
uniform mat4 fg_LightMatrix_csm0;
|
||||
uniform mat4 fg_LightMatrix_csm1;
|
||||
|
@ -40,6 +43,11 @@ const vec2 uv_shifts[4] = vec2[4](
|
|||
vec2(0.0, 0.5), vec2(0.5, 0.5));
|
||||
const vec2 uv_factor = vec2(0.5, 0.5);
|
||||
|
||||
const float AERIAL_SLICES = 16.0;
|
||||
const float AERIAL_LUT_TILE_SIZE = 1.0 / AERIAL_SLICES;
|
||||
const float AERIAL_LUT_TEXEL_SIZE = 1.0 / 512.0;
|
||||
const float AERIAL_MAX_DEPTH = 32000.0;
|
||||
|
||||
const float MAX_PREFILTERED_LOD = 4.0;
|
||||
|
||||
const vec3 SUN_INTENSITY = vec3(20.0);
|
||||
|
@ -163,10 +171,10 @@ float getShadowing(vec3 p, vec3 n, float NdotL)
|
|||
float shadow = 1.0;
|
||||
|
||||
vec4 lightSpacePos[4];
|
||||
lightSpacePos[0] = getLightSpacePosition(p, n, NdotL, 0.01, fg_LightMatrix_csm0);
|
||||
lightSpacePos[1] = getLightSpacePosition(p, n, NdotL, 0.01, fg_LightMatrix_csm1);
|
||||
lightSpacePos[2] = getLightSpacePosition(p, n, NdotL, 0.01, fg_LightMatrix_csm2);
|
||||
lightSpacePos[3] = getLightSpacePosition(p, n, NdotL, 0.01, fg_LightMatrix_csm3);
|
||||
lightSpacePos[0] = getLightSpacePosition(p, n, NdotL, 0.05, fg_LightMatrix_csm0);
|
||||
lightSpacePos[1] = getLightSpacePosition(p, n, NdotL, 0.2, fg_LightMatrix_csm1);
|
||||
lightSpacePos[2] = getLightSpacePosition(p, n, NdotL, 1.0, fg_LightMatrix_csm2);
|
||||
lightSpacePos[3] = getLightSpacePosition(p, n, NdotL, 5.0, fg_LightMatrix_csm3);
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
// Map-based cascade selection
|
||||
|
@ -322,15 +330,44 @@ vec3 BRDF(in vec3 albedo, in float metalness, in float roughness,
|
|||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
float map(float value, float min1, float max1, float min2, float max2) {
|
||||
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
|
||||
}
|
||||
|
||||
vec3 sampleAerialPerspectiveSlice(sampler2D tex, int slice)
|
||||
{
|
||||
float offset = slice * AERIAL_LUT_TILE_SIZE + AERIAL_LUT_TEXEL_SIZE * 0.5;
|
||||
float x = texCoord.x * (AERIAL_LUT_TILE_SIZE - AERIAL_LUT_TEXEL_SIZE) + offset;
|
||||
return texture(tex, vec2(x, texCoord.y)).rgb;
|
||||
}
|
||||
|
||||
vec3 sampleAerialPerspective(sampler2D tex, vec3 zero, float depth)
|
||||
{
|
||||
vec3 color;
|
||||
depth = min(abs(depth), AERIAL_MAX_DEPTH);
|
||||
float d = map(depth, fg_NearFar.x, AERIAL_MAX_DEPTH, 0.0, AERIAL_SLICES);
|
||||
if (d <= 1.0) {
|
||||
color = mix(zero, sampleAerialPerspectiveSlice(tex, 0), d);
|
||||
} else {
|
||||
d -= 1.0;
|
||||
color = mix(sampleAerialPerspectiveSlice(tex, int(floor(d))),
|
||||
sampleAerialPerspectiveSlice(tex, int(ceil(d))),
|
||||
fract(d));
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void main()
|
||||
{
|
||||
float depth = texture(depth_tex, texCoord).r;
|
||||
vec4 gbuffer0 = texture(gbuffer0_tex, texCoord);
|
||||
vec2 gbuffer1 = texture(gbuffer1_tex, texCoord).rg;
|
||||
vec4 gbuffer2 = texture(gbuffer2_tex, texCoord);
|
||||
float depth = texture(depth_tex, texCoord).r * 2.0 - 1.0; // Clip space
|
||||
float ao = texture(ao_tex, texCoord).r;
|
||||
|
||||
vec3 pos = positionFromDepth(texCoord * 2.0 - 1.0, depth);
|
||||
vec3 pos = positionFromDepth(texCoord * 2.0 - 1.0, depth * 2.0 - 1.0);
|
||||
vec3 v = normalize(-pos);
|
||||
vec3 n = decodeNormal(gbuffer1);
|
||||
|
||||
|
@ -341,7 +378,7 @@ void main()
|
|||
float clearcoat = gbuffer2.b;
|
||||
float clearcoatRoughness = gbuffer2.a;
|
||||
|
||||
vec3 l = normalize(vec4(fg_ViewMatrix * vec4(fg_SunDirection, 0.0)).xyz);
|
||||
vec3 l = fg_SunDirection;
|
||||
vec3 h = normalize(v + l);
|
||||
|
||||
float NdotL = clamp(dot(n, l), 0.001, 1.0);
|
||||
|
@ -366,5 +403,10 @@ void main()
|
|||
float shadowFactor = getShadowing(pos, n, NdotL);
|
||||
vec3 color = ambient + brdf * sunIlluminance * shadowFactor;
|
||||
|
||||
fragHdrColor = color;
|
||||
vec3 inscatter = sampleAerialPerspective(
|
||||
aerial_inscatter_lut, vec3(0.0), length(pos));
|
||||
vec3 transmittance = sampleAerialPerspective(
|
||||
aerial_transmittance_lut, vec3(1.0), length(pos));
|
||||
|
||||
fragHdrColor = color * transmittance + inscatter;
|
||||
}
|
||||
|
|
|
@ -2,39 +2,19 @@
|
|||
|
||||
out vec4 fragColor;
|
||||
|
||||
in vec3 rayDirVertex;
|
||||
in vec3 rayDir;
|
||||
|
||||
uniform mat4 osg_ModelViewMatrix;
|
||||
uniform mat4 osg_ViewMatrix;
|
||||
uniform vec3 fg_SunDirection;
|
||||
uniform sampler2D sky_view_lut;
|
||||
|
||||
vec3 calculateScattering(vec3 rayOrigin,
|
||||
vec3 rayDir,
|
||||
vec3 sceneColor,
|
||||
float depth,
|
||||
float maxDist,
|
||||
float earthRadius,
|
||||
vec3 lightDir);
|
||||
const float PI = 3.141592653;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Ground point (skydome center) in eye coordinates
|
||||
vec4 groundPoint = inverse(osg_ViewMatrix) * osg_ModelViewMatrix
|
||||
* vec4(0.0, 0.0, 0.0, 1.0);
|
||||
float azimuth = atan(rayDir.y, rayDir.x) / PI * 0.5 + 0.5;
|
||||
// Undo the non-linear transformation from the sky-view LUT
|
||||
float l = asin(rayDir.z);
|
||||
float elev = sqrt(abs(l) / (PI * 0.5)) * sign(l) * 0.5 + 0.5;
|
||||
|
||||
// HACK: WGS84 models the Earth as an oblate spheroid, so we can't use
|
||||
// a constant Earth radius. This should be precomputed!
|
||||
float earthRadius = length(groundPoint);
|
||||
|
||||
vec3 cameraPos = vec4(inverse(osg_ViewMatrix) * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
|
||||
vec3 rayDir = normalize(rayDirVertex);
|
||||
|
||||
vec3 color = calculateScattering(cameraPos,
|
||||
rayDir,
|
||||
vec3(0.0),
|
||||
1.0,
|
||||
3.0 * earthRadius,
|
||||
earthRadius,
|
||||
fg_SunDirection);
|
||||
vec3 color = texture(sky_view_lut, vec2(azimuth, elev)).rgb;
|
||||
fragColor = vec4(color, 1.0);
|
||||
}
|
||||
|
|
|
@ -2,17 +2,12 @@
|
|||
|
||||
layout(location = 0) in vec4 pos;
|
||||
|
||||
out vec3 rayDirVertex;
|
||||
out vec3 rayDir;
|
||||
|
||||
uniform mat4 osg_ModelViewMatrix;
|
||||
uniform mat4 osg_ModelViewProjectionMatrix;
|
||||
uniform mat4 osg_ViewMatrix;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = osg_ModelViewProjectionMatrix * pos;
|
||||
vec4 rayDirView = normalize(osg_ModelViewMatrix * pos);
|
||||
rayDirView.w = 0.0;
|
||||
rayDirVertex = vec4(inverse(osg_ViewMatrix) * rayDirView).xyz;
|
||||
rayDirVertex = normalize(rayDirVertex);
|
||||
rayDir = normalize(pos.xyz);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue