[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