Files

54 lines
1.9 KiB
Plaintext

layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
// Binding for the input skybox cubemap.
layout(set = 0, binding = 0) uniform samplerCube uSkybox;
// Binding for the output irradiance (diffuse) cube map stored as a 2D array (each layer is one face).
#ifdef SHADER_STORAGE_IMAGE_EXTENDED_FORMATS
layout(set = 0, binding = 1, rgb10_a2) uniform restrict writeonly image2DArray uIrradianceMap;
#else
layout(set = 0, binding = 1, rgba8) uniform restrict writeonly image2DArray uIrradianceMap;
#endif
#include "utils/environment_map.glsl"
void main()
{
ivec2 pix = ivec2(gl_GlobalInvocationID.xy);
if (pix.x >= pc.size || pix.y >= pc.size) return;
// Get normalized UV for current pixel.
vec2 uv = (vec2(pix) + 0.5) / vec2(pc.size, pc.size);
int face = int(gl_GlobalInvocationID.z);
vec3 normal = FaceUVtoDir(face, uv);
// Establish a tangent space basis.
vec3 up = abs(normal.y) < 0.999 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
vec3 right = normalize(cross(up, normal));
vec3 tangent = cross(normal, right);
vec3 irradiance = vec3(0.0);
float weight = 0.0;
uint sampleCount = uint(pc.sampleCount);
for (uint i = 0u; i < sampleCount; i++)
{
vec2 xi = Hammersley(i, sampleCount);
// Cosine-weighted hemisphere sampling.
float phi = 2.0 * PI * xi.x;
float cosTheta = sqrt(1.0 - xi.y); // weight factor equals cos(theta)
float sinTheta = sqrt(xi.y);
vec3 sampleDir = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
// Transform sample direction from tangent space to world space.
vec3 sampleVec = normalize(right * sampleDir.x + tangent * sampleDir.y + normal * sampleDir.z);
vec3 sampleColor = texture(uSkybox, sampleVec).rgb;
irradiance += sampleColor * cosTheta;
weight += cosTheta;
}
irradiance /= weight;
imageStore(uIrradianceMap, ivec3(pix, face), vec4(irradiance, 1.0));
}