Files
HelloVulkan/shaders/ibl_brdf_lut.comp
T
atdunbg 1d690067bd feat: IBL 预积分 GPU compute 化 + 环境资产入 Assets 层(动态切换)
CPU 逐像素卷积(venice 4k 阻塞 7.36s)→ 4 个 compute shader 一次性
提交:equirect→cube / irradiance / prefilter×5mip / BRDF LUT。
Cubemap 瘦身为纯资源持有类,生成职责移交 IblGenerator;
环境经 AssetManager 缓存(EnvRef),Renderer::SetEnvironment
动态换绑(RenderPass::OnEnvironmentChanged 广播)。
调试视图 +4:EnvCube / Irradiance / Prefilter / BRDF LUT。

性能前后对比(RTX 5060 Laptop,venice_dawn_1_4k.hdr):
- 改造前 CPU:7.36 s(主线程阻塞)
- 改造后 GPU:HDR decode 127-134ms + 资源 22-35ms + compute 17-19ms
  ≈ 165-190ms(约 40×);Neutral 兜底 ~6ms
- 运行中动态切换环境同量级(ms 级 GPU,decode 占大头)

冒烟:两构建目录 0 警告;运行期 0 validation(含两次环境切换 +
调试视图 9-12 轮播自动化验证)。
2026-09-24 13:23:59 +08:00

55 lines
1.9 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#version 450
// IBL ④:BRDF 积分 LUT(2D,纯数学,与环境内容无关)。
// (NdotV, roughness) → (F 缩放 A, F 偏置 B):specular = prefiltered·(F·A + B)。
// 与环境切换无关,但随生成链一起跑(GPU 亚毫秒级),省去跨环境缓存。
#include "ibl_common.glsl"
layout(local_size_x = 8, local_size_y = 8) in;
layout(set = 0, binding = 0, rg16f) uniform restrict writeonly image2D outLut;
const uint SAMPLES = 128;
void main()
{
ivec2 gid = ivec2(gl_GlobalInvocationID);
if (gid.x >= imageSize(outLut).x || gid.y >= imageSize(outLut).y) return;
vec2 uv = (vec2(gid) + 0.5) / vec2(imageSize(outLut));
float nDotV = uv.x;
float roughness = uv.y;
// V 在以 N 为 +Z 的切线空间里(积分只依赖这两角度)
vec3 V = vec3(sqrt(1.0 - nDotV * nDotV), 0.0, nDotV);
vec3 Nz = vec3(0.0, 0.0, 1.0);
float a = 0.0, b = 0.0;
float k = roughness * roughness * 0.5; // IBL 版 Smith k
for (uint i = 0u; i < SAMPLES; ++i) {
vec3 H = iblImportanceSampleGGX(iblHammersley(i, SAMPLES), Nz, roughness);
vec3 L = normalize(2.0 * dot(V, H) * H - V);
float lDotN = L.z;
float nDotL = max(lDotN, 0.0);
float nDotH = max(H.z, 0.0);
float vDotH = max(dot(V, H), 0.0);
if (nDotL <= 0.0) continue;
float g = (nDotV / (nDotV * (1.0 - k) + k)) *
(nDotL / (nDotL * (1.0 - k) + k));
// 高 roughness 时部分样本 H.z 恰为 0(g 也为 0),0/0 = NaN
// 会累进 LUT——分母钳 epsilon(与 CPU 版一致)
float gVis = g * vDotH / max(nDotH * nDotV, 1e-6);
float fc = 1.0 - vDotH;
float f = fc * fc * fc * fc * fc; // (1-vDotH)⁵
a += (1.0 - f) * gVis;
b += f * gVis;
}
imageStore(outLut, gid, vec4(a / float(SAMPLES), b / float(SAMPLES), 0.0, 1.0));
}