17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-17 10:59:20 +02:00
Files
maszyna/shaders/atmosphere_multiscattering.comp

70 lines
2.9 KiB
Plaintext

// light scattered more than once, for the multiple scattering table (Hillaire 2020, section 5.5): for a point at a height
// lit by the sun at an angle, the second order scattering from 64 directions around it, summed as a geometric series of
// all the orders. one work group per texel, one invocation per direction. run after the transmittance table
#include <common>
#include <atmosphere_common.glsl>
layout(binding = ATMOSPHERE_TRANSMITTANCE_UNIT) uniform sampler2D atmo_transmittance_lut;
#include <atmosphere_integrate.glsl>
layout(local_size_x = 64) in;
layout(binding = ATMOSPHERE_MULTISCATTERING_UNIT, rgba16f) writeonly uniform image2D multiscattering_target;
const int MULTISCATTERING_SAMPLES = 20;
const int SQRT_DIRECTIONS = 8;
shared vec3 shared_luminance[64];
shared vec3 shared_multiscattering[64];
void main()
{
ivec2 texel = ivec2(gl_WorkGroupID.xy);
uint index = gl_LocalInvocationID.x;
vec2 uv = (vec2(texel) + 0.5) / float(ATMOSPHERE_MULTISCATTERING_SIZE);
uv = vec2(atmo_sub_uv_to_unit(uv.x, float(ATMOSPHERE_MULTISCATTERING_SIZE)), atmo_sub_uv_to_unit(uv.y, float(ATMOSPHERE_MULTISCATTERING_SIZE)));
uv = clamp(uv, 0.0, 1.0);
float cossunzenith = uv.x * 2.0 - 1.0;
vec3 sundirection = vec3(0.0, sqrt(max(1.0 - cossunzenith * cossunzenith, 0.0)), cossunzenith);
float radius = atmo_bottom_radius + clamp(uv.y + 1e-4, 0.0, 1.0) * (atmo_top_radius - atmo_bottom_radius - 1e-3);
vec3 origin = vec3(0.0, 0.0, radius);
// directions spread evenly over the sphere
float a = (0.5 + float(index / uint(SQRT_DIRECTIONS))) / float(SQRT_DIRECTIONS);
float b = (0.5 + float(index % uint(SQRT_DIRECTIONS))) / float(SQRT_DIRECTIONS);
float theta = 2.0 * ATMO_PI * a;
float phi = acos(clamp(1.0 - 2.0 * b, -1.0, 1.0));
vec3 direction = vec3(cos(theta) * sin(phi), sin(theta) * sin(phi), cos(phi));
atmo_scattering_s result = atmo_integrate(origin, direction, sundirection, true, MULTISCATTERING_SAMPLES, false, false);
const float spheresolidangle = 4.0 * ATMO_PI;
const float directions = float(SQRT_DIRECTIONS * SQRT_DIRECTIONS);
shared_luminance[index] = result.luminance * spheresolidangle / directions;
shared_multiscattering[index] = result.multiscattering_as_1 * spheresolidangle / directions;
barrier();
for (uint stride = 32U; stride > 0U; stride >>= 1)
{
if (index < stride)
{
shared_luminance[index] += shared_luminance[index + stride];
shared_multiscattering[index] += shared_multiscattering[index + stride];
}
barrier();
}
if (index != 0U)
return;
const float isotropicphase = 1.0 / spheresolidangle;
vec3 inscatteredluminance = shared_luminance[0] * isotropicphase;
vec3 multiscatteringas1 = shared_multiscattering[0] * isotropicphase;
// every further order of scattering is the previous one times multiscatteringas1
vec3 luminance = inscatteredluminance / max(vec3(1.0) - multiscatteringas1, vec3(1e-3));
imageStore(multiscattering_target, texel, vec4(luminance, 1.0));
}