games101 - 4 - Ray Tracing
games101 - 4 - Ray Tracing
- games101 - 4 - Ray Tracing
- 为什么需要Ray Tracing
- Recursive (Whitted-Style) Ray Tracing
- Ray-Surface Intersection
- Bounding Volumes
- Spatial Partitions
- Bounding Volume Hierarchy (BVH)
- Radiometry
- Bidirectional Reflectance Distribution Function (BRDF)
- 反射方程
- 渲染方程
- Understanding the rendering equation
- Probability Review
- Monte Carlo Integration
- Path Tracing
- Materials and Appearances
- 没有覆盖到的内容
对应的Lecture 13 ~ 17
为什么需要Ray Tracing
光栅化无法处理全局效果
- 软阴影;
- 光反弹次数超过一次的情况,如glossy reflection,indirection illumination;
- 光栅化的很快,但是质量比较低;
- raytracing,很准确,但是很慢;

Recursive (Whitted-Style) Ray Tracing
An improved Illumination model for shaded display” T. Whitted, CACM 1980

Ray-Surface Intersection
射线的定义:\(r(t) = o + td, 0 \le t \lt \infty\),一个起始点,和方向构成了一个射线。
对于射线和方程隐式表示的表面,可以通过求解方程式得到交点。更常见的场景是射线和三角网格模型进行求交计算。对于射线和三角形求交计算,可以先和平面进行求交,然后再判断交点是不是位于三角形内部。
(23条消息) Möller-Trumbore算法-射线三角形相交算法_zhanxi1992的专栏-CSDN博客
O - P_0 = (P_1 - P_0)b_1 + (P_2 - P_0)b_2 - tD \\
S = E_1b_1 + E_2b_2 -tD
\]
矩阵的形式表示如下:
-D & E_1 & E_2
\end{bmatrix}
\begin{bmatrix}
t \\
b_1 \\
b_2
\end{bmatrix} = S
\]
然后利用克莱姆法则(\(Ax = c=>x_i = detA_i/detA\))求解,

如果遍历三角网格中的所有三角形,对每个三角形进行相交计算,并找到最近的交点,整个过程是非常耗时的。需要的开销为#pixels x #triangles (x #bounces).
Bounding Volumes
可以利用包围盒,进行加速。针对复杂物体,构建出包围盒,然后如果射线不和包围盒相交,那么射线就不和包围盒内部的物体相交,如果相交,然后再进行内部物体的相交测试,而包围盒相交监测速度非常快。常见的包围盒有:包围球,轴对⻬包围盒,非轴对齐包围盒。更常用的是使用轴对齐包围盒,因为针对它的相交计算很简单。
在计算直线和Axis-Aligned Box相交的时候(此处允许t<0),分别针对每个维度,计算出\(t_{min}\)和\(t_{max}\),那么\(t_{enter}\)等于各个维度\(t_{min}\)的最大值,\(t_{exit}\)等于各个维度\(t_{max}\)的最小值。如果\(t_{enter} < t_{exit}\),那么相交。

但是ray并不是一条直线需要对负值的情况进行额外判断:
- 如果\(t_{exit} < 0\),那么不相交;
- 如果\(t_{exit} \ge 0\)并且\(t_{enter} < 0\),那么射线的原点位于box内部,相交;
- 那么ray和AABB相交,当且仅当\(t_{enter} < t_{exit}\ \&\& \ t_{exit} \ge 0\)
Spatial Partitions
- Uniform Spatial Partitions (Grids) 适用于很多对象均匀的分布在空间中的场景。
更常用的是不均匀空间划分。
常见的分法如下:

K-D Tree - OI Wiki (oi-wiki.org)
Bounding Volume Hierarchy (BVH)

构建一个BVHs,需要进行如下操作:
- 找到包围盒;
- 将包围盒中的对象分成两个部分(细分的时候需要选择维度最大的方向进行划分,这里通常选择当前node轴长最大的轴,切分的位置通常位于中间);
- 重新计算子集的包围盒;
- 达到某种条件后中断,通常是node中的对象少于一定数量;
- 将对象存储到各个节点中;
BVH的数据结构主要分为两类:内部节点和叶子节点。内部节点包括:包围盒,子节点;叶子节点包括:包围盒,对象集合;
BVH树的遍历:
Intersect(Ray ray, BVH node) {
if (ray misses node.bbox) return;
if (node is a leaf node)
test intersection with all objects;
return closest intersection;
hit1 = Intersect(ray, node.child1);
hit2 = Intersect(ray, node.child2);
return the closer of hit1, hit2;
}
Radiometry
radiant energy: the energy of electromagnetic radiation. \(Q\ [J=Joule]\); 能量整体
radiant flux: the energy emitted, reflected, transmitted or received, per unit time. \(\Phi = dQ/dt\),单位是[W=Watt],或者是[lm = lumen]。单位时间的能量;
另外几个关键概念,示意图如下:

