路径追踪中焦散渲染异常排查:折射代码疑似错误
路径追踪器折射代码问题分析(导致焦散无法生成)
核心问题1:折射率(IOR)赋值完全颠倒
当前代码中IOR的逻辑完全反了:
- 当光线从外部(空气,IOR=1)进入物体(介质IOR=mat_IOR)时,折射公式需要的是入射介质/折射介质的折射率比(即
1.0/mat_IOR),但你写成了material['IOR'] - 当光线从物体内部射出到外部时,需要的是
mat_IOR/1.0,但你写成了1/material['IOR']
这会导致折射方向完全错误,光线无法按预期路径折射,自然无法形成焦散。
问题2:Schlick近似的参数c计算错误
Schlick反射率近似公式中,参数应为1 - cosθ(cosθ是入射角的余弦值,正数)。当前代码:
c = 1.0 - (-cos_theta if out_to_in else d_Tr_dot_N)
当out_to_in为真时,-cos_theta是正确的入射角余弦,但1 - (-cos_theta)等于1 + cosθ,和公式要求的1 - cosθ完全相反,会导致反射率计算错误,光线采样的概率权重偏离,进一步影响焦散生成。
问题3:折射方向的向量计算需匹配标准公式
修正IOR后,需要确保折射方向符合斯内尔定律的向量形式,原代码的符号逻辑在IOR修正后需要调整。
修正后的代码片段
# 反射方向计算 d_Re = ray_direction - 2 * (ray_dir_dot_N) * N # 判断光线是从外部进入还是内部穿出 out_to_in = ray_dir_dot_N < 0 mat_IOR = material['IOR'] # 修正IOR赋值:n1/n2,n1是入射介质,n2是折射介质 if out_to_in: # 空气(n1=1)→ 介质(n2=mat_IOR) IOR = 1.0 / mat_IOR nl = N # 法线指向入射介质(空气) else: # 介质(n1=mat_IOR)→ 空气(n2=1) IOR = mat_IOR nl = -N # 法线指向入射介质(介质内部) # 计算入射角的余弦(正数) cos_theta1 = max(0.0, np.dot(-ray_direction, nl)) sin2_theta1 = 1.0 - cos_theta1 ** 2 sin2_theta2 = (IOR ** 2) * sin2_theta1 if sin2_theta2 > 1.0: # 全反射,只能走反射路径 ray_dir = d_Re ray_prob = 1.0 else: cos_theta2 = np.sqrt(1.0 - sin2_theta2) # 计算折射方向(符合标准斯内尔向量公式) d_Tr = IOR * ray_direction + (IOR * cos_theta1 - cos_theta2) * nl # 计算Schlick反射率 R0 = ((1.0 - mat_IOR) / (1.0 + mat_IOR)) ** 2 if out_to_in: # 入射时用入射角余弦 c = 1.0 - cos_theta1 else: # 出射时用折射角余弦 c = 1.0 - cos_theta2 Re = R0 + (1.0 - R0) * (c ** 5) Tr = 1.0 - Re # 重要性采样:选择反射或折射 p_Re = 0.25 + 0.5 * Re if np.random.rand() < p_Re: ray_dir = d_Re ray_prob = Re / p_Re else: ray_dir = d_Tr ray_prob = Tr / (1.0 - p_Re)
额外注意事项
- 确保路径追踪器在光线弹射时正确累积权重(
ray_prob需要乘到颜色贡献中) - 反向路径追踪生成焦散的噪声极大,需要足够多的样本才能看到明显效果,可先测试单一路径的折射方向是否正确
- 确认场景中的光源是发光物体,且路径追踪器能正确处理直接命中光源的情况
内容的提问来源于stack exchange,提问作者cabbage_queen
相关产品推荐
相关产品推荐

