目录
两种AABBs加速光线
1.均匀空间分区(网格)
预处理-构建加速均匀网格
如何知道光线方向是如何遍历网格?
网格的划分大小问题, 分为两个极端
网格最佳的划分方法
优点: 网格适用于在大小和空间上均匀分布的大型对象集合
缺点: 不适用于大规模空白的场景
2.空间划分
2.1 八叉树
2.2 BSP-Tree
2.3 KD-Tree
KD-Tree 预处理过程
判断是否有交点 - 实际做法
KD-Tree缺点(难点)
2.4 BVH
BVH的运作过程
BVH过程总结
BVH 与 KD-Tree的区别
BVH缺点
BVH如何划分一个节点(包围盒)
停止划分原则
内部节点存储
叶节点存储
节点表示场景中原有物体的子集
算法的伪代码
空间划分VS对象划分
空间划分(比如KD-Tree)
对象划分(比如BVH)
Basic radiometry(辐射度量学)
为什么要学辐射度量学?
辐射度量学是什么?
新术语介绍
辐射能定义
辐射通量定义
重要的光测量单位
① 从光源发出的光-----”辐射强度(Radiant Intensity)”
② 落在表面上的光-----”辐照度(Irradiance)”
③ 沿着射线传播的光-----”辐射度(Radiance)”
辐射强度的计算
角度与立体角
微分(单位)立体角的计算
第十四节课 :光线追踪(Ray Tracing 2)
1.均匀空间分区(网格)
2.空间划分
1. 找到包围盒
2. 创建网格
3. 将对象与格子相交的区域记录下来(涂成灰色)
小错误: 右上角有一块应该涂成灰色
4. 最后, 对光线与场景求交点
4.1 按光线遍历的顺序逐步穿过网格
4.2 对于每个网格单元,测试与存储在该单元中的所有对象是否相交
答: 不可能对每个网格单元都测试一次是否有交点, 可以利用光线方向判断可能经过的网格,
比如方向为↗, 则只判断当前已产生交点的网格位置的右或者上是否有交点.
①太稀疏, 导致没有产生加速效果
② 太密集, 导致要判断太多的网格是否有交点,而效率低下
C是一个常数, objs为3d物体数量
最佳划分方法没有很大意义, 主要思想就是要适中.
如下图:
想象一下“运动场上的茶壶”, 描述一个大规模空白的场景出现一个需要判断光线与网格交点的物体, 需要遍历很多无效的网格,造成浪费.
下图是2D的, 所以变成了四叉树, 每次切两刀(以网格中心为原点, 往x,y轴切)
如果已经切好的网格是空的(无物体), 那么就停止该网格的继续切分两刀的操作.
缺点 :如果维度上升, 切的次数会增多同时网格数量也会增多, 导致计算量增大.
不沿着x,y轴方向划分.
缺点: 与八叉树一样, 随着维度增高, 计算量就增大
划分方式和八叉树极为类似, 但是KD-Tree只砍一刀(沿着x轴或者y轴), 一般是以x轴划分一次, 再以y轴划分一次, 这样交替划分, 以确保均匀划分.如果已经切好的网格是空的(无物体), 那么就停止这个网格的继续切分一刀的操作.
给定一个场景, 先把加速结构做好(例如KD-Tree)
① 网格划分一次(沿y轴砍了一刀)(蓝/绿)
② 再次划分(沿x轴再砍一刀)(绿色=绿色+橙色)
Ps:下图只是忽略蓝色被处理过程, 蓝色和绿色网格处理方式一致.
③ 不断划分得到最终的KD树的数据结构
内部节点存储
-分割轴:x、y或z轴
-分割位置:分割平面沿轴的坐标
-子节点:指向子节点的指针
在内部节点中不存储任何对象, 物体对象都存储在叶子节点.
叶节点存储 : 对象列表
遍历KD树(每次都记录tmin和tmax,判断是否有交点)
① 先和最大的包围盒做交点检测
判断光线是否与A包围盒有交点
发现光线与A包围盒确实有交点
② 光线既然与A相交, 那么有可能就与它的子节点(1,B)相交
判断光线是否与A的子节点1有交点, 发现有交点(这里假设1是叶子节点, 无法继续切分)
③ 判断光线是否与A的子节点B有交点, 发现是有交点的
④ 既然光线与B相交, 那么就有可能与它的子节点(2,C)相交, 判断光线是否与B的子节点2有交点, 发现光线与2有交点.(这里依旧假设2是叶子节点, 无法继续切分)
⑤ 继续判断C是否与光线有交点, 发现确实有交点
⑥ 判断C的子节点3与光线是否有交点
⑦ 继续判断D是否有交点, 发现有交点
⑧ 判断D的子节点4是否有交点, 发现是最后的一个叶子节点且有交点
⑨ 最后同为最后一个子节点的5是没有交点
① KD-Tree建立时, 难以对包围盒与三角形求交点
② 物体可能存在多个不同的网格(包围盒),
例如: 看上图3,4,5包围盒中都有含有同一个圆形.
所以导致它渐渐不被使用
对象分区/包围体层次结构(BVH)
跟上述Tree以空间划分不一样的是, 此结构是以对象进行分区.
① 根节点
② 以某种算法(计算盒中三角形的x和y的min/max)把三角形分为两堆(蓝/黄), 重新计算对应的包围盒, 形成两个子节点
③ 重复上一步, 再次划分上面定义的蓝色部分,分成(蓝/绿)
④ 继续划分蓝色区域, 得到两个子节点(C ,D), 重新计算对应的包围盒
⑤ 直到认为叶子节点存储的三角形足够少为止, 就可以停止分割. 当然可以按照自定义算法, 对三角形包围盒分割得均匀
1.查找边界框
2.递归地将对象集划分成两个子集
3.重新计算子集的包围盒
4.必要时停止划分
5.在每个叶子节点中存储对象
选择要拆分的维度
#1:始终选择节点中的最长轴
#2:在三角形个数中间值的位置处分割节点, 例如有四个三角形在一个包围盒里, 就找到第二个三角形, 并把第一个和第二个放一个节点, 另外两个放另一个节点.
当节点(包围盒)包含少量元素(三角形)时停止
1.包围盒
2.子节点:指向子节点的指针
1.包围盒
2.对象列表
1.子树中的所有对象
BVH加速结构与光线的求交, 这个本质上和KD-Tree没区别,因为是把已经预处理的加速结构与光线做求交点操作.
Intersect(Ray ray, BVH node)
{
If(光线没遇到节点.包围盒) return;
下面是遇到了节点->包围盒的情况
If(节点是叶子节点)
光线要对叶子节点内的所有物体求一次交点;
return 最近的交点;
If(节点是内部节点)
hit1 = Intersect(ray, 节点.child1);
hit2 = Intersect(ray, 节点.child2);(递归算法)
Return 最近的 hit1, hit2;
}
① 将空间划分为非重叠区域
② 一个对象可以包含在多个区域中
① 将对象的分区集划分为不相交的子集
② 每个集合的边界框可能在空间中重叠
Ps:从这里开始的光线追踪,国内课程无讲解
经过观察:
在任务3中,我们实现了Blinn-Phong模型
其中参数例如,光强I 是10
但是10什么单位?
你认为Whitted style的光线追踪能给你正确的结果吗?
所有的答案都可以在辐射度量学中找到.
① 照明的测量系统和装置
② 精确地测量光的空间特性
③ 以正确的方式进行照明计算
辐射能和辐射通量(功率)radiant energy and flux(power)
用符号表示:
用符号表示:
可以理解为功率, 或者光学中的光通量lumen: 衡量光源在单位时间内发出的可见光总量.
辐射通量 -光子在单位时间内流过传感器的数量
若其中一个灯泡更亮, 是因为它单位时间内的光子更多
-对应立体角上的能量
-对应面积上的能量
辐射(发光)强度是点光源发射的单位立体角的功率
辐射强度 =单位能量/单位立体角
光学上也可以表示, lumen(lm)/sr(立体角单位) = candela(cd)
角度: 弧长/半径, 整个圆角度就是2
立体角:球体对向面积(A) /半径的平方, 整个球的立体角就是4
① 是用y轴绕着一个z轴去旋转产生的角度
② 是用z轴绕着一个y轴去旋转产生的角度
③ 就是产生的角度, 在变化相同量时, 对于立体角的改变并不相同
总结 :对球面面积不是均匀得划分.
④ dA是下图方块面积
⑤ 半径乘以, 得到弧长, 是方块的一条边(竖).
⑥ 因为其半径不同, 所以要sin转换一下半径, 乘以得到弧长, 是方块的另一条边(横).
⑦ d: 立体角
求整个球的立体角, 微分出来的结果是4
作为方向向量
将使用表示方向向量(单位长度)
微分 :把不均匀的变化细分成很小的单位
积分 :把微分出来的结果算总和
光源的全部能量 = 积分(所有方向向量 d 的辐射强度)
得出辐射强度 = 光源的全部能量 / 整个球的立体角 4
生活中联系以上概念
Intensity = 815() / (立体角) = 65()