Radiant intensity: the power per unit solid angle emitted by a point light source. \(I(\omega) = d\Phi/d\omega\),单位是[W/sr],或者是[lm/sr = candela]。单位时间单位立体角的能量;立体角的概念,微分,积分,如下:

Irradiance:the power per (perpendicular projected) unit area incident on a surface point.\(E(x) = d\Phi(x)/dA\)。单位面积单位时间的能量(面积为垂直于光线方向);面积理解的示意图如下:

Radiance: the power emitted, reflected, transmitted or received by a surface, per unit solid angle, per projected unit area. 示意图及公式如下:

irradiance和radiance概念对比,irradiance表示的是单位面积接收到的所有能量,radiance表示,从某一个单位立体角看过去的单位面积上接收的能量。

Bidirectional Reflectance Distribution Function (BRDF)
BRDF: 用来表示从每个方向过来的光线,有多少会贡献到每个outgoing方向。represents how much light is reflected into each outgoing direction \(\omega_r\) from each incoming direction. 对应的公式如下:

上面的公式中为什么需要对Lr做微分,对Ei做微分呢?具体解释可以参见:关于BRDF公式理解的笔记_fatever的博客-CSDN博客,摘录关键内容如下:

反射方程

表示的不同方向的irradiance对出射方向上的贡献的积分。
渲染方程
在反射方程的基础上再加上emission项,得到渲染方程。

Understanding the rendering equation

图中,当一个光源的时候,用间接反射光取代了入射光。
Probability Review
随机变量的概率密度函数:\(P(a\le x\lt b) = \int_a^b p(x) dx\)。p(x)即为概率密度函数。从负无穷到正无穷的图形对应的面积为1。对应的期望为\(E(X) = \int xp(x)dx\).
Monte Carlo Integration
蒙特卡罗方法(Monte Carlo Method)概述——概念、起源、思路、应用、特点、计算程序、计算举例和文献资料(21k) (sohu.com)
如果需要求解定积分,\(\int_a^bf(x) dx\),首先需要知道x的概率分布,那么可以转换成求解积分,\(\int_a^bf(x)/p(x)\cdot p(x) dx\),那么用蒙特卡洛进行期望估计,得到:

Path Tracing
Whitted-Style Ray Tracing的条件是:总是执行镜面反射和折射;碰到漫反射表面停止。这种近似对于一些场景会存在问题:1)对于glossy reflection表面;2)在diffuse材质,不会有反射;

之前给出的rendering equation是正确的,那么如何求解呢?
A Simple Monte Carlo Solution
问题:假设我们需要渲染下面场景中一个点(仅考虑直接光照):

那么可以得到如下的反射方程:
\]
要求解这样的积分,我们利用蒙特卡洛积分,构建“f(x)",为:\(L_i(p,\omega_i)f_r(p,\omega_i, \omega_o)(n\cdot\omega_i)\),并且先假设\(\omega_i\)的概率密度函数为\(p(\omega_i)=1/(2\pi)\),半球上均匀分布,那么可以得到:

如果在光线追踪的时候,一条光线hit到了物体,而没有hit到light,需要怎么处理呢?那么首先需要计算hit到物体的位置,贡献的光是多少。如下:
shade(p, wo)
Randomly choose N directions wi~pdf
Lo = 0.0
For each wi
Trace a ray r(p, wi)
If ray r hit the light
Lo += (1/N) * L_i * f_r * cosine / pdf(wi)
Else If ray r hit an object at q
Lo += (1/N) * shade(q, -wi) * f_r * cosine / pdf(wi)
Return Lo
这样就ok了么,并不然。上述的处理方式还存在什么问题呢?
问题1:光线次数随着碰撞次数的增多而指数增长
问题1:光线次数随着碰撞次数的增多而指数增长。如下图所示:

