mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
152 lines
6.5 KiB
HLSL
152 lines
6.5 KiB
HLSL
#ifndef SKY_INSCATTERING_HLSLI
|
|
#define SKY_INSCATTERING_HLSLI
|
|
|
|
/*
|
|
* Buffer B: Sky texture
|
|
*
|
|
* "A Scalable and Production Ready Sky and Atmosphere Rendering Technique"
|
|
* by Sébastien Hillaire (2020).
|
|
*
|
|
* We render the sky to a texture instead of raymarching on the entire screen.
|
|
* This is not very useful in Shadertoy, but very useful for someone looking
|
|
* to implement this on a real application.
|
|
*
|
|
* It is important to note that quality decreases significantly when rendering
|
|
* space views. To avoid this, the compute_inscattering() function can be used
|
|
* directly when rendering to a fullscreen quad.
|
|
*/
|
|
|
|
#include "sky_common.hlsli"
|
|
|
|
void compute_inscattering(Texture2D transmittance_lut, SamplerState lut_sampler, in float molecular_phase, in float aerosol_phase, int steps, float3 ray_origin, float3 ray_dir, float t_min, float t_max, float3 sun_dir, inout float4 L_inscattering, inout float4 transmittance)
|
|
{
|
|
float dt = (t_max - t_min) / float(steps);
|
|
|
|
for (int i = 0; i < steps; ++i) {
|
|
float t = t_min + (float(i) + 0.5) * dt;
|
|
float3 x_t = ray_origin + ray_dir * t;
|
|
|
|
float distance_to_earth_center = length(x_t);
|
|
float3 zenith_dir = x_t / distance_to_earth_center;
|
|
float altitude = distance_to_earth_center - EARTH_RADIUS;
|
|
float normalized_altitude = altitude / ATMOSPHERE_THICKNESS;
|
|
|
|
float sample_cos_theta = dot(zenith_dir, sun_dir);
|
|
|
|
float4 aerosol_absorption, aerosol_scattering;
|
|
float4 molecular_absorption, molecular_scattering;
|
|
float4 fog_scattering;
|
|
float4 extinction;
|
|
get_atmosphere_collision_coefficients(
|
|
altitude,
|
|
aerosol_absorption, aerosol_scattering,
|
|
molecular_absorption, molecular_scattering,
|
|
fog_scattering,
|
|
extinction);
|
|
|
|
float4 transmittance_to_sun = transmittance_from_lut(
|
|
transmittance_lut, lut_sampler, sample_cos_theta, normalized_altitude);
|
|
|
|
float4 ms = get_multiple_scattering(
|
|
transmittance_lut, lut_sampler, sample_cos_theta, normalized_altitude,
|
|
distance_to_earth_center);
|
|
|
|
float4 S = sun_spectral_irradiance *
|
|
(molecular_scattering * (molecular_phase * transmittance_to_sun + ms) +
|
|
(aerosol_scattering + fog_scattering) * (aerosol_phase * transmittance_to_sun + ms));
|
|
|
|
float4 step_transmittance = exp(-dt * extinction);
|
|
|
|
// Energy-conserving analytical integration
|
|
// "Physically Based Sky, Atmosphere and Cloud Rendering in Frostbite"
|
|
// by Sébastien Hillaire
|
|
float4 S_int = (S - S * step_transmittance) / max(extinction, 1e-7);
|
|
L_inscattering += transmittance * S_int;
|
|
transmittance *= step_transmittance;
|
|
}
|
|
}
|
|
|
|
void compute_inscattering_with_cloud_shadow(Texture2D transmittance_lut, Texture2D clouds, SamplerState lut_sampler, in float molecular_phase, in float aerosol_phase, int steps, float3 ray_origin, float3 ray_dir, float t_min, float t_max, float3 sun_dir, inout float4 L_inscattering, inout float4 transmittance)
|
|
{
|
|
float dt = (t_max - t_min) / float(steps);
|
|
|
|
for (int i = 0; i < steps; ++i) {
|
|
float t = t_min + (float(i) + 0.5) * dt;
|
|
float3 x_t = ray_origin + ray_dir * t;
|
|
|
|
float distance_to_earth_center = length(x_t);
|
|
float3 zenith_dir = x_t / distance_to_earth_center;
|
|
float altitude = distance_to_earth_center - EARTH_RADIUS;
|
|
float normalized_altitude = altitude / ATMOSPHERE_THICKNESS;
|
|
|
|
float sample_cos_theta = dot(zenith_dir, sun_dir);
|
|
|
|
float shadow = 1.;
|
|
float c_t = ray_sphere_intersection(ray_dir * t, sun_dir, 10000.);
|
|
if(c_t >= 0.) {
|
|
float3 cloud_dir = normalize(ray_dir * t + sun_dir * c_t);
|
|
cloud_dir.y = 4. * cloud_dir.y;
|
|
cloud_dir = normalize(cloud_dir);
|
|
float4 cloud_mask = clouds.SampleLevel(lut_sampler, cloud_dir.xz * .5 + .5, 0.);
|
|
shadow = min(shadow, 1. - cloud_mask.a * smoothstep(-.01, .01, cloud_dir.y));
|
|
}
|
|
|
|
float4 aerosol_absorption, aerosol_scattering;
|
|
float4 molecular_absorption, molecular_scattering;
|
|
float4 fog_scattering;
|
|
float4 extinction;
|
|
get_atmosphere_collision_coefficients(
|
|
altitude,
|
|
aerosol_absorption, aerosol_scattering,
|
|
molecular_absorption, molecular_scattering,
|
|
fog_scattering,
|
|
extinction);
|
|
|
|
float4 transmittance_to_sun = transmittance_from_lut(
|
|
transmittance_lut, lut_sampler, sample_cos_theta, normalized_altitude) * shadow;
|
|
|
|
float4 ms = get_multiple_scattering(
|
|
transmittance_lut, lut_sampler, sample_cos_theta, normalized_altitude,
|
|
distance_to_earth_center);
|
|
|
|
float4 S = sun_spectral_irradiance *
|
|
(molecular_scattering * (molecular_phase * transmittance_to_sun + ms) +
|
|
(aerosol_scattering + fog_scattering) * (aerosol_phase * transmittance_to_sun + ms));
|
|
|
|
float4 step_transmittance = exp(-dt * extinction);
|
|
|
|
// Energy-conserving analytical integration
|
|
// "Physically Based Sky, Atmosphere and Cloud Rendering in Frostbite"
|
|
// by Sébastien Hillaire
|
|
float4 S_int = (S - S * step_transmittance) / max(extinction, 1e-7);
|
|
L_inscattering += transmittance * S_int;
|
|
transmittance *= step_transmittance;
|
|
}
|
|
}
|
|
|
|
float4 get_inscattering(Texture2D transmittance_lut, SamplerState lut_sampler, int steps, float altitude, float3 ray_dir, float t_min, float t_max, float3 sun_dir) {
|
|
float cos_theta = dot(-ray_dir, sun_dir);
|
|
float molecular_phase = molecular_phase_function(cos_theta);
|
|
float aerosol_phase = aerosol_phase_function(cos_theta);
|
|
|
|
float3 ray_origin = float3(0.0, EARTH_RADIUS + max(altitude, 1.), 0.0);
|
|
float atmos_dist = ray_sphere_intersection(ray_origin, ray_dir, ATMOSPHERE_RADIUS);
|
|
float ground_dist = ray_sphere_intersection(ray_origin, ray_dir, EARTH_RADIUS);
|
|
// We are inside the atmosphere
|
|
if (ground_dist < 0.0) {
|
|
// No ground collision, use the distance to the outer atmosphere
|
|
t_max = min(t_max, atmos_dist);
|
|
} else {
|
|
// We have a collision with the ground, use the distance to it
|
|
t_max = min(t_max, ground_dist);
|
|
}
|
|
|
|
if(t_min >= t_max) return float4(0., 0., 0., 1.);
|
|
|
|
float4 L = 0.;
|
|
float4 transmittance = 1.;
|
|
compute_inscattering(transmittance_lut, lut_sampler, molecular_phase, aerosol_phase, 32, ray_origin, ray_dir, t_min, t_max, sun_dir, L, transmittance);
|
|
return float4(linear_srgb_from_spectral_samples(L) * exp2(EXPOSURE), dot(transmittance, .25));
|
|
}
|
|
|
|
#endif |