news 2026/9/12 19:15:59

光线追踪-2:光线照射到物体表面后,反射的Radiance怎么求

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
光线追踪-2:光线照射到物体表面后,反射的Radiance怎么求

0、前言

上一节我们知道了如何求光源(或自发光)的,这一节,我们来求渲染方程的后半部分。反射分为漫反射和镜面反射,入射光又分直接光照和间接光照。

图一

直接光照:光线从光源照射到物体A表面某个点,然后反射到人眼

间接光照:光线从物体B反射出去,入射到物体A表面某个点,然后反射到人眼

那么渲染方程可以扩展为:

直接光照部分:

间接光照部分

各部分含义:

  • ​:光线照射到物体然后反射出去的 Radiance,这个可能会直接反射到眼睛,也可能反射到别的物体上,成为另一个物体表面某个点的间接光照
  • ​:从某个方向射来的 Radiance,包含直接光照和间接光照
  • : 直接从光源的入射光
  • :从别的物体反射出的入射光,例:图一 物体B接收到直接光照和间接光照,然后反射出的光线,入射到物体A
  • ​:材质如何反射光,也就是 BRDF,包含漫反射和镜面反射
  • cos⁡θ:斜着来的光贡献较少(入射光与相交表面的法线夹角)
  • 积分:把上方所有入射方向都考虑进去

Tips: 本节内容只考虑单一光源,多光源需要一个求和计算

1、反射 BRDF

反射包含漫反射和镜面反射,同样也要区分

渲染方程可以扩展为

1.1 漫反射

漫反射可以理解为:

光照到粗糙墙面后,向各个方向比较均匀地散开

漫反射反照率(diffuse albedo),常用 ρ 表示,表示材质对入射光进行漫反射的比例,即

ρ = 漫反射能量 / 入射能量, 是一个通常位于 0 到 1之间的参数。

在PBR工作流中:

(1)对于非金属材质

ρBaseColor

例如:

ρ=(0.8,0.2,0.1)

表示红、绿、蓝三个颜色通道的漫反射反射比例不同。

但这只是近似关系,尤其在存在纹理、次表面散射、光谱效应等情况下,不能简单认为 它就是实验上测得的真实反射率。

(2) 对于金属材质

ρ0

理想情况下金属几乎没有传统意义上的漫反射

金属的颜色主要体现在镜面反射的 Fresnel 反射率中,而不是 ρ这个 Lambert 漫反射参数中

漫反射BRDF:即表示入射能量 一部分转化成立漫反射能量, 除表示向这个半球均匀发散

1.2 镜面反射

镜面反射可以理解成:

像镜子、抛光金属或光滑塑料那样,光主要沿一个特定方向反射。

物理渲染通常不用简单的 Phong或Blinn-Phong模型,而使用微表面模型,例如 Cook-Torrance BRDF:

2、求直接光照的Radiance

直接光照:光线从光源 --> 物体表面x点 -- >人眼

2.1 光源为无半径点光源、方向光

因为这两种光源因没有发光面积无法求出Radiance,且只有一个方向, 可以用Irradiance 来间接求出发射

2.2 光源为面光源

面光源是可以理解为很多个点光源组合在一起,且可以求出光源Radiance的,得到,具体见上一篇

(默认真空环境,radiance 不会衰减,实际环境中也会因为空气颗粒、雾气等衰减)

Tips :这个是对面光源上所有的微元y到物体表面x这个方向的立体角进行积分。 因与光线在物体表面的入射角相关,所以不能把提到积分外。

2.2.1 光线到物体表面x方向的立体角积分 转换为 光源面积的积分

对立体角进行积分比较复杂, 所有我们通常会把上边的公式转化为 对光源表面微元的面积积分

x : 光线招式到的物体表面位置

y:面光源微元的位置

r:x到y 的距离

:光线入射方向与物体表面法线的夹角

:光线从光源射出方向 与光源微元法线 的夹角

:光源微元的面积

解释一下这个转换,

可以求出光源微元的辐射强度

进而求出入射光线在物体表面的辐照度Irradiance

物体表面反射的Radiance

2.2.2Monte Carlo 积分 (多次采样)

积分对于计算机来说还是复杂运算,可以通过蒙特卡洛, 用随机采样来估算积分结果

Monte Carlo 积分的步骤

1、随机采样N个点,

2、每次采样计算的结果除以概率分布函数pdf,得到一个预估值

3、求和N次的预估值,除以N 得到一个

例如:

原积分方程:

Monte Carlo估计为

因为面光源表面微元贡献值一样,采样均匀采样,对于单个面光源微元的采样概率

这个时候就得到直接光照

********* 为啥均匀采样得概率分布函数为? **********

首先均匀采样得概率分布函数是一个常数,总的概率为1,则

3、求间接光照得Radiance

间接光照:光线从光源 -->物体 --> ... -->物体B --> 物体A表面x点 -- >人眼

间接光照是一个递归运算,公式:

A表面x点的直接光照 + A表面x点的间接光照

为物体A表面x点接收到,来自物体B的间接光照 = 物体B反射出的(通过入射物体B某一点的直接光照+间接光照 求出的反射

计算光线追踪的间接光照时,单次反射的采样数还有递归深度都可能造成路径数爆炸。为了避免路径数爆炸,实际的优化方向有以下几种:

3.1 Monte Carla 积分(单次采样)

如果是多次采样,每次反射,生成的路径会指数级翻倍,所以我们采样单次采样。从物体A表面的x点随机选择一个入射方向(而不是选择多个方向),取 -,然后发射一条射线,看是否与别的物体有交点。

因为只随机选择一个入射方向,但需要通过积分所有的入射方向,才能算出正确的, 所有需要一个入射方向的概率分布函数, 通过

估算出方向的间接光照。 我们需要找到一个合适的

常见的几种采样方式及对应的概率分布函数

3.1.1 均匀半球采样

比较好理解,半球内任意方向的概率都是相当的

pdf :

归一化验证 :

半球的各方向的总概率为1,正确

求间接光照:

优点:

  • 实现简单
  • 适用于所有材质

缺点:

  • 方差极大
  • 实际小的方向贡献极小,但均匀半球采样的pdf 给了同等的概率
  • 不推荐使用

3.1.2 余弦加权采样

也比较好理解,就是余弦函数 再除以一个常数,使pdf 的积分等于1,特点是pdf 的形状和余弦函数差不多,方向小的方向贡献小,方向大的方向贡献大

pdf :

归一化验证 :

半球的各方向的总概率为1,正确

求间接光照:

优点:

  • 比均匀采样方差小很多
  • 适用于漫反射材质
  • 公式简洁

缺点:

  • 对镜面反射效果差
  • 没有考虑 镜面反射 BRDF 的形状

3.1.3 BRDF 重要性采样

可以这么理解,镜面反射中,一束入射光经过镜面反射,反射光会在一个反射方向范围内;同样也可以认为一个反射方向范围内的所有入射光,经过镜面反射,变成一束出射光

GGX 微表面 BRDF 的采样

是微表面法线 h的分布函数

  • : 粗糙度参数, 通常
  • : 微表面法线,

微表面法线 h的pdf:

入射间接光的 pdf:

将微表面法线h 的pdf,转换成入射间接光的 pdf, 这个变换暂时没搞懂,以后再推导

pdf :

通常的步骤:

1、随机一个微表面法线h,

2、根据, 计算出

3、再求

或者

1、随机生成一个

2、求微表面法线

3、再求

求间接光照:

( 约掉了、4 、

优点:

  • 镜面反射方差极小
  • 求间接光照时,光滑材质效果好
  • 物理正确

缺点:

  • 粗糙表面效果不如余弦加权
  • 实现复杂
  • 推导p(w_i)时,没有考虑的真实分布

3.1.4 该怎么选采样算法?

均匀半球采样方差太大, 余弦加权采样适合间接光照的漫反射,BRDF重要性采样适合间接光照的镜面反射。那真实场景中是怎么用的呢?

(1)麻布等只有漫反射的材质,用余弦加权采样

(2)玻璃等只有镜面反射的材质,用BRDF重要性采样

(3)同时拥有漫反射和镜面反射的材质有两种方案

3.1.4.1方案1:随机混合

步骤:

1、根据材质的性质,判断漫反射和镜面反射的比例,例如漫反射0.2, 镜面反射0.8

2、从漫反射和镜面反射概率分布函数中随机选一个生成入射光线

3、根据生成漫反射pdf、镜面反射pdf

4、生成混合pdf = 漫反射pdf * 0.2 + 镜面反射* 0.8

5、

如何判断漫反射和镜面反射的比例?这个以后有时间再补上

3.1.4.2方案2:多重重要性采样 MIS

这个就是计算间接光照时,发两条射线去计算,一个用余弦加权采样,一个用BRDF重要性采样,然后再合起来,具体细节以后有时间再聊

总结:效果上肯定多重重要性采样 更好,但增加了光线路径,效率上变慢。实时光线追踪普遍使用的是

3.2 递归什么时候停止?

实际渲染中:

  • 不能无限递归(会栈溢出)
  • 不能计算无限长的路径(太慢)

必须在某个地方停止递归。

3.2.1 方案一、设置最大递归深度

这种方式比较简单,但有两个问题

(1)损失能量,以Cornell Box为例,光线在封闭盒子里反复反弹,假设每次反弹损失20%能量

bounce 0: 1.0

bounce 1: 0.8

bounce 2: 0.64

bounce 3: 0.512

bounce 4: 0.410

bounce 5: 0.328

bounce 6: 0.262

...

真实总能量 = 1 / (1 - 0.8) = 5.0

如果递归深度设为3 ,只计算前4项

1 + 0.8 + 0.64 + 0.512 = 2.952

损失了 (5.0 - 2.952) / 5.0 = 41% 的能量!

(2)计算浪费

对于高反射率的材质(如白色墙),后续 bounces 贡献大,需要很深的路径。

但对于低反射率的材质(如黑色布料),2~3 次 bounce 后能量就衰减到几乎为 0。

固定深度的问题:

  • 对暗材质:浪费计算(追踪了没用的路径)
  • 对亮材质:深度不够(丢失了重要能量)

3.2.2 方案二、俄罗斯轮盘赌 (推荐)

通过一个概率值q来决定是否要继续递归, ( 0< q < 1), 如果一个0到1内的随机数小于q, 就继续,否则就结束递归

俄罗斯轮盘赌提供了一种递归终止的方式,但因为有1- q的概率会终止,所以当递归要继续时,返回的,用来弥补能量损失。

def trace_ray(ray, depth): hit = scene.intersect(ray) if not hit: return background_color L_direct = compute_direct_light(...) # ========================================== # 俄罗斯轮盘赌 # ========================================== if depth >= MIN_DEPTH: # 例如 MIN_DEPTH = 3 # 计算继续概率 q_continue = 0.8 # 或者根据 albedo 动态计算 if random() > q_continue: # 停止递归 # 只返回L_direct , 因为L_indirect = 0 return L_direct else: q_continue = 1.0 # 前几次 bounce 强制继续 # ========================================== # 继续追踪(如果没被杀死) # ========================================== ω_sample, pdf = sample_direction(...) ray_indirect = Ray(hit.position, ω_sample) L_o_next = trace_ray(ray_indirect, depth + 1) L_indirect = (f_r × L_o_next × cos) / pdf # ========================================== # 俄罗斯轮盘赌修正 # ========================================== L_indirect /= q_continue # ← 补偿被杀死的路径 return L_direct + L_indirect

这个q 值怎么选?

可以是一个固定值,也可以根据材质albedo

def get_continue_probability(material, albedo, depth): # 前几次 bounce 强制继续 if depth < 3: return 1.0 # 根据路径贡献 luminance = 0.2126 × albedo.r + 0.7152 × albedo.g + 0.0722 × albedo.b q = min(luminance, 0.95) # 至少有 5% 继续概率(避免完全停止) return max(q, 0.05)

3.2.3 总结

tips : 因为间接光照的反射时仅采样一个随机方向,俄罗斯轮盘赌也会有误差,可以通过增加像素的射线数来使结果趋向期望值

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 19:14:39

Java微服务架构深度审计:基于AST的工程健康度评测

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 19:14:28

YOLO数据集清洗工具实战:从标注错误到稳定训练

简介&#xff1a;面向计算机、电子信息工程、数学等专业学生在课程设计、期末大作业或毕业设计中经常遇到的海量数据标注与清洗难题&#xff0c;可直接采用这套基于Qt与C的YOLO数据集清洗工具。压缩包共7个文件&#xff0c;体积仅12KB&#xff0c;以cpp源文件、ui界面文件、pro…

作者头像 李华
网站建设 2026/9/12 19:11:39

无人机开源科研平台——猫头鹰mini3硬核评测

文章目录前言一、硬件规格与感知计算平台配置二、 核心算法全面开源&#xff0c;二次开发零门槛1.高精度VIO视觉定位 (VINS-Fusion)2.自主避障与路径规划 (EGO-Planner)3.目标检测算法 (Yolo26)4. 丰富的SDK和API接口三、从单机智能到多机“蜂群协同”总结前言 在无人机开发领…

作者头像 李华
网站建设 2026/9/12 19:11:04

数据主题域设计:业务驱动的数据仓库架构核心

1. 数据主题域的本质与价值第一次接触"数据主题域"这个概念时&#xff0c;我正负责一个零售企业的数据仓库重构项目。当时业务部门抱怨找不到关键报表&#xff0c;技术人员则疲于应付各种临时取数需求。直到我们将散落各处的交易、会员、商品数据按主题域重新组织后&…

作者头像 李华
网站建设 2026/9/12 19:10:49

Linux文本处理四件套:cut、sed、awk、sort实战指南

接手 Linux 服务器时间长了&#xff0c;你会发现一个特别有意思的现象&#xff1a;很多看起来复杂得要命的问题&#xff0c;最后查来查去&#xff0c;都落到几个最基础的命令上。尤其是处理日志、清洗数据、批量改配置这种活儿&#xff0c; cut 、 sed 、 awk 、 sort …

作者头像 李华
网站建设 2026/9/12 19:10:10

嵌入式无FPU实现二阶高通滤波器:定点近似与浮点实现性能对比

本文面向嵌入式开发者,完整讲解二阶高通滤波器的设计流程,从截止频率 1kHz、采样频率 10kHz、品质因数 0.707 的设计目标出发,推导出差分方程系数并给出可直接移植的 C 语言实现。文章重点对比浮点实现与定点近似(1+53/128、1+79/128)在精度、资源占用和适用场景上的差异,…

作者头像 李华