为了避免光线数量的暴增。随机只选择一条光线进行处理。如下:
shade(p, wo)
Randomly choose 1 directions wi~pdf
Lo = 0.0
Trace a ray r(p, wi)
If ray r hit the light
Lo += L_i * f_r * cosine / pdf(wi)
Else If ray r hit an object at q
Lo += shade(q, -wi) * f_r * cosine / pdf(wi)
Return Lo
这种方式的话,如果一个像素上只有一条光线穿过,那么得到的结果噪声会很大,因此需要多条射线穿过一个像素位置,然后对结果进行平均。这样针对一个像素位置的伪代码如下:
ray_generation(camPos, pixel)
Uniformly choose N sample positions within the pixel
pixel_radiance = 0
For each sample in the pixel
Shoot a ray r(camPos, cam_to_sample)
If ray hit the screen at p
pixel_radiance += 1 / N * shade(p, sample_to_cam)
Return pixel_radiance
问题2:此时shade函数如何终止
问题2:此时shade函数中还存在一个问题,就是函数进行无限循环。解决方案是提供轮盘赌的方式(Russian Roulette)。假设我们手动设置一个概率值,P,在发射一条光线的时候,给出一个随机值,如果范围在P~1,那么返回:0,否则返回:Lo/P。这样得到的Lo的期望为:E = P * (Lo/P) + (1-P)*0 = Lo。将这部分内容加到shader伪代码中如下:
shade(p, wo)
Manully specify a probability P_RR
Randomly select ksi in a uniform dist. in [0, 1]
If (ksi > P_RR) return 0.0
Randomly choose ONE direction wi-pdf(w)
Trace a ray r(p, wi)
If ray r hit the light
Return L_i * f_r * cosine / pdf(wi) / P_RR
Else If ray r hit an object at q
Return shade(q,-wi) * f_r * cosine / pdf(wi) / P_RR
问题3:如何提高采样效率
上述的实现并不是很高效,如下图所示:

如果光源面积比较大,那么发射较少数量的光线,就可以碰撞到光源,如果光源面积比较小,那么需要发生很多的光线才行。这样如果我们在半球表面进行均匀采样,那么会有大量的光线是wasted的。那么怎么解决呢?
可以将采样分为两部分,1)针对光源进行采样,2)针对非直接光照场景进行采样;


从渲染方程得知,接收到的光照信息,是针对立体角进行积分的,那么怎么转换到,通过光源面积进行积分呢?从立体角的定义得到:
\]
那么渲染方程可以重写为:

此时shade伪代码可以写为:
shade(p, wo)
# Contribute from the light source
Uniformly sample the light at x' (pdf_light = 1/A)
# test blocked
Shoot a ray from p to x'
If the ray is not blocked in the middle
L_dir = L_i * f_r * costheta * costheta' / |x' - p|^2 / pdf_light
# Contribute from other reflectors
L_indir = 0.0
Test Russian Roulette with probability P_RR
Uniformly sample the hemisphere toward Wi (pdf_hemi = 1/2pi)
Trace a ray r(p, wi)
If ray hit a non-emitting object at q
L_indir = shade(q, -wi) * f_r * costheta / pdf_hemi / P_RR
Materials and Appearances
Materials == BRDF。BRDF用来表示从每个方向过来的光线,有多少会贡献到每个outgoing方向。

Snell's Law

传输方向从i到t,那么如果\(\eta_i/\eta_t > 1\)可能发生完全内反射(即,没有折射的现象)。
Fresnel Reflection
用来解释:视线垂直于表面时,反射较弱,而当视线非垂直表面时,夹角越小,反射越明显,这一种现象。
Fresnel Reflection - 菲涅尔反射 - Tekkaman - 博客园 (cnblogs.com)
准确解和近似解分别如下:

微表面

