蒙特卡洛路径追踪总结
前言
上一篇介绍如何表达一个正确的光线传播模型,但没有提及如何解它的值,因此本篇将介绍使用蒙特卡洛路径追踪来解决该问题
什么是蒙特卡洛积分?
-
原理:对函数值均匀采样求平均并作为积分值的近似。简单来说,就是将下图积分面积分割为多个小长方形,再对这些小长方形的面积求和
-
定义形式:欲求取[a,b]区间的积分制,需要选定一个采样分布函数
,再对其进行多次函数值采样
-
例子
为什么使用蒙特卡洛积分?
因为蒙特卡洛积分适用于计算较为困难的定积分——解析式不好写,该方法可以直接算出对应值
比如下图该函数,确实难以写出它的表达式
路径追踪
- 思想:从视点发出一条光线,光线与物体表面相交时根据表面的材质属性继续采样一个方向,发出另一条光线,如此迭代,直到光线打到光源上或逃逸出场景,再使用蒙特卡洛积分,计算光线的贡献, 作为像素的颜色值。而使用蒙特卡洛方法对积分的求解是
无偏的
,只要时间足够长,最终图像能收敛到一个正确的结果
解渲染方程
-
直接光照
现在有这样一个场景:一个很大的面光源,一个反射点,有一个盒子挡住光,一个观测方向,忽略自发光,考虑.那么目前该视点接收的光是环境光和反射点BRDF作用后的光
可以发现该情况是一个半球上的积分,我们采用蒙特卡洛求解:
- 伪代码
基于p点选取N个采样方向,判断每个方向是否和光源相交,相交就累加求和
-
全局光照
对于下图而言,欲求从Q到P的radiance,相当于是P接收Q的直接光照,也就是说这是个递归
- 伪代码
- 伪代码
存在的问题及解决方法
目前虽然实现了蒙特卡洛路径追踪,但还存在部分问题:
- 光线数目呈指数级增加
- 递归没有终止条件
- 效率低
-
解决方法
-
对于第一个问题,为了防止光线数量的爆发式增长,我们唯一取N = 1——
只采样一个方向,也就是一个像素点
。随之而来的问题是虽然蒙特卡洛积分是无偏的,但它需要大量样本,该解决方法是多条样本穿过该像素点,最后对该像素点取平均
-
对于第二个问题,需要用到
轮盘赌
:有P的概率触发该事件,1-P的概率不触发
对应在路径追踪:有P的概率光线递归,且返回值为
;1-P的概率光线停止递归,返回0
-
对于第三个问题如何提升效率?
-
回想一下,采样时是任选一个方向,这很可能会导致很少有方向能和光源相交。那么如何做到完全不浪费采样?很直接的想法是
直接在光源上采样
,这样必定不会产生浪费,如何实现呢?如下图,将光源看作一个二维的框,设反射点的法线和入射光线的夹角为
,光源的法线和出射光线的夹角为 ,光源的面积为 ,在该光源平面上均匀采样——
但渲染方程并不定义在光源,而是立体角(半球),因此需要将渲染方程改成光源上的积分,也就是说需要求得
dω和dA的关系
:做映射,将A的面积投影到单位球上
最后,以轮盘赌的方式加上间接光,并判断物体是否挡住光源。伪代码如下
-
-
-
效果图
reference
https://github.com/QianMo/Game-Programmer-Study-Notes/blob/master/Content/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!