[Add] Atmospheric scattering and improved clouds.
This commit is contained in:
parent
19a431ccc8
commit
95134c91d8
@ -4,30 +4,82 @@ out vec4 FragColor;
|
|||||||
in vec3 TexCoords;
|
in vec3 TexCoords;
|
||||||
|
|
||||||
uniform sampler2D u_CloudTexture;
|
uniform sampler2D u_CloudTexture;
|
||||||
uniform vec3 u_LightDir;
|
uniform vec3 u_SunPos;
|
||||||
|
|
||||||
const float PI = 3.14159265359;
|
const float PI = 3.14159265359;
|
||||||
|
|
||||||
|
/* Atmosphere parameters. */
|
||||||
|
const float ATMOSPHERE_RADIUS = 6520275.0;
|
||||||
|
const float PLANET_RADIUS = 6371000.0;
|
||||||
|
const float RAYLEIGH_SCALE_HEIGHT = 8000.0;
|
||||||
|
const float MIE_SCALE_HEIGHT = 1200.0;
|
||||||
|
|
||||||
|
/* Scattering coefficients. */
|
||||||
|
const vec3 RAYLEIGH_SCATTERING_COEFF = vec3(0.0000058, 0.0000135, 0.0000331);
|
||||||
|
const vec3 MIE_SCATTERING_COEFF = vec3(0.00002);
|
||||||
|
|
||||||
|
/* Mie scattering parameters. */
|
||||||
|
const float MIE_G = 0.76;
|
||||||
|
|
||||||
|
/* Number of samples for ray marching. */
|
||||||
|
const int SAMPLES = 16;
|
||||||
|
const int LIGHT_SAMPLES = 8;
|
||||||
|
|
||||||
|
float ray_sphere_intersect(vec3 origin, vec3 dir, float radius) {
|
||||||
|
float a = dot(dir, dir);
|
||||||
|
float b = 2.0 * dot(origin, dir);
|
||||||
|
float c = dot(origin, origin) - radius * radius;
|
||||||
|
float d = b * b - 4.0 * a * c;
|
||||||
|
if (d < 0.0) {
|
||||||
|
return -1.0;
|
||||||
|
}
|
||||||
|
return (-b + sqrt(d)) / (2.0 * a);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 get_sky_color(vec3 dir) {
|
||||||
|
vec3 eye = vec3(0.0, PLANET_RADIUS + 1.0, 0.0);
|
||||||
|
float dist = ray_sphere_intersect(eye, dir, ATMOSPHERE_RADIUS);
|
||||||
|
vec3 totalRayleigh = vec3(0.0);
|
||||||
|
vec3 totalMie = vec3(0.0);
|
||||||
|
float stepSize = dist / float(SAMPLES);
|
||||||
|
for (int i = 0; i < SAMPLES; i++) {
|
||||||
|
vec3 p = eye + dir * (float(i) + 0.5) * stepSize;
|
||||||
|
float h = length(p) - PLANET_RADIUS;
|
||||||
|
float rayleighDensity = exp(-h / RAYLEIGH_SCALE_HEIGHT);
|
||||||
|
float mieDensity = exp(-h / MIE_SCALE_HEIGHT);
|
||||||
|
float lightDist = ray_sphere_intersect(p, normalize(u_SunPos), ATMOSPHERE_RADIUS);
|
||||||
|
float lightStepSize = lightDist / float(LIGHT_SAMPLES);
|
||||||
|
float opticalDepthLight = 0.0;
|
||||||
|
for (int j = 0; j < LIGHT_SAMPLES; j++) {
|
||||||
|
vec3 lp = p + normalize(u_SunPos) * (float(j) + 0.5) * lightStepSize;
|
||||||
|
float lh = length(lp) - PLANET_RADIUS;
|
||||||
|
opticalDepthLight += exp(-lh / RAYLEIGH_SCALE_HEIGHT) * lightStepSize;
|
||||||
|
}
|
||||||
|
vec3 transmittance = exp(-(opticalDepthLight * RAYLEIGH_SCATTERING_COEFF
|
||||||
|
+ opticalDepthLight * MIE_SCATTERING_COEFF));
|
||||||
|
totalRayleigh += rayleighDensity * stepSize * transmittance;
|
||||||
|
totalMie += mieDensity * stepSize * transmittance;
|
||||||
|
}
|
||||||
|
|
||||||
|
float mu = dot(dir, normalize(u_SunPos));
|
||||||
|
float rayleighPhase = 3.0 / (16.0 * PI) * (1.0 + mu * mu);
|
||||||
|
float miePhase = 3.0 / (8.0 * PI) * ((1.0 - MIE_G * MIE_G)
|
||||||
|
* (1.0 + mu * mu)) / ((2.0 + MIE_G * MIE_G) * pow(1.0 + MIE_G
|
||||||
|
* MIE_G - 2.0 * MIE_G * mu, 1.5));
|
||||||
|
return 20.0 * (totalRayleigh * RAYLEIGH_SCATTERING_COEFF * rayleighPhase
|
||||||
|
+ totalMie * MIE_SCATTERING_COEFF * miePhase);
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
/* Convert 3D texture coords to 2D using spherical mapping. */
|
|
||||||
float u = atan(TexCoords.z, TexCoords.x) / (2.0 * PI) + 0.5;
|
float u = atan(TexCoords.z, TexCoords.x) / (2.0 * PI) + 0.5;
|
||||||
float v = asin(TexCoords.y) / PI + 0.5;
|
float v = asin(TexCoords.y) / PI + 0.5;
|
||||||
|
float cloudAlpha = texture(u_CloudTexture, vec2(u,v)).r;
|
||||||
|
|
||||||
/* Sample noise value from cloud texture. */
|
vec3 skyColor = get_sky_color(normalize(TexCoords));
|
||||||
float noise = texture(u_CloudTexture, vec2(u, v)).r;
|
vec3 cloudColor = mix(skyColor, vec3(1.0), smoothstep(0.5, 0.8, cloudAlpha));
|
||||||
|
|
||||||
/* Create soft-edged clouds from the noise. */
|
|
||||||
float cloudAlpha = smoothstep(0.5, 0.8, noise);
|
|
||||||
|
|
||||||
/* Some simple lighting. */
|
|
||||||
vec3 normal = normalize(TexCoords);
|
|
||||||
float diffuse = max(dot(normal, -u_LightDir), 0.0);
|
|
||||||
vec3 cloudColor = vec3(1.0) * (diffuse * 0.5 + 0.5); /* Add some ambient light. */
|
|
||||||
|
|
||||||
/* Fade out clouds at the poles to hide pinching. */
|
|
||||||
float poleFade = 1.0 - abs(TexCoords.y);
|
float poleFade = 1.0 - abs(TexCoords.y);
|
||||||
cloudAlpha *= smoothstep(0.0, 0.2, poleFade);
|
float finalAlpha = smoothstep(0.0, 0.2, poleFade) * smoothstep(0.5, 0.8, cloudAlpha);
|
||||||
|
|
||||||
/* Cloud colour is white. it's transparency is determined by alpha. */
|
FragColor = vec4(pow(cloudColor, vec3(1.0/2.2)), finalAlpha);
|
||||||
FragColor = vec4(cloudColor, cloudAlpha);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,80 @@
|
|||||||
#version 330 core
|
#version 330 core
|
||||||
out vec4 FragColor;
|
out vec4 FragColor;
|
||||||
|
|
||||||
in vec3 WorldPos;
|
in vec3 v_WorldPos;
|
||||||
|
|
||||||
|
uniform vec3 u_SunPos;
|
||||||
|
|
||||||
|
const float PI = 3.14159265359;
|
||||||
|
|
||||||
|
/* Atmosphere parameters. */
|
||||||
|
const float ATMOSPHERE_RADIUS = 6520275.0;
|
||||||
|
const float PLANET_RADIUS = 6371000.0;
|
||||||
|
const float RAYLEIGH_SCALE_HEIGHT = 8000.0;
|
||||||
|
const float MIE_SCALE_HEIGHT = 1200.0;
|
||||||
|
|
||||||
|
/* Scattering coefficients. */
|
||||||
|
const vec3 RAYLEIGH_SCATTERING_COEFF = vec3(0.0000058, 0.0000135, 0.0000331);
|
||||||
|
const vec3 MIE_SCATTERING_COEFF = vec3(0.00002);
|
||||||
|
|
||||||
|
/* Mie scattering parameters. */
|
||||||
|
const float MIE_G = 0.76;
|
||||||
|
|
||||||
|
/* Number of samples for ray marching. */
|
||||||
|
const int SAMPLES = 16;
|
||||||
|
const int LIGHT_SAMPLES = 8;
|
||||||
|
|
||||||
|
float ray_sphere_intersect(vec3 origin, vec3 dir, float radius) {
|
||||||
|
float a = dot(dir, dir);
|
||||||
|
float b = 2.0 * dot(origin, dir);
|
||||||
|
float c = dot(origin, origin) - radius * radius;
|
||||||
|
float d = b * b - 4.0 * a * c;
|
||||||
|
if (d < 0.0) {
|
||||||
|
return -1.0;
|
||||||
|
}
|
||||||
|
return (-b + sqrt(d)) / (2.0 * a);
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
/* Define colours for the top and bottom of the sky. */
|
vec3 dir = normalize(v_WorldPos);
|
||||||
vec3 zenithColor = vec3(0.3, 0.5, 0.8);
|
vec3 eye = vec3(0.0, PLANET_RADIUS + 1.0, 0.0);
|
||||||
vec3 horizonColor = vec3(0.7, 0.85, 1.0);
|
|
||||||
|
|
||||||
float blendFactor = (normalize(WorldPos).y + 1.0) / 2.0;
|
float dist = ray_sphere_intersect(eye, dir, ATMOSPHERE_RADIUS);
|
||||||
|
|
||||||
/* Blend the two colours. */
|
vec3 totalRayleigh = vec3(0.0);
|
||||||
vec3 finalColor = mix(horizonColor, zenithColor, blendFactor);
|
vec3 totalMie = vec3(0.0);
|
||||||
|
|
||||||
FragColor = vec4(finalColor, 1.0);
|
float stepSize = dist / float(SAMPLES);
|
||||||
|
for(int i = 0; i < SAMPLES; i++) {
|
||||||
|
vec3 p = eye + dir * (float(i) + 0.5) * stepSize;
|
||||||
|
float h = length(p) - PLANET_RADIUS;
|
||||||
|
|
||||||
|
float rayleighDensity = exp(-h / RAYLEIGH_SCALE_HEIGHT);
|
||||||
|
float mieDensity = exp(-h / MIE_SCALE_HEIGHT);
|
||||||
|
|
||||||
|
float lightDist = ray_sphere_intersect(p, normalize(u_SunPos), ATMOSPHERE_RADIUS);
|
||||||
|
float lightStepSize = lightDist / float(LIGHT_SAMPLES);
|
||||||
|
float opticalDepthLight = 0.0;
|
||||||
|
for(int j = 0; j < LIGHT_SAMPLES; j++) {
|
||||||
|
vec3 lp = p + normalize(u_SunPos) * (float(j) + 0.5) * lightStepSize;
|
||||||
|
float lh = length(lp) - PLANET_RADIUS;
|
||||||
|
opticalDepthLight += exp(-lh / RAYLEIGH_SCALE_HEIGHT) * lightStepSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 transmittance = exp(-(opticalDepthLight * RAYLEIGH_SCATTERING_COEFF
|
||||||
|
+ opticalDepthLight * MIE_SCATTERING_COEFF));
|
||||||
|
totalRayleigh += rayleighDensity * stepSize * transmittance;
|
||||||
|
totalMie += mieDensity * stepSize * transmittance;
|
||||||
|
}
|
||||||
|
|
||||||
|
float mu = dot(dir, normalize(u_SunPos));
|
||||||
|
float rayleighPhase = 3.0 / (16.0 * PI) * (1.0 + mu * mu);
|
||||||
|
float miePhase = 3.0 / (8.0 * PI) * ((1.0 - MIE_G * MIE_G)
|
||||||
|
* (1.0 + mu * mu)) / ((2.0 + MIE_G * MIE_G)
|
||||||
|
* pow(1.0 + MIE_G * MIE_G - 2.0 * MIE_G * mu, 1.5));
|
||||||
|
|
||||||
|
vec3 finalColor = 20.0 * (totalRayleigh * RAYLEIGH_SCATTERING_COEFF
|
||||||
|
* rayleighPhase + totalMie * MIE_SCATTERING_COEFF * miePhase);
|
||||||
|
|
||||||
|
FragColor = vec4(pow(finalColor, vec3(1.0/2.2)), 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,13 @@
|
|||||||
#version 330 core
|
#version 330 core
|
||||||
layout (location = 0) in vec3 aPos;
|
layout (location = 0) in vec3 aPos;
|
||||||
|
|
||||||
out vec3 WorldPos;
|
|
||||||
|
|
||||||
uniform mat4 view;
|
uniform mat4 view;
|
||||||
uniform mat4 projection;
|
uniform mat4 projection;
|
||||||
|
|
||||||
void main() {
|
out vec3 v_WorldPos;
|
||||||
WorldPos = aPos;
|
|
||||||
|
|
||||||
/* Force depth value to 1.0 after perspective division
|
void main() {
|
||||||
* to ensure the skybox is always rendered behind everythig else.
|
v_WorldPos = aPos;
|
||||||
*/
|
vec4 pos = projection * view * vec4(aPos, 1.0);
|
||||||
vec4 pos = projection * view * vec4(WorldPos, 1.0);
|
|
||||||
gl_Position = pos.xyww;
|
gl_Position = pos.xyww;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -265,6 +265,7 @@ void Renderer::_render_sky(const Camera& camera) {
|
|||||||
|
|
||||||
_sky_shader.set_mat4("view", view);
|
_sky_shader.set_mat4("view", view);
|
||||||
_sky_shader.set_mat4("projection", _projection);
|
_sky_shader.set_mat4("projection", _projection);
|
||||||
|
_sky_shader.set_vec3("u_SunPos", {0.0f, 1.0f, 0.0f});
|
||||||
|
|
||||||
glBindVertexArray(_sky_vao);
|
glBindVertexArray(_sky_vao);
|
||||||
glDrawElements(GL_TRIANGLES, _sky_indices_count, GL_UNSIGNED_INT, 0);
|
glDrawElements(GL_TRIANGLES, _sky_indices_count, GL_UNSIGNED_INT, 0);
|
||||||
@ -288,6 +289,7 @@ void Renderer::_render_clouds(const Camera& camera) {
|
|||||||
_cloud_shader.set_mat4("projection", _projection);
|
_cloud_shader.set_mat4("projection", _projection);
|
||||||
_cloud_shader.set_mat4("view", cloud_view);
|
_cloud_shader.set_mat4("view", cloud_view);
|
||||||
_cloud_shader.set_vec3("u_LightDir", {-0.5f, -1.0f, -0.5f});
|
_cloud_shader.set_vec3("u_LightDir", {-0.5f, -1.0f, -0.5f});
|
||||||
|
_cloud_shader.set_vec3("u_SunPos", {0.0f, 1.0f, 0.0f});
|
||||||
|
|
||||||
glBindVertexArray(_sky_vao);
|
glBindVertexArray(_sky_vao);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user