微表面,针对每一个元素都可以视为mirror。
没有覆盖到的内容
- uniformly sampling the hemisphere; How?
- Monte carlo integration allows arbitrary pdfs. What's the best choice?
- Do random numbers matter ? Yes! (low discrepancy sequences)
- I can sample the hemisphere and the light. Can I combine them? Yes! (multiple imp. sampling)
- The radiance of a pixel is the average of radiance on all paths passing through it. Why? (pixel reconstruction filter)
- Is the radiance of a pixel the color of a pixel? No. (gamma correction, curves, color space)
- deeper path tracing.
games101 - 4 - Ray Tracing的更多相关文章
- OpenCascade Ray Tracing Rendering
OpenCascade Ray Tracing Rendering eryar@163.com 摘要Abstract:OpenCascade6.7.0中引入了光线跟踪算法的实现.使用光线跟踪算法可实现 ...
- 开始研究Ray tracing
几个月前面试时Boss问过我一个问题--"除了scanline渲染方法,你还知道什么其他渲染方式?",我没答出来,至今记忆犹新. 前段时间摆弄Intel VTune时看了它的示例代 ...
- Ray Tracing
Ray Tracing 题目链接:http://codeforces.com/problemset/problem/724/C 拓展欧几里得 //为什么这次C题这么难啊=.= 可以观察到,光线在矩形中 ...
- 《Ray Tracing in One Weekend》、《Ray Tracing from the Ground Up》读后感以及光线追踪学习推荐
<Ray Tracing in One Weekend> 优点: 相对简单易懂 渲染效果相当好 代码简短,只看书上的代码就可以写出完整的程序,而且Github上的代码是将基类与之类写在一起 ...
- 【Ray Tracing The Next Week 超详解】 光线追踪2-7 任意长方体 && 场景案例
上一篇比较简单,很久才发是因为做了一些好玩的场景,后来发现这一章是专门写场景例子的,所以就安排到了这一篇 Preface 这一篇要介绍的内容有: 1. 自己做的光照例子 2. Cornell box画 ...
- 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-7 混合概率密度
Preface 注:鉴于很多网站随意爬取数据,可能导致内容残缺以及引用失效等问题,影响阅读,请认准原创网址: https://www.cnblogs.com/lv-anchoret/category ...
- 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-5 random direction & ONB
Preface 往后看了几章,对这本书有了新的理解 上一篇,我们第一次尝试把MC积分运用到了Lambertian材质中,当然,第一次尝试是失败的,作者发现它的渲染效果和现实有些出入,所以结尾处声明要 ...
- 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-4 基于重要性采样的材质初探
Preface 我们今天来把第三本书从开局到现在讲的一大堆理论运用到我们的框架中,那么今天我们首先将原始的材质改为基于重要性采样原理的材质 这一篇是代码工程中进行MC理论应用的初步尝试篇 Read ...
- 【Ray Tracing The Next Week 超详解】 光线追踪2-9
我们来整理一下项目的代码 目录 ----include --hit --texture --material ----RTdef.hpp ----ray.hpp ----camera.hpp ---- ...
随机推荐
- Function Overloading in C++
In C++, following function declarations cannot be overloaded. (1)Function declarations that differ o ...
- Mybatis-Plus默认主键策略导致自动生成19位长度主键id的坑
原创/朱季谦 某天检查一位离职同事写的代码,发现其对应表虽然设置了AUTO_INCREMENT自增,但页面新增功能生成的数据主键id很诡异,长度达到了19位,且不是从1开始递增的-- 我检查了一下,发 ...
- Python基础入门(5)- 函数的定义与使用
定义函数 函数的定义 函数的分类 函数的创建方法 函数的返回return 函数的定义 将一件事情的步骤封装在一起并得到最终结果 函数名代表了这个函数要做的事情 函数体是实现函数功能的流程 函数可以帮助 ...
- <转>android 解析json数据格式
json数据格式解析我自己分为两种:一种是普通的,一种是带有数组形式的: 普通形式的:服务器端返回的json数据格式如下:{"userbean":{"Uid": ...
- 数组基础(Excel函数集团)
此处文章均为本妖原创,供下载.学习.探讨! 文章下载源是Office365国内版1Driver,如有链接问题请联系我. 请勿用于商业! 谢谢 下载地址:https://officecommunity- ...
- CF108A Palindromic Times 题解
Content 现在是 \(h\) 时 \(m\) 分,请求出在此之后(不包含此时)的第一个回文时间. 数据范围:\(0\leqslant h\leqslant 23,0\leqslant m\leq ...
- 第一周python学习总结
多行注释:格式化输出内容,用{}传递变量内容 执行输出 while: for XXX: if: range(satar,end,步长) break continue input 等于python2里面 ...
- shell判断新字符串列表是否在老字符串列表中
for sn in `cat 12.30-new`;do if ! [[ `cat 12.30-old` =~ $sn ]];then echo $sn; fi; done
- 痞子衡嵌入式:揭秘i.MXRT1170上用J-Link连接复位后PC总是停在0x223104的原因
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1170上安全调试策略实现对JLink调试的影响. 痞子衡之前写过一篇旧文 <i.MXRT600的ISP模式下用J-L ...
- 总结Vue第二天:自定义子组件、父子组件通信、插槽
总结Vue第二天:自定义子组件.父子组件通信.插槽 一.组件: 组件目录 1.注册组件(全局组件.局部组件和小demo) 2.组件数据存放 3.父子组件通信(父级向子级传递数据.子级向父级传递数据) ...