路径追踪余弦半球采样下自发光物体光照偏斜问题求助
问题原理
方向偏移问题根源
你最初的采样函数将生成半球极坐标参数的随机向量和计算切空间tangent的随机向量复用了同一个randomVec,导致半球采样的极角、方位角参数和切空间朝向存在强耦合关联,两个本应独立的采样变量产生了绑定,最终采样方向整体出现系统性偏移。十字伪影问题根源
你所用的PCG4D随机数初始化逻辑存在设计缺陷:rng_initialize中种子的第四分量直接用了p.x + p.y的线性组合,和前两个分量p.x、p.y强相关,导致rand3()返回的xyz分量在像素网格上存在隐性的线性关联。当你第一次修改为tangent单独调用rand3()后,采样的方向参数仍然和像素坐标有线性绑定,最终表现为网格状/十字形伪影。
你后续的修复方案本质是通过叠加两次不同的随机数调用结果,人为破坏了这种线性相关性,所以伪影消失,但属于临时 workaround 而非规范实现。
方案合规性说明
你的修复方案可以得到正确的光照结果,但不符合路径追踪的最优实现规范:
- 额外多调用了一次随机数生成函数,无意义增加了计算开销
- 依赖随机向量生成切空间的做法本身就存在稳定性风险,属于不必要的设计
更合理的优化方案
1. 替换随机切空间为固定正交基构建
余弦加权半球采样不需要随机切空间,直接通过法线构建固定的TBN正交基即可,完全不需要消耗随机数,从根源上避免切空间和随机分量的关联,同时降低性能开销。参考实现:
void buildTBN(in float3 n, out float3 t, out float3 b) { float3 up = abs(n.z) < 0.999 ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0); t = normalize(cross(up, n)); b = cross(n, t); }
2. 优化随机数初始化逻辑
替换原来的线性相关种子生成逻辑,使用哈希算法生成四个独立的种子分量,避免伪随机数的分量相关性,参考修改:
void rng_initialize(float2 p, int frame) { // 简单哈希打散像素坐标与帧计数的关联 uint seed = uint(p.x) ^ uint(p.y) * 16777619u ^ uint(frame) * 2654435761u; RandomSeed = uint4(seed, seed * 1234567u, seed * 7654321u, seed * 11111111u); }
3. 简化采样函数实现
优化后的采样函数仅需要两个随机数即可完成采样,性能更高且稳定性更强:
float3 SampleHemisphere3(float3 norm, float alpha = 0.0) { float2 rand = rand2(); // 仅需两个独立随机数 float r = pow(rand.x, 1.0 / (1.0 + alpha)); float angle = rand.y * PI_TWO; float sr = sqrt(1.0 - r * r); float3 ph = float3(sr * cos(angle), sr * sin(angle), r); float3 t, b; buildTBN(norm, t, b); return mul(ph, float3x3(t, b, norm)); }
内容的提问来源于stack exchange,提问作者teamclouday
相关产品推荐
相关产品推荐

