承接上一本 weekend 的内容,上一本的最后已经基本实现了光线追踪的主要内容,接下来要做的是一些特殊的效果,以及一些优化的的东西,不断地完善光线追踪的内容。
这本涉及到的东西太多,每章都可以延伸出很远,所以也就记录个大概。
原文地址:https://github.com/RayTracing/raytracing.github.io/
运动模糊
运动模糊是指物体或相机在高速运动时留下的轨迹,做法就是相机动或者物体动。在这篇文章中,给了物体的运动起点和重点,让物体不断循环往复的运动,然后让摄像机在t0到t1这段时间之间找一个随机的时间t发出射线来与物体进行碰撞,来营造出运动模糊的效果。
包围盒
在光线追踪的时候,发出无数条射线去跟场景交互,要判断有没有碰撞,如果没有的话,这些算力就浪费掉了。包围盒是一种加速求交计算的方式,通过包围盒把所有物体都包围住,没有物体的地方就不用在进行求交点的计算。
包围盒一般有两种,轴对齐包围盒和非轴对齐包围盒,轴对齐是指这个包围盒的xyz是沿着轴的,非轴对齐的也顾名思义。场景中的物体都是球体并且分布也比较集中,所以包围盒会有很好的加速效果。
到目前为止用到的物体都是球体,球体的包围盒用圆心坐标分别在三个方向加减半径即可得到正方体包围盒,但随着后续物体的增加,包围盒的构造也会变得复杂。
重叠的包围盒如何合并,层次包围盒的结构怎么构造(类似八叉树的空间划分),都是比较复杂的问题,有很多这方面的算法,在此不多说了。
实体纹理
纹理也是渲染的一个比较大的方向,这里用的纹理并不是贴图,而是颜色的填充,然后利用正弦波形使两种颜色交替出现,这种实体纹理的方法与数学有较深的关系。
噪声纹理
噪声图是无序的2维黑白图像,可以理解为2维随机图,会经常被用在需要随即生成的地方,在这里使用的是比较常用的柏林噪声,用噪声贴图实现了类似大理石纹理的效果。这部分涉及到的算法大部分与柏林噪声的生成相关。
图像纹理
把纹理附在物体上,因为uv坐标都是0-1,所以2维的平面纹理直接映射就可以
u
=
i
/
n
x
−
1
u=i/nx-1
u=i/nx−1
v
=
j
/
n
y
−
1
v=j/ny-1
v=j/ny−1
而对于球型就要使用极坐标系
u
=
Φ
/
2
π
u=Φ/2π
u=Φ/2π
v
=
θ
/
π
v=θ/π
v=θ/π可以用点的坐标来求出Φ和θ
x
=
c
o
s
(
Φ
)
c
o
s
(
θ
)
x=cos(Φ)cos(θ)
x=cos(Φ)cos(θ)
y
=
s
i
n
(
Φ
)
c
o
s
(
θ
)
y=sin(Φ)cos(θ)
y=sin(Φ)cos(θ)
z
=
s
i
n
(
θ
)
z=sin(θ)
z=sin(θ)
通过反三角函数求出Φ和θ,然后可以用一个开源库 stb_image去读出图像,读出的值转换到0到1的范围里,再输出即可。
矩形
定义矩形的左下角(最小的x,y)和右上角(最大的x,y)(根据坐标轴不同会产生变化),在定义一个z值,即可定义矩形。然后求光线与矩形相交,像之前求过的相交一样,光线同样表示为一个射出点的向量a与t时刻的方向上的向量b的和:
p
(
t
)
=
a
+
t
∗
b
p(t)=a+t*b
p(t)=a+t∗b此时,交点的z分量也可以利用这个公式
z
(
t
)
=
a
z
+
t
∗
b
z
z(t)=a_z+t*b_z
z(t)=az+t∗bz假设z分量为k,变换为t分量的表达式:
t
=
(
k
−
a
z
)
/
b
z
t=(k-a_z)/b_z
t=(k−az)/bz再用t值求出x分量和y分量的值
x
=
a
x
+
t
∗
b
x
x=a_x+t*b_x
x=ax+t∗bx
y
=
a
y
+
t
∗
b
y
y=a_y+t*b_y
y=ay+t∗by当x大于x的最小值,小于x的最大值时,光线与矩形相交。
自发光
这里将着色阶段进行更改,将原来着色的颜色加上了一个发散的属性,只有自发光的物体才有这个值,其他的材料值都为0;
Cornell Box
用制作矩形的方式做6个矩形就变成了box,如果用矩形平移的方式形成的box,还需要反转法线,法线值在计算散射的时候用到了。
体积
当光线打到类似丁达尔介质的物体时会产生散射,根据物体的密度不同,有的光能穿过,有的不能,形成了类似雾的效果,所以实现方式就是光线碰撞物体的时候进行一个方向随机的散射,方向与密度有关。