#version 450 // IBL ②:环境 cube → 漫反射辐照度 cube(半球 Lambert 卷积)。 // E = ∫ L·cosθ·sinθ dθ dφ,切线基 up×N 构造。64×32 = 2048 采样/像素 // (与 CPU 版同级精度),32² 低频输出上 GPU 耗时可忽略。 #include "ibl_common.glsl" layout(local_size_x = 8, local_size_y = 8) in; layout(set = 0, binding = 0) uniform samplerCube env; layout(set = 0, binding = 1, rgba16f) uniform restrict writeonly image2DArray outCube; const int PHI_STEPS = 64; const int THETA_STEPS = 32; void main() { ivec3 gid = ivec3(gl_GlobalInvocationID); ivec2 size = imageSize(outCube).xy; if (gid.x >= size.x || gid.y >= size.y) return; vec2 uv = (vec2(gid.xy) + 0.5) / vec2(size); vec3 N = iblFaceDir(uint(gid.z), uv.x, uv.y); vec3 up = abs(N.y) > 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); vec3 T = normalize(cross(up, N)); vec3 B = cross(N, T); float dPhi = 2.0 * IBL_PI / float(PHI_STEPS); float dTheta = 0.5 * IBL_PI / float(THETA_STEPS); vec3 irradiance = vec3(0.0); for (int p = 0; p < PHI_STEPS; ++p) { float phi = (float(p) + 0.5) * dPhi; for (int t = 0; t < THETA_STEPS; ++t) { float theta = (float(t) + 0.5) * dTheta; float sinT = sin(theta); float cosT = cos(theta); vec3 sampleDir = T * (sinT * cos(phi)) + B * (sinT * sin(phi)) + N * cosT; irradiance += texture(env, sampleDir).rgb * (cosT * sinT); } } imageStore(outCube, gid, vec4(irradiance * (dPhi * dTheta), 1.0)); }