You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PBR基于图像照明(IBL)相关技术疑问求助

PBR IBL 基础概念困惑解答

问题1:IBL中光源方向设为反射向量时,半向量是否会与法线完全一致?

  • 明确向量定义:EyeToFragDir是视线向量V(相机指向片元),reflect(EyeToFragDir, Normal)得到的是视线相对法线的反射向量R。这里把FragToLightDir设为R,是IBL镜面反射采样的特定处理——用反射方向作为“虚拟光源方向”,用来采样环境贴图中对应镜面反射的区域。
  • 代入半向量公式推导:HalfVecDir = normalize(R + V)。根据反射向量几何关系,R = 2*(N·V)*N - V,代入后R+V = 2*(N·V)*N,归一化后方向与法线N完全一致,因此NDotH = dot(N, N) = 1.0,这个结论是对的。
  • 这么做的目的:在GGX分布的IBL重要性采样中,半向量H的分布是核心,将H固定为N可以简化采样逻辑,把计算集中在镜面高光对应的环境区域,只适用于IBL镜面反射部分,不是通用光照逻辑。

问题2:Lys镜面立方体贴图采样中的NDotR定义与掠射角过亮问题

NDotR的定义

IBL中的NDotR就是dot(Normal, ReflectDir),其中ReflectDir是视线向量V相对法线N的反射向量R。根据反射公式推导,dot(N, R) = 2*(N·V)² - 1,它和dot(N, V)并不等价:当V垂直于N时,NDotR=1;当V掠射(N·V趋近于0)时,NDotR=-1。

掠射角过亮的原因

你代码中用max(NDotR, EPSILON)会把掠射角下的负NDotR强制转为极小值,导致specular_power被除以极小值后变得极大,最终采样层级趋近于0(采样最清晰的Mip层)。但掠射角下,相同粗糙度的镜面反射区域应该更模糊,采样清晰Mip层就会出现过亮问题。

修正方案

  • 只保留法线正面的反射贡献,将NDotR取为max(dot(N, R), 0.0),背面反射直接放弃计算;
  • 可以通过N·V直接推导NDotR,避免额外的反射向量计算;
  • 修正后的采样函数:
float computeSpecularCubeMip(float perc_ruf, float NdotV)
{
    float NdotR = max(2.0 * NdotV * NdotV - 1.0, 0.0); // 等价于dot(N, reflect(-V, N))
    float specular_power = (2.0 / max(EPSILON, perc_ruf*perc_ruf*perc_ruf*perc_ruf)) - 2.0;
    specular_power /= (4.0 * max(NdotR, EPSILON));
    return sqrt(max(EPSILON, sqrt(2.0/(specular_power + 2.0)))) * MipScaler;
}
  • 你之前用NDotH效果正常,但因为问题1中的处理导致NDotH=1.0,这是逻辑混淆——Lys的采样层级计算原本就不需要依赖半向量H,应该基于视线和法线的关系来计算NDotR。

内容的提问来源于stack exchange,提问作者Robert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 19:10:29