1
0
Fork 0

improved shader

This commit is contained in:
Fernando García Liñán 2019-12-05 16:36:30 +01:00
parent 9a8c28af1c
commit ae8fee80f7
8 changed files with 563 additions and 115 deletions

View file

@ -10,6 +10,37 @@
<height>screen</height>
<format>rgba8</format>
</buffer>
<buffer>
<name>depth</name>
<type>2d</type>
<width>screen</width>
<height>screen</height>
<format>depth32f</format>
</buffer>
<buffer>
<name>clouds</name>
<type>2d</type>
<width>screen</width>
<height>screen</height>
<!--
<screen-width-scale>0.5</screen-width-scale>
<screen-height-scale>0.5</screen-height-scale>
-->
<format>rgba8</format>
<border-color type="vec4d">0.0 0.0 0.0 1.0</border-color>
</buffer>
<buffer>
<name>prevFrameClouds</name>
<type>2d</type>
<width>screen</width>
<height>screen</height>
<!--
<screen-width-scale>0.5</screen-width-scale>
<screen-height-scale>0.5</screen-height-scale>
-->
<format>rgba8</format>
<border-color type="vec4d">0.0 0.0 0.0 1.0</border-color>
</buffer>
<buffer>
<name>final</name>
<type>2d</type>
@ -103,19 +134,47 @@
<attachment>
<buffer>color</buffer>
<component>color0</component>
<!--
<multisample-samples>4</multisample-samples>
<multisample-color-samples>4</multisample-color-samples>
-->
</attachment>
<attachment>
<buffer>depth</buffer>
<component>depth</component>
</attachment>
</pass>
<pass>
<name>volumetric-clouds</name>
<name>volclouds</name>
<type>quad</type>
<effect>Effects/ALS/volumetric-clouds</effect>
<binding>
<buffer>prevFrameClouds</buffer>
<unit>0</unit>
</binding>
<binding>
<buffer>depth</buffer>
<unit>1</unit>
</binding>
<attachment>
<buffer>clouds</buffer>
<component>color0</component>
</attachment>
</pass>
<pass>
<name>postprocess</name>
<type>quad</type>
<effect>Effects/ALS/postprocess</effect>
<binding>
<buffer>color</buffer>
<unit>0</unit>
</binding>
<binding>
<buffer>clouds</buffer>
<unit>4</unit>
</binding>
<attachment>
<buffer>final</buffer>
<component>color0</component>
@ -130,4 +189,18 @@
<unit>0</unit>
</binding>
</pass>
<pass>
<name>copyprevclouds</name>
<type>quad</type>
<binding>
<buffer>clouds</buffer>
<unit>0</unit>
</binding>
<attachment>
<buffer>prevFrameClouds</buffer>
<component>color0</component>
</attachment>
</pass>
</PropertyList>

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<PropertyList>
<name>Effects/ALS/postprocess</name>
<technique n="1">
<pass>
<program>
<vertex-shader>Shaders/ALS/fullscreen.vert</vertex-shader>
<fragment-shader>Shaders/ALS/postprocess.frag</fragment-shader>
</program>
<uniform>
<name>color_tex</name>
<type>sampler-2d</type>
<value type="int">0</value>
</uniform>
<uniform>
<name>clouds_tex</name>
<type>sampler-2d</type>
<value type="int">4</value>
</uniform>
</pass>
</technique>
</PropertyList>

View file

@ -4,27 +4,41 @@
<parameters>
<texture n="5">
<image>Textures/Sky/vol_cloud_base.png</image>
<type>2d</type>
<filter>linear</filter>
<type>3d</type>
<filter>linear-mipmap-linear</filter>
<wrap-s>repeat</wrap-s>
<wrap-t>repeat</wrap-t>
<wrap-r>repeat</wrap-r>
<internal-format>normalized</internal-format>
</texture>
<texture n="6">
<image>Textures/Sky/vol_cloud_erosion.png</image>
<type>2d</type>
<filter>linear</filter>
<type>3d</type>
<filter>linear-mipmap-linear</filter>
<wrap-s>repeat</wrap-s>
<wrap-t>repeat</wrap-t>
<wrap-r>repeat</wrap-r>
<internal-format>normalized</internal-format>
</texture>
<!-- ambient correction -->
<ambient-correction type="float">0.05</ambient-correction>
<visibility><use>/environment/ground-visibility-m</use></visibility>
<avisibility><use>/environment/visibility-m</use></avisibility>
<lthickness><use>/environment/ground-haze-thickness-m</use></lthickness>
<scattering><use>/rendering/scene/scattering</use></scattering>
<terminator><use>/environment/terminator-relative-position-m</use></terminator>
<fogtype><use>/sim/rendering/shaders/skydome</use></fogtype>
<wetness><use>/environment/surface/wetness</use></wetness>
<rnorm><use>/environment/rain-norm</use></rnorm>
<snow_level><use>/environment/snow-level-m</use></snow_level> <snow_thickness_factor><use>/environment/surface/snow-thickness-factor</use></snow_thickness_factor>
<base_scale><use>/test/base_scale</use></base_scale>
<erosion_scale><use>/test/erosion_scal</use></erosion_scale>
<cloud_density><use>/test/cloud_density</use></cloud_density>
<erosion_scale><use>/test/erosion_scale</use></erosion_scale>
<erosion_strength><use>/test/erosion_strength</use></erosion_strength>
<test_value><use>/test/test_value</use></test_value>
</parameters>
<technique n="10">
<technique n="1">
<pass>
<texture-unit>
<unit>5</unit>
@ -43,6 +57,9 @@
<wrap-t>
<use>texture[5]/wrap-t</use>
</wrap-t>
<wrap-r>
<use>texture[5]/wrap-r</use>
</wrap-r>
<internal-format>
<use>texture[5]/internal-format</use>
</internal-format>
@ -64,30 +81,110 @@
<wrap-t>
<use>texture[6]/wrap-t</use>
</wrap-t>
<wrap-r>
<use>texture[6]/wrap-r</use>
</wrap-r>
<internal-format>
<use>texture[6]/internal-format</use>
</internal-format>
</texture-unit>
<program>
<vertex-shader>Shaders/Default/trivial.vert</vertex-shader>
<vertex-shader>Shaders/ALS/fullscreen.vert</vertex-shader>
<fragment-shader>Shaders/ALS/volumetric-clouds.frag</fragment-shader>
<fragment-shader>Shaders/ALS/noise.frag</fragment-shader>
<fragment-shader>Shaders/ALS/hazes.frag</fragment-shader>
</program>
<uniform>
<name>color_tex</name>
<name>prevframe_tex</name>
<type>sampler-2d</type>
<value type="int">0</value>
</uniform>
<uniform>
<name>noise_base_tex</name>
<name>depth_tex</name>
<type>sampler-2d</type>
<value type="int">1</value>
</uniform>
<uniform>
<name>noise_base_tex</name>
<type>sampler-3d</type>
<value type="int">5</value>
</uniform>
<uniform>
<name>noise_erosion_tex</name>
<type>sampler-2d</type>
<type>sampler-3d</type>
<value type="int">6</value>
</uniform>
<uniform>
<name>avisibility</name>
<type>float</type>
<value><use>avisibility</use></value>
</uniform>
<uniform>
<name>cloud_self_shading</name>
<type>float</type>
<value><use>cloud_self_shading</use></value>
</uniform>
<uniform>
<name>eye_alt</name>
<type>float</type>
<value><use>eye_alt</use></value>
</uniform>
<uniform>
<name>ground_scattering</name>
<type>float</type>
<value><use>ground_scattering</use></value>
</uniform>
<uniform>
<name>hazeLayerAltitude</name>
<type>float</type>
<value><use>lthickness</use></value>
</uniform>
<uniform>
<name>moonlight</name>
<type>float</type>
<value><use>moonlight</use></value>
</uniform>
<uniform>
<name>overcast</name>
<type>float</type>
<value><use>overcast</use></value>
</uniform>
<uniform>
<name>scattering</name>
<type>float</type>
<value><use>scattering</use></value>
</uniform>
<uniform>
<name>terminator</name>
<type>float</type>
<value><use>terminator</use></value>
</uniform>
<uniform>
<name>terrain_alt</name>
<type>float</type>
<value><use>terrain_alt</use></value>
</uniform>
<uniform>
<name>visibility</name>
<type>float</type>
<value><use>visibility</use></value>
</uniform>
<uniform>
<name>air_pollution</name>
<type>float</type>
<value><use>air_pollution</use></value>
</uniform>
<uniform>
<name>snowlevel</name>
<type>float</type>
<value><use>snow_level</use></value>
</uniform>
<uniform>
<name>snow_thickness_factor</name>
<type>float</type>
<value><use>snow_thickness_factor</use></value>
</uniform>
<uniform>
<name>BASE_SCALE</name>
@ -109,6 +206,11 @@
<type>float</type>
<value><use>erosion_strength</use></value>
</uniform>
<uniform>
<name>test_value</name>
<type>float</type>
<value><use>test_value</use></value>
</uniform>
</pass>
</technique>
</PropertyList>

View file

@ -0,0 +1,6 @@
#version 120
void main()
{
gl_Position = ftransform();
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
}

View file

@ -0,0 +1,15 @@
#version 120
uniform sampler2D color_tex;
uniform sampler2D clouds_tex;
uniform vec2 fg_ViewportSize;
void main()
{
vec2 uv = gl_FragCoord.xy / fg_ViewportSize;
vec3 color = texture2D(color_tex, uv).rgb;
vec4 clouds = texture2D(clouds_tex, uv);
color = clouds.rgb + color * clouds.a;
gl_FragColor = vec4(color, 1.0);
}

View file

@ -1,46 +1,164 @@
#version 120
#extension GL_EXT_gpu_shader4 : enable
const int MAX_MARCHING_STEPS = 64;
const float CLOUD_START_ALT = 1500.0;
const float CLOUD_END_ALT = 3000.0;
const float CUTOFF_DISTANCE = 100000.0;
const float COVERAGE_SCALE = 0.001;
const int LIGHT_MARCHING_STEPS = 6;
const float FORWARD_SCATTERING = 0.8;
const float BACKWARD_SCATTERING = -0.5;
const float SCATTERING_MIX = 0.5;
const vec4 NO_CLOUD = vec4(0.0, 0.0, 0.0, 1.0);
const vec4 STRATUS_GRADIENT = vec4(0.02f, 0.05f, 0.09f, 0.11f);
const vec4 STRATOCUMULUS_GRADIENT = vec4(0.02f, 0.2f, 0.48f, 0.625f);
const vec4 CUMULUS_GRADIENT = vec4(0.01f, 0.0625f, 0.78f, 1.0f);
#define MAX_MARCHING_STEPS 256
#define CLOUD_START_ALT 1500.0
#define CLOUD_END_ALT 3000.0
uniform float BASE_SCALE;
uniform float EROSION_SCALE;
uniform float CLOUD_DENSITY; // 0.04
uniform float CLOUD_EROSION_STRENGTH; // 0.2
uniform float CLOUD_EROSION_STRENGTH;
uniform float test_value;
uniform sampler2D color_tex;
uniform sampler2D noise_base_tex;
uniform sampler2D noise_erosion_tex;
uniform unsigned int osg_FrameNumber;
uniform vec2 fg_ViewportSize;
uniform vec3 fg_CameraPositionCart;
uniform vec3 fg_CameraPositionGeod;
uniform vec3 fg_LightDirection;
uniform mat4 fg_PrevViewMatrix;
uniform mat4 fg_PrevViewMatrixInverse;
uniform mat4 fg_PrevProjectionMatrix;
uniform mat4 fg_ViewMatrix;
uniform mat4 fg_ViewMatrixInverse;
uniform mat4 fg_ProjectionMatrixInverse;
uniform vec3 fg_LightDirection;
uniform sampler2D prevframe_tex;
uniform sampler2D depth_tex;
uniform sampler3D noise_base_tex;
uniform sampler3D noise_erosion_tex;
uniform float avisibility;
uniform float cloud_self_shading;
uniform float eye_alt;
uniform float ground_scattering;
uniform float hazeLayerAltitude;
uniform float moonlight;
uniform float overcast;
uniform float scattering;
uniform float terminator;
uniform float terrain_alt;
uniform float visibility;
uniform float air_pollution;
uniform float snowlevel;
uniform float snow_thickness_factor;
// constants needed by the light and fog computations ##########################
const float EarthRadius = 5800000.0;
const float terminator_width = 200000.0;
vec4 cloudPositionWorldSpace;
////////////////////////////////////////////////////////////////////////////////
float Noise2D(in vec2 coord, in float wavelength);
float Noise3D(in vec3 coord, in float wavelength);
vec3 rayleigh_out_shift(in vec3 color, in float outscatter);
vec3 get_hazeColor(in float lightArg);
vec3 moonlight_perception(in vec3 light);
////////////////////////////////////////////////////////////////////////////////
// ALS functions
float light_func (in float x, in float a, in float b, in float c, in float d, in float e)
{
if (x > 30.0) {return e;}
if (x < -15.0) {return 0.0;}
return e / pow((1.0 + a * exp(-b * (x-c)) ),(1.0/d));
}
void getALSLight(in vec3 pos, out vec3 ambient, out vec3 diffuse)
{
vec3 shadedFogColor = vec3(0.55, 0.67, 0.88);
vec3 moonLightColor = vec3 (0.095, 0.095, 0.15) * moonlight;
vec3 lightHorizon = fg_LightDirection - normalize(pos) *
dot(normalize(pos), fg_LightDirection);
float yprime = -dot(pos, lightHorizon);
float yprime_alt = yprime - sqrt(2.0 * EarthRadius * eye_alt);
float lightArg = (terminator-yprime_alt)/100000.0;
float earthShade = 0.6 * (1.0 - smoothstep(-terminator_width + terminator, terminator_width + terminator, yprime_alt)) + 0.4;
vec3 light_diffuse;
vec3 light_ambient;
float intensity;
light_diffuse.b = light_func(lightArg, 1.330e-05, 0.264, 2.227, 1.08e-05, 1.0);
light_diffuse.g = light_func(lightArg, 3.931e-06, 0.264, 3.827, 7.93e-06, 1.0);
light_diffuse.r = light_func(lightArg, 8.305e-06, 0.161, 3.827, 3.04e-05, 1.0);
light_ambient.r = light_func(lightArg, 0.236, 0.253, 1.073, 0.572, 0.33);
light_ambient.g = light_ambient.r * 0.4/0.33;
light_ambient.b = light_ambient.r * 0.5/0.33;
if (earthShade < 0.5) {
intensity = length(light_ambient.rgb);
light_ambient.rgb = intensity *
normalize(mix(light_ambient.rgb, shadedFogColor,
1.0 - smoothstep(0.1,0.8, earthShade) ));
light_ambient.rgb = light_ambient.rgb + moonLightColor *
(1.0 - smoothstep(0.4, 0.5, earthShade));
intensity = length(light_diffuse.rgb);
light_diffuse.rgb = intensity *
normalize(mix(light_diffuse.rgb, shadedFogColor,
(1.0 - smoothstep(0.5,0.9, cloud_self_shading))));
}
ambient = light_ambient;
diffuse = light_diffuse;
}
////////////////////////////////////////////////////////////////////////////////
// General utility functions
float map(float s, float a1, float a2, float b1, float b2)
{
return b1+(s-a1)*(b2-b1)/(a2-a1);
}
vec3 getAmbientLight(float altitude)
vec2 cartToGeoc(vec3 cart)
{
// TODO: Actually return the cloud ambient light for this altitude
return mix(vec3(39.0, 67.0, 87.0) * (1.5/255.0),
vec3(149.0, 167.0, 200.0) * (1.5/255.0),
altitude);
vec2 geoc = vec2(0.0);
geoc.x = atan(cart.y, cart.x);
float nxy = sqrt(cart.x*cart.x + cart.y*cart.y);
geoc.y = atan(cart.z, nxy);
return geoc;
}
vec3 getFragmentWorldPos(vec2 uv)
{
vec3 posCS = vec3(uv, texture2D(depth_tex, uv).r) * 2.0 - 1.0;
vec4 pos = fg_ViewMatrixInverse * fg_ProjectionMatrixInverse *
vec4(posCS, 1.0);
return pos.xyz / pos.w;
}
////////////////////////////////////////////////////////////////////////////////
// Henyey-Greenstein phase function is used instead of the much more complicated
// Mie phase function to approximate the angular distribution of scattered light
float HenyeyGreenstein(float costheta, float g)
@ -49,146 +167,163 @@ float HenyeyGreenstein(float costheta, float g)
return (1.0 - gg) * pow(1.0 + gg - 2.0 * g * costheta, -1.5) * 0.25;
}
// Placeholder function to read a tiled 2D texture as a 3D texture
float sampleNoiseTexture(sampler2D tex, vec3 p, float size)
vec3 getAmbientLight(float altitude)
{
float xoffset = mod(p.z, size) * size;
float x = mod(p.x, size);
float y = mod(p.y, size);
vec2 uv = vec2(xoffset + x, y);
// TODO: Actually return the cloud ambient light for this altitude
return mix(
vec3(0.5f, 0.67f, 0.82f),
vec3(1.0f, 1.0f, 1.0f),
altitude);
}
return texture2D(tex, uv).r;
float densityHeightGradient(float heightFrac, float cloudType)
{
float stratus = 1.0 - clamp(cloudType * 2.0, 0.0, 1.0);
float stratocumulus = 1.0 - abs(cloudType - 0.5) * 2.0;
float cumulus = clamp(cloudType - 0.5, 0.0, 1.0) * 2.0;
vec4 cloudGradient =
STRATUS_GRADIENT * stratus +
STRATOCUMULUS_GRADIENT * stratocumulus +
CUMULUS_GRADIENT * cumulus;
return smoothstep(cloudGradient.x, cloudGradient.y, heightFrac) -
smoothstep(cloudGradient.z, cloudGradient.w, heightFrac);
}
// Get the cloud density in a given sky position and altitude
float getDensity(vec3 pos, float alt)
float sampleDensity(vec3 pos, float alt)
{
// Get the low frequency noise that defines the base shape of the cloud
float lowFreqNoise = sampleNoiseTexture(noise_base_tex, pos / BASE_SCALE, 128.0);
float baseCloud = texture3D(noise_base_tex, pos / BASE_SCALE).r;
// Modulate the noise by a coverage value (this could be a CPU generated
// Calculate the cloud coverage value (this could be a CPU generated
// weather texture instead)
float coverage = Noise3D(pos, 10000.0) * 0.625 +
Noise3D(pos, 5000.0) * 0.250 +
Noise3D(pos, 2500.0) * 0.125;
coverage = smoothstep(0.6, 0.7, coverage);
vec2 pos2d = cartToGeoc(pos);
float coverage = Noise2D(pos2d, COVERAGE_SCALE) * 0.625 +
Noise2D(pos2d, COVERAGE_SCALE / 2.0) * 0.250 +
Noise2D(pos2d, COVERAGE_SCALE / 4.0) * 0.125;
coverage = smoothstep(0.5, 1.0, coverage);
//coverage *= weather_coverage;
float baseCloud = map(lowFreqNoise, 1.0 - coverage, 1.0, 0.0, 1.0);
baseCloud *= coverage;
float baseCloudWithCoverage = map(baseCloud, 1.0 - coverage, 1.0, 0.0, 1.0);
baseCloudWithCoverage *= coverage;
// Get the height signal
float heightSignal = smoothstep(0.0, 0.1, alt) * (1.0 - smoothstep(0.6, 1.0, alt));
baseCloud *= heightSignal;
baseCloudWithCoverage *= densityHeightGradient(alt, 1.0);
// Apply some erosion to add details
float highFreqNoise = sampleNoiseTexture(noise_erosion_tex, pos / EROSION_SCALE, 32.0);
//float highFreqNoise = 0.0;
float density = map(baseCloud, highFreqNoise * CLOUD_EROSION_STRENGTH, 1.0,
0.0, 1.0);
float highFreqNoise = texture3D(noise_erosion_tex, pos / EROSION_SCALE).r;
float highFreqNoiseModifier = mix(1.0 - highFreqNoise, // whispy
highFreqNoise,
alt);
float density = map(baseCloudWithCoverage,
highFreqNoiseModifier * CLOUD_EROSION_STRENGTH,
1.0, 0.0, 1.0);
return clamp(density * CLOUD_DENSITY, 0.0, 1.0);
return clamp(density, 0.0, 1.0);
}
float shadowing(vec3 pos, float alt, vec3 lightDir)
float sampleDensityAlongLightRay(vec3 p, float alt, vec3 lightDir)
{
float stepDelta = 10.0;
float t = stepDelta;
float shadow = 1.0;
for(int i = 0; i < 6; ++i) {
vec3 samplePoint = pos + lightDir * t;
float density = getDensity(samplePoint, alt);
for(int i = 0; i < LIGHT_MARCHING_STEPS; ++i) {
vec3 samplePoint = p + lightDir * t;
float density = sampleDensity(samplePoint, alt);
shadow *= exp(-density * stepDelta);
stepDelta *= 1.6;
stepDelta *= 1.3;
t += stepDelta;
}
return shadow;
}
vec3 raySphereIntersection(vec3 cameraPos, vec3 direction, float altitude)
vec3 sampleLighting(vec3 p, float alt, vec3 lightDir, float phase)
{
float radius = length(cameraPos) - fg_CameraPositionGeod.z + altitude;
float a = dot(direction, direction) * 2.0;
float b = dot(direction, cameraPos) * 2.0;
float c = dot(cameraPos, cameraPos) - radius * radius;
float discriminant = b * b - 2.0 * a * c;
float t = max(0.0, (-b + sqrt(discriminant)) / a);
vec3 intersection = cameraPos + direction * t;
return intersection;
vec3 ambient, diffuse;
getALSLight(p, ambient, diffuse);
ambient = getAmbientLight(alt);
float shadow = sampleDensityAlongLightRay(p, alt, lightDir);
// float loddedDensity = texture3DLod(noise_base_tex, p / BASE_SCALE, 3.0).r;
// float depthProbability = 0.05 +
// pow(loddedDensity, map(alt, 0.3, 0.85, 0.5, 2.0));
return ambient + diffuse * phase * shadow;
}
vec4 rayMarch(vec3 eye, vec3 dir)
bool rayAtmosphereIntersection(in vec3 ro, in vec3 rd, in float alt,
out float t1, out float t2)
{
vec3 entry;
float dist;
// TODO: make this actually work
if (fg_CameraPositionGeod.z < CLOUD_START_ALT) {
// We are below the clouds
float radius = length(ro) - fg_CameraPositionGeod.z + alt;
float a = dot(rd, rd) * 2.0;
float b = dot(rd, ro) * 2.0;
float c = dot(ro, ro) - radius * radius;
float discriminant = b * b - 2.0 * a * c;
if (discriminant < 0.0)
return false;
// Discard fragments below the horizon
if (dot(normalize(eye), dir) < 0.0)
return vec4(0.0, 0.0, 0.0, 1.0);
t1 = max(0.0, (-b - sqrt(discriminant)) / a);
t2 = max(0.0, (-b + sqrt(discriminant)) / a);
return true;
}
entry = raySphereIntersection(eye, dir, CLOUD_START_ALT);
vec3 exit = raySphereIntersection(eye, dir, CLOUD_END_ALT);
dist = distance(entry, exit);
} else if (fg_CameraPositionGeod.z > CLOUD_END_ALT) {
// We are over the clouds
entry = raySphereIntersection(eye, dir, CLOUD_END_ALT);
vec3 exit = raySphereIntersection(eye, dir, CLOUD_START_ALT);
dist = distance(entry, exit);
} else {
// We are inside the clouds
entry = eye;
vec3 exit = raySphereIntersection(eye, dir, CLOUD_END_ALT);
if (exit == eye)
exit = raySphereIntersection(eye, dir, CLOUD_START_ALT);
dist = max(distance(entry, exit), 2000.0);
}
float radicalInverse_VdC(unsigned int bits)
{
bits = (bits << 16u) | (bits >> 16u);
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
}
float t = 0.0;
float stepDelta = dist / float(MAX_MARCHING_STEPS);
vec4 rayMarch(vec3 ro, vec3 rd, float depth, vec3 fragWorldPos)
{
vec3 lightDir = normalize(fg_LightDirection);
float costheta = dot(rd, lightDir);
vec3 lightDir = fg_LightDirection;
float costheta = dot(dir, lightDir);
float phase = mix(HenyeyGreenstein(costheta, FORWARD_SCATTERING),
HenyeyGreenstein(costheta, BACKWARD_SCATTERING),
SCATTERING_MIX);
phase = clamp(phase, 0.0, 1.0);
float phase = mix(HenyeyGreenstein(costheta, 0.8),
HenyeyGreenstein(costheta, -0.2),
0.5);
float stepDelta = depth / float(MAX_MARCHING_STEPS);
float t = stepDelta * radicalInverse_VdC(osg_FrameNumber);
// The RGB part contains the scattered light color and the alpha value contains
// the transmittance, both along the ray
vec4 result = vec4(0.0, 0.0, 0.0, 1.0);
for (int i = 0; i < MAX_MARCHING_STEPS; ++i) {
vec3 samplePoint = entry + dir * t;
vec3 samplePoint = ro + rd * t;
// Skip samples behind other objects
float fragToCamera = distance(fragWorldPos, fg_CameraPositionCart);
float sampleToCamera = distance(samplePoint, fg_CameraPositionCart);
if (fragToCamera < sampleToCamera)
continue;
float earthRadius = length(fg_CameraPositionCart) - fg_CameraPositionGeod.z;
float altitude = length(samplePoint) - earthRadius;
float normalizedAlt = clamp((altitude - CLOUD_START_ALT) /
(CLOUD_END_ALT - CLOUD_START_ALT), 0.0, 1.0);
float density = getDensity(samplePoint, normalizedAlt);
float density = sampleDensity(samplePoint, normalizedAlt);
// Only evaluate lighting for samples inside clouds
if (density > 0.0) {
vec3 ambient = getAmbientLight(normalizedAlt);
float transmittance = exp(-density * stepDelta);
// Analytical integration of BeerLamberts law to calculate
// transmittance
vec3 S = (ambient + (phase * shadowing(samplePoint, normalizedAlt, lightDir))) * density;
//float transmittance = exp(-density * stepDelta);
float transmittance = max(exp(-density * stepDelta), (exp(-density * stepDelta * 0.25) * 0.7));
vec3 S = sampleLighting(samplePoint, normalizedAlt, lightDir, phase)
* density;
vec3 Sint = (S - S * transmittance) / density;
result.rgb += result.a * Sint;
result.a *= transmittance;
}
if (result.a <= 0.1)
// Early exit if we reached maximum density
if (result.a < 0.01)
break;
t += stepDelta;
@ -197,18 +332,113 @@ vec4 rayMarch(vec3 eye, vec3 dir)
return result;
}
vec4 getCloudColor(vec3 rd)
{
vec3 ro = fg_CameraPositionCart;
vec3 entry = vec3(0.0);
float depth = 0.0;
float t1 = 0.0, t2 = 0.0;
if (fg_CameraPositionGeod.z < CLOUD_START_ALT) {
// We are below the clouds
// Discard fragments below the horizon
if (dot(normalize(ro), rd) < 0.0)
return NO_CLOUD;
rayAtmosphereIntersection(ro, rd, CLOUD_START_ALT, t1, t2);
entry = ro + rd * t2;
rayAtmosphereIntersection(ro, rd, CLOUD_END_ALT, t1, t2);
vec3 exit = ro + rd * t2;
depth = distance(entry, exit);
} else if (fg_CameraPositionGeod.z > CLOUD_END_ALT) {
// We are over the clouds
if (!rayAtmosphereIntersection(ro, rd, CLOUD_END_ALT, t1, t2))
return NO_CLOUD;
entry = ro + rd * t1;
if (rayAtmosphereIntersection(ro, rd, CLOUD_START_ALT, t1, t2)) {
vec3 exit = ro + rd * t1;
depth = distance(entry, exit);
} else {
// We didn't intersect with the inner bound, use a fixed cloud depth
depth = CUTOFF_DISTANCE;
}
} else {
// We are inside the clouds
entry = ro;
vec3 exit;
if (!rayAtmosphereIntersection(ro, rd, CLOUD_END_ALT, t1, t2)) {
rayAtmosphereIntersection(ro, rd, CLOUD_START_ALT, t1, t2);
exit = ro + rd * t2;
} else {
exit = ro + rd * t1;
}
depth = max(distance(entry, exit), CUTOFF_DISTANCE);
}
cloudPositionWorldSpace = vec4(entry, 1.0);
vec3 fragWorldPos = getFragmentWorldPos(gl_TexCoord[0].st);
return rayMarch(entry, rd, depth, fragWorldPos);
}
const unsigned int bayerMatrix4[16] = unsigned int[](
0, 8, 2, 10,
12, 4, 14, 6,
3, 11, 1, 9,
15, 7, 13, 5
);
void main()
{
vec2 uv = gl_FragCoord.xy / fg_ViewportSize;
vec2 uv = gl_TexCoord[0].st;
vec2 rayNDS = uv * 2.0 - 1.0;
vec4 rayCS = vec4(rayNDS, -1.0, 1.0);
vec4 rayVS = fg_ProjectionMatrixInverse * rayCS;
rayVS = vec4(rayVS.xy, -1.0, 0.0);
vec3 rayWS = normalize(fg_ViewMatrixInverse * rayVS).xyz;
vec4 rayWS = fg_ViewMatrixInverse * rayVS;
vec3 rayWSNorm = normalize(rayWS).xyz;
vec4 cloudColor = rayMarch(fg_CameraPositionCart, rayWS);
vec3 backgroundColor = texture2D(color_tex, uv).xyz;
//vec3 backgroundColor = texture2D(color_tex, uv).xyz;
gl_FragColor = vec4(cloudColor.rgb + backgroundColor.rgb * cloudColor.a, 1.0);
vec4 fragColor;
vec4 cloudColor = getCloudColor(rayWSNorm);
vec4 rayPrime = fg_PrevProjectionMatrix * fg_PrevViewMatrix *
cloudPositionWorldSpace;
rayPrime /= rayPrime.w;
vec2 prev_uv = rayPrime.xy * 0.5 + 0.5;
vec4 prevColor = texture2D(prevframe_tex, prev_uv);
vec3 fragViewSpacePos = (fg_ViewMatrix * vec4(getFragmentWorldPos(gl_TexCoord[0].st), 1.0)).xyz;
bool isOut = any(greaterThan(abs(prev_uv - 0.5), vec2(0.5)));
const float alpha = 0.1;
if (isOut || fragViewSpacePos.z > -500.0) {
fragColor = cloudColor;
} else {
fragColor = cloudColor * alpha + prevColor * (1.0 - alpha);
}
// vec2 pixel = gl_TexCoord[0].st * fg_ViewportSize;
// unsigned int bayerIndex = unsigned int(mod(pixel.x*pixel.y, 16));
// if (unsigned int(mod(float(osg_FrameNumber), 16)) != bayerMatrix4[bayerIndex]) {
// // It's NOT the time to render clouds
// vec4 rayPrime = fg_PrevProjectionMatrix * fg_PrevViewMatrix * rayWS;
// vec2 prev_uv = rayPrime.xy * 0.5 + 0.5;
// vec4 prevColor = texture2D(prevframe_tex, prev_uv);
// //vec2 haveInfo = step(vec2(0.0), prev_uv) - step(vec2(1.0), prev_uv);
// //fragColor = mix(vec4(0.0, 0.0, 0.0, 1.0), prevColor, haveInfo.x*haveInfo.y);
// fragColor = prevColor;
// } else {
// vec4 cloudColor = getCloudColor(rayWSNorm);
// fragColor = cloudColor;
// }
// TEMPORAL
//fragColor = mix(backgroundColor, prevColor, haveInfo.x*haveInfo.y);
// CURRENT
//fragColor = cloudColor.rgb + backgroundColor.rgb * cloudColor.a;
gl_FragColor = fragColor;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 974 KiB

After

Width:  |  Height:  |  Size: 975 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 22 KiB