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

128 lines
4.7 KiB
Plaintext

// what the cpu needs from the atmosphere, worked out from the sky-view table in one work group: the light arriving at the
// observer from every direction as spherical harmonics (the ground below the horizon lit by the sun and the sky), the
// transmittance towards the sun, and the average light of the sky above the horizon and over the whole sky.
// run after the sky-view table; the result is read back by the cpu a few frames later
#include <common>
#include <atmosphere_common.glsl>
layout(binding = ATMOSPHERE_TRANSMITTANCE_UNIT) uniform sampler2D atmo_transmittance_lut;
layout(binding = ATMOSPHERE_SKYVIEW_UNIT) uniform sampler2D atmo_skyview_lut;
layout(local_size_x = ATMOSPHERE_AMBIENT_GROUP_SIZE) in;
layout(std430, binding = ATMOSPHERE_RESULT_SSBO_BINDING) writeonly buffer atmosphere_result_ssbo
{
vec4 result_radiance_sh[9];
vec4 result_sun_transmittance;
vec4 result_horizon;
vec4 result_average;
vec4 result_zenith_transmittance;
};
// directions of the upper hemisphere each invocation takes
const uint DIRECTIONS_PER_INVOCATION = 4U;
const uint DIRECTIONS = ATMOSPHERE_AMBIENT_GROUP_SIZE * DIRECTIONS_PER_INVOCATION;
// the sky up to this sine of the elevation is the horizon (about 6 degrees)
const float HORIZON_BAND = 0.1;
// partial sums: the 9 coefficients, the light on an upward facing surface, the horizon and its weight, the sky average
const int SUMS = 12;
shared vec4 shared_sums[ATMOSPHERE_AMBIENT_GROUP_SIZE];
void sh_basis(vec3 n, out float basis[9])
{
basis[0] = 0.282095;
basis[1] = 0.488603 * n.y;
basis[2] = 0.488603 * n.z;
basis[3] = 0.488603 * n.x;
basis[4] = 1.092548 * n.x * n.y;
basis[5] = 1.092548 * n.y * n.z;
basis[6] = 0.315392 * (3.0 * n.z * n.z - 1.0);
basis[7] = 1.092548 * n.x * n.z;
basis[8] = 0.546274 * (n.x * n.x - n.y * n.y);
}
// sum of the value of every invocation, valid in invocation 0
vec4 reduce(vec4 value)
{
uint index = gl_LocalInvocationID.x;
barrier();
shared_sums[index] = value;
barrier();
for (uint stride = ATMOSPHERE_AMBIENT_GROUP_SIZE / 2U; stride > 0U; stride >>= 1)
{
if (index < stride)
shared_sums[index] += shared_sums[index + stride];
barrier();
}
return shared_sums[0];
}
void main()
{
uint index = gl_LocalInvocationID.x;
vec3 sundirection = normalize(atmo_sun_direction.xyz);
vec3 sums[SUMS];
for (int i = 0; i < SUMS; ++i)
sums[i] = vec3(0.0);
// even spread over the upper hemisphere: a fibonacci spiral in the sine of the elevation
const float goldenangle = 2.39996323;
const float solidangle = 2.0 * ATMO_PI / float(DIRECTIONS);
for (uint k = 0U; k < DIRECTIONS_PER_INVOCATION; ++k)
{
uint i = index * DIRECTIONS_PER_INVOCATION + k;
float y = (float(i) + 0.5) / float(DIRECTIONS);
float r = sqrt(max(1.0 - y * y, 0.0));
float azimuth = goldenangle * float(i);
vec3 direction = vec3(r * cos(azimuth), y, r * sin(azimuth));
vec3 radiance = textureLod(atmo_skyview_lut, atmo_skyview_uv_world(direction, sundirection), 0.0).rgb;
float basis[9];
sh_basis(direction, basis);
for (int c = 0; c < 9; ++c)
sums[c] += radiance * (basis[c] * solidangle);
sums[9] += radiance * (y * solidangle);
if (y < HORIZON_BAND)
{
sums[10] += radiance;
sums[11] += vec3(1.0);
}
}
vec3 total[SUMS];
for (int i = 0; i < SUMS; ++i)
total[i] = reduce(vec4(sums[i], 0.0)).rgb;
if (index != 0U)
return;
// the transmittance towards the sun, zero once the planet is in the way
float radius = atmo_observer_radius;
vec3 origin = vec3(0.0, radius, 0.0);
vec3 suntransmittance = texture(atmo_transmittance_lut, atmo_transmittance_uv(radius, sundirection.y)).rgb;
if (atmo_ray_sphere_nearest(origin, sundirection, atmo_bottom_radius) >= 0.0)
suntransmittance = vec3(0.0);
// the ground, a lambertian surface lit by the sun and the sky, fills the lower hemisphere with uniform light. its
// spherical harmonics have only the constant term and the vertical one: for a uniform radiance L over the lower
// hemisphere, 0.282095 * 2 pi * L and 0.488603 * (-pi) * L
// the band 0 coefficient of the sky alone over the solid angle of the hemisphere
vec3 skyaverage = total[0] / (0.282095 * 2.0 * ATMO_PI);
vec3 irradiance = suntransmittance * max(sundirection.y, 0.0) + total[9];
vec3 groundradiance = atmo_ground.rgb / ATMO_PI * irradiance;
total[0] += groundradiance * (0.282095 * 2.0 * ATMO_PI);
total[1] += groundradiance * (0.488603 * -ATMO_PI);
for (int c = 0; c < 9; ++c)
result_radiance_sh[c] = vec4(total[c], 0.0);
result_sun_transmittance = vec4(suntransmittance, 0.0);
result_horizon = vec4(total[10] / max(total[11].x, 1.0), 0.0);
result_average = vec4(skyaverage, 0.0);
// what the sun high in the sky looks like at the observer, for the white balance
result_zenith_transmittance = vec4(texture(atmo_transmittance_lut, atmo_transmittance_uv(radius, 1.0)).rgb, 0.0);
}