#version 450 // IBL ③:环境 cube → pre-filtered cube(GGX 重要性采样,split-sum 镜面端)。 // R(N) ≈ Σ L·NdotL / Σ NdotL。每 mip 一次 dispatch(storage view 必须 // 单 mip),roughness 经 push constant 传入;256 采样统一(高 roughness // 分布更宽,取 CPU 版采样数上限保证收敛)。 #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; layout(push_constant) uniform Push { float roughness; } pc; const uint SAMPLES = 256; 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 V = N; // split-sum 约定:V 沿 N vec3 acc = vec3(0.0); float weight = 0.0; for (uint i = 0u; i < SAMPLES; ++i) { vec3 H = iblImportanceSampleGGX(iblHammersley(i, SAMPLES), N, pc.roughness); vec3 L = normalize(2.0 * dot(V, H) * H - V); float nDotL = max(dot(N, L), 0.0); if (nDotL > 0.0) { acc += texture(env, L).rgb * nDotL; weight += nDotL; } } imageStore(outCube, gid, vec4(weight > 0.0 ? acc / weight : vec3(0.0), 1.0)); }