engine/bin/data/shaders/commands/irradiance.comp.glsl

52 lines
1.8 KiB
GLSL

#version 450
#pragma shader_stage(compute)
layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
layout(binding = 0) uniform samplerCube environmentMap;
layout(binding = 1, rgba16f) uniform writeonly image2DArray irradianceMap;
const float PI = 3.14159265359;
vec3 getDirection(uint face, vec2 uv) {
vec3 dir;
uv = uv * 2.0 - 1.0;
switch(face) {
case 0: dir = vec3( 1.0, -uv.y, -uv.x); break; // POSITIVE_X
case 1: dir = vec3(-1.0, -uv.y, uv.x); break; // NEGATIVE_X
case 2: dir = vec3( uv.x, 1.0, uv.y); break; // POSITIVE_Y
case 3: dir = vec3( uv.x, -1.0, -uv.y); break; // NEGATIVE_Y
case 4: dir = vec3( uv.x, -uv.y, 1.0); break; // POSITIVE_Z
case 5: dir = vec3(-uv.x, -uv.y, -1.0); break; // NEGATIVE_Z
}
return normalize(dir);
}
void main() {
ivec3 storePos = ivec3(gl_GlobalInvocationID);
ivec2 size = imageSize(irradianceMap).xy;
if (storePos.x >= size.x || storePos.y >= size.y) return;
vec2 uv = (vec2(storePos.xy) + 0.5) / vec2(size);
vec3 normal = getDirection(storePos.z, uv);
vec3 irradiance = vec3(0.0);
vec3 up = vec3(0.0, 1.0, 0.0);
vec3 right = normalize(cross(up, normal));
up = normalize(cross(normal, right));
float sampleDelta = 0.025;
float nrSamples = 0.0;
for(float phi = 0.0; phi < 2.0 * PI; phi += sampleDelta) {
for(float theta = 0.0; theta < 0.5 * PI; theta += sampleDelta) {
vec3 tangentSample = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));
vec3 sampleVec = tangentSample.x * right + tangentSample.y * up + tangentSample.z * normal;
irradiance += texture(environmentMap, sampleVec).rgb * cos(theta) * sin(theta);
nrSamples++;
}
}
irradiance = PI * irradiance * (1.0 / float(nrSamples));
imageStore(irradianceMap, storePos, vec4(irradiance, 1.0));
}