17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-28 23:57:28 +01:00
Files
maszyna/shaders/vk14/cabprobe_sh.comp

97 lines
3.6 KiB
Plaintext

#version 460 core
#define STAGE_COMPUTE 1
#define LAYOUT_COMPUTE 1
#include "common.glsl"
// the light the occupied cab lights itself with again, from its probe (gfx::cab_probe), in one work group: the light of its lamps the
// cab reflects towards the middle of its box, as spherical harmonics of bands 0..2, convolved with the cosine lobe and divided by
// pi, so their value for a direction is the light a white lambertian surface facing it gets, in the units of the ambient light
// (light_common.glsl, cab_probe_bounce()). the light is taken from a level of the probe of at most CAB_PROBE_SH_SIZE pixels a
// face, each pixel weighed by its solid angle. the basis is the one of the sky (gl::sky_data)
layout(local_size_x = CAB_PROBE_SH_GROUP_SIZE) in;
layout(set = COMPUTE_SET, binding = 0) uniform samplerCube probe_light;
layout(std430, set = COMPUTE_SET, binding = 1) writeonly buffer cab_probe_result_ssbo
{
vec4 result_sh[9];
};
// the parameters of the kernel (push constants): x the level of the probe read, y its size, pixels
layout(push_constant) uniform kernel_constants
{
ivec2 level;
};
shared vec3 partial[CAB_PROBE_SH_GROUP_SIZE][9];
shared float partialweight[CAB_PROBE_SH_GROUP_SIZE];
// the direction through the middle of the pixel (s, t) of the face, -1..1 across it, in the order of the faces of a cube map
vec3 face_direction(int face, float s, float t)
{
switch (face)
{
case 0: return vec3(1.0, -t, -s);
case 1: return vec3(-1.0, -t, s);
case 2: return vec3(s, 1.0, t);
case 3: return vec3(s, -1.0, -t);
case 4: return vec3(s, -t, 1.0);
default: return vec3(-s, -t, -1.0);
}
}
void main()
{
uint invocation = gl_LocalInvocationID.x;
int size = max(level.y, 1);
int texels = 6 * size * size;
vec3 sum[9];
for (int i = 0; i < 9; ++i)
sum[i] = vec3(0.0);
float weights = 0.0;
for (int index = int(invocation); index < texels; index += CAB_PROBE_SH_GROUP_SIZE)
{
int face = index / (size * size);
int texel = index - face * size * size;
float s = (float(texel % size) + 0.5) / float(size) * 2.0 - 1.0;
float t = (float(texel / size) + 0.5) / float(size) * 2.0 - 1.0;
vec3 direction = face_direction(face, s, t);
// the solid angle of the pixel
float lengthsquared = dot(direction, direction);
float weight = 1.0 / (lengthsquared * sqrt(lengthsquared));
vec3 n = direction * inversesqrt(lengthsquared);
vec3 light = textureLod(probe_light, n, float(level.x)).rgb * weight;
sum[0] += light * 0.282095;
sum[1] += light * (0.488603 * n.y);
sum[2] += light * (0.488603 * n.z);
sum[3] += light * (0.488603 * n.x);
sum[4] += light * (1.092548 * n.x * n.y);
sum[5] += light * (1.092548 * n.y * n.z);
sum[6] += light * (0.315392 * (3.0 * n.z * n.z - 1.0));
sum[7] += light * (1.092548 * n.x * n.z);
sum[8] += light * (0.546274 * (n.x * n.x - n.y * n.y));
weights += weight;
}
for (int i = 0; i < 9; ++i)
partial[invocation][i] = sum[i];
partialweight[invocation] = weights;
barrier();
for (uint stride = CAB_PROBE_SH_GROUP_SIZE / 2; stride > 0U; stride /= 2U)
{
if (invocation < stride)
{
for (int i = 0; i < 9; ++i)
partial[invocation][i] += partial[invocation + stride][i];
partialweight[invocation] += partialweight[invocation + stride];
}
barrier();
}
if (invocation < 9U)
{
// the weights add up to the whole sphere, 4 pi; the cosine lobe over pi: 1 for band 0, 2/3 for band 1, 1/4 for band 2
float sphere = 12.566371 / max(partialweight[0], 1e-6);
float band = (invocation == 0U) ? 1.0 : (invocation < 4U) ? (2.0 / 3.0) : 0.25;
result_sh[invocation] = vec4(partial[0][invocation] * (sphere * band), 0.0);
}
}