目录
Introduction
Vulkan 的学习算告一段落了。下一个阶段是图形基础的复习与学习。这里以Games的课程入手,通过Games课程的学习, 再使用Vulkan实现经典的图形算法, 这样一举两得!
- 使用课程的地址:http://games-cn.org/
首先从Games 渲染课程开始。老本行,容易上手,毕竟需要自己搭建学习使用的Vulkan框架。需要时间做调整。渲染课程结束后再学习其他课程。从Games202开始(101跟过课程), 其实202中的内容也差不多都接触过,但很久没看论文了,有必要做一下恢复性训练#109。
Shadow Mapping
阴影算是我的入行第一课,虽然阴影算法实现不难,但是向一个陌生架构的引擎里塞新功能还是有挑战的!
复习的阴影算法: Games课程讲的阴影算法:
- 2-Pass Algorithm Shadow Mapping
- Percentage Closer Soft Shadows (PCF)
- Variance Soft Shadow Mapping
- Moment Shadow Mapping
- Distance Field Soft Shadows
2-Pass Algorithm Shadow Mapping
阴影生成分为两个 PASS
- Pass1
- 用以光源为相机的视图渲染一张场景的深度图像
- Pass2
- 使用当前相机视图渲染场景
- 将当前相机染视渲图中的可见点投影回光源视图中
- 判断当前着色点深度值与该点在光源视图中的深度值大小确定是否有阴影
- 阴影生成实现 (Vulkan Samples - shadowmapping)
- 生成以光源为相机视图的场景深度图
- 渲染当前场景
- VS中 使用光源视图的MVP矩阵乘以当前着色点, 再乘以 bias 矩阵, 将着色点投影到光源视图中
- 得到投影后的向量inShadowCoord(其实就是当前着色点在深度贴图中像素坐标, Z/W为深度)
- FS中计算遮挡
- 获取当前着色点在深度贴图中uv坐标
- inShadowCoord/inShadowCoord/w
- inShadowCoord.z 与 深度贴图中对应位置的深度值做比较.
- 如果 inShadowCoord.z 大于该深度值即遮挡
- 获取当前着色点在深度贴图中uv坐标
- 在输出最终着色颜色时, 根据遮挡情况乘以一个常量表示阴影
- diffuse * shadow
- shadow(一般使用visibility)不遮挡是为1, 遮挡时设置为小于1的数即可
- VS中 使用光源视图的MVP矩阵乘以当前着色点, 再乘以 bias 矩阵, 将着色点投影到光源视图中
- 问题
- 自遮挡
- 精度误差
- 当前着色点在光源视图中的投影深度不在此深度贴图中
- 由于深度贴图受限于贴图分辨率, 有可能获取当前着色点在光源视图中深度值时, 其所对应的深度值不是该着色点在光源视图的深度(因为深度贴图保存的是离散值), 从而可能产生自遮挡. (相机观察方向与地面夹角越大, 越明显. 当相机观察方向与地面垂直时不会出现自遮挡问题)
- 自遮挡解决办法
- 增加bais
- 虽然深度贴图保存的是离散值, 但是着色点投影到光源视图的深度值与深度贴图对应的深度值的差异不会太大. 在比较两个深度值时, 使用一个可变变量bais来控制自遮挡问题的出现.
- 增加bais
- 不接触阴影(Detached Shadow)
- 引入bais虽然能规避自遮挡问题, 但是会出现Detached Shadow. 这是显而易见的, 当着色点在光源视图中的投影值与深度贴图中对应深度值差值小于等于bais值时会被认为不遮挡.
- 走样 (Aliasing)
- 阴影受限于深度贴图分辨率, 因此走样是必然的.
- 解决办法: Cascaded Shadow Mapping
- 自遮挡
Approximation In Shadow Mapping
- 实时渲染中的两个注意事项
- 实时渲染不相信复杂度
- 不等式的应用: 不关心不等, 更关心近似相等
- 因此可以使用一些经典不等式解决实时渲染中的问题
- 实时渲染中重要的近似公式
∫ Ω f ( x ) g ( x ) d x ≈ ∫ Ω f ( x ) d x ∫ Ω d x ⋅ ∫ Ω g ( x ) d x (1) \tag{1} \int_\varOmega f(x)g(x)dx \approx \cfrac{\int_\varOmega f(x)dx}{\int_\varOmega dx} \cdot \int_\varOmega g(x)dx ∫Ωf(x)g(x)dx≈∫Ωdx∫Ωf(x)dx⋅∫Ωg(x)dx(1)
- 实时渲染的渲染方程:
L o ( p , ω 0 ) = ∫ Ω + L i ( p , ω i ) f r ( p , ω i , ω o ) c o s θ i V ( p , ω i ) d ω i (2) \tag{2}L_o(p, \omega_0) = \int_{\varOmega^+}L_i(p, \omega_i)f_r(p, \omega_i, \omega_o)cos\theta_i V(p, \omega_i)d\omega_i Lo(p,ω0)=∫Ω+Li(p,ωi)fr(p,ωi,ωo)cosθiV(p,ωi)dωi(2)
其中:- L o ( p , ω 0 ) L_o(p, \omega_0) Lo(p,ω0) 是出射光线(outgoing lighting)
- L i ( p , ω i ) L_i(p, \omega_i) Li(p,ωi) 是入射光线(incident lighting)
- f r ( p , ω i , ω o ) c o s θ i f_r(p, \omega_i, \omega_o)cos\theta_i fr(p,ωi,ωo)cosθi是BRDF
- V ( p , ω i ) V(p, \omega_i) V(p,ωi) 是visibility(可见性, 主要指阴影)
- p p p当前着色点
- ω i \omega_i ωi表示方向
- 将visibility项从渲染方程拆出可使用公式(1), 即得
L o ( p , ω 0 ) ≈ ∫ Ω + V ( p , ω i ) d ω i ∫ Ω + d ω i ⋅ ∫ Ω + L i ( p , ω i ) f r ( p , ω i , ω o ) c o s θ i d ω i (3) \tag{3}L_o(p, \omega_0) \approx \cfrac{\int_{\varOmega^+}V(p, \omega_i)d\omega_i}{\int_{\varOmega^+}d\omega_i} \cdot \int_{\varOmega^+}L_i(p, \omega_i)f_r(p, \omega_i, \omega_o)cos\theta_i d\omega_i Lo(p,ω0)≈∫Ω+dωi∫Ω+V(p,ωi)dωi⋅∫Ω+Li(p,ωi)fr(p,ωi,ωo)cosθidωi(3) - 该近似方程(公式3)成立, 即shadow mapping准确需满足以下条件之一:
- 积分范围极小时 ( Δ \Delta Δ)(点光源, 定向光)
- 当不包含visibility项的部分(积分)光滑的情况, 即低频时
- 光源光滑(smooth): 面光源
- 着色点(shading point): diffuse
Percentage Closer Soft Shadows (PCF)
- Percentage Closer Filtering
- PCF在实时渲染中一般用于解决抗锯齿问题
- 因此阴影抗锯齿也同样可以使用PCF
- 思想
- 在Pass-2中做阴影贴图深度比较时, 不仅仅比较当前着色点在光源视图投影值与深度贴图深度值, 还要比较深度贴图该投影点uv坐标周围像素的深度值.
- 然后将这些比较的结果做平均获取得到visibility
- 思想
- 因此阴影抗锯齿也同样可以使用PCF
- PCF在实时渲染中一般用于解决抗锯齿问题
- Percentage Closer Soft Shadows
- PCSS是基于PCF思想产生半影
w P e n u m b r a = ( d R e c e i v e r − d B l o c k e r ) ⋅ w L i g h t / d B l o c k e r (4) \tag{4}w_{Penumbra} = (d_{Receiver} - d_{Blocker}) \cdot w_{Light} /d_{Blocker} wPenumbra=(dReceiver−dBlocker)⋅wLight/dBlocker(4)
其中:- w P e n u m b r a w_{Penumbra} wPenumbra为最后所得半影宽度
- d R e c e i v e r d_{Receiver} dReceiver为光源到阴影接受物的距离
-
d
B
l
o
c
k
e
r
d_{Blocker}
dBlocker为遮挡物与接受物的距离
- 距离的计算: 当遮挡物为一个区域时
- 使用所有遮挡物深度值的平均值
- 距离的计算: 当遮挡物为一个区域时
- w L i g h t w_{Light} wLight为光源的大小(点光源与定向光无软阴影)
- PCSS是基于PCF思想产生半影
- PCSS阴影生成的步骤
- 查找遮挡物(Blocker search)
- 获得某一区域遮挡物的平均深度
- 在阴影深度贴图中查找,找到所有比接受物更靠近光源的像素(即遮挡物),把这些深度值做平均
- 获得某一区域遮挡物的平均深度
- 半影估计(Penumbra estimation)
- 使用公式(4)获取半影
- 估计半影的宽度
- 使用公式(4)获取半影
- PCF(Percentage Closer Filtering)
- 使用PCF方法生成最终阴影
- PCF的采样区域与半影宽度成正比
- 使用PCF方法生成最终阴影
- 查找遮挡物(Blocker search)
- 查找区域的大小由光源大小和接受物与光源的距离决定, PFC的采样可以使用固定值, 如5*5.
- 采样范围可以使用光源到接受物形成的椎体确定
- 取决于光源大小
- 以及接收物与光源的距离
- 如下图所示: (图出自GAMES202_Lecture_03(引用Fernando et al.))
PCF 的理论
- Filter/Convolution
如果对某个函数做滤波/卷积( Filter/Convolution), 可以记作:
[ w ∗ f ] ( p ) = ∑ q ∈ N ( p ) w ( p , q ) f ( q ) (5) \tag5[w\ast f](p) = \displaystyle\sum_{q\in\Nu(p)} w(p,q)f(q) [w∗f](p)=q∈N(p)∑w(p,q)f(q)(5)
-
其中:
- [ w ∗ f ] ( p ) [w\ast f](p) [w∗f](p)为滤波函数, 表示使用权重 w w w对函数 f ( p ) f(p) f(p)做卷积的结果
- q ∈ N ( p ) q\in\Nu(p) q∈N(p)表示函数 f ( p ) f(p) f(p)中点 p p p的所有邻域点
- w ( p , q ) w(p,q) w(p,q)表示点 p p p在点 q q q处所对应的权重
- ∑ q ∈ N ( p ) w ( p , q ) f ( q ) \displaystyle\sum_{q\in\Nu(p)} w(p,q)f(q) q∈N(p)∑w(p,q)f(q) 求和, 即最终得到点 p p p处的滤波值
-
In PCSS
V ( x ) = ∑ q ∈ N ( p ) w ( p , q ) ⋅ χ + [ D S M ( q ) − D s c e n e ( x ) ] (6) \tag6V(x) =\displaystyle\sum_{q\in\Nu(p)}w(p,q)\sdot\chi^+[D_{SM}(q)-D_{scene}(x)] V(x)=q∈N(p)∑w(p,q)⋅χ+[DSM(q)−Dscene(x)](6)- 其中:
-
χ
+
[
D
S
M
(
q
)
−
D
s
c
e
n
e
(
x
)
]
\chi^+[D_{SM}(q)-D_{scene}(x)]
χ+[DSM(q)−Dscene(x)]为阶梯函数 – 符号函数,
- D S M ( q ) D_{SM}(q) DSM(q)表示点 q q q在shadow map 中的深度值, 即 q q q到光源的距离
- D s c e n e ( x ) D_{scene}(x) Dscene(x)表示在场景中点 x x x投影到光源视图空间中, 与光源的距离.
- D S M ( q ) − D s c e n e ( x ) D_{SM}(q)-D_{scene}(x) DSM(q)−Dscene(x)其实就是就是判断点 p p p( x x x投影点)是否被遮挡, 即是否有阴影(小于0有阴影(visibility = 0), 大于0则无 (visibility = 1))
-
χ
+
[
D
S
M
(
q
)
−
D
s
c
e
n
e
(
x
)
]
\chi^+[D_{SM}(q)-D_{scene}(x)]
χ+[DSM(q)−Dscene(x)]为阶梯函数 – 符号函数,
- 公式(6)表示: 对于任意一个shading point ( x x x), 即场景中的某一个位置, 考虑它投影到光源视图中的像素位置 p p p邻域点 q i q_i qi所对应的shading point是否能遮挡 x x x. 比较的结果 χ + \chi^+ χ+(kai) 加权平为 x x x的visibility.
- 疑问: 求平均在公式哪里体现出来的. 应该是 w ( p , q ) w(p,q) w(p,q)权重函数为 w / c o u n t w/count w/count.
- 其中:
-
PCF不是在对阴影贴图进行滤波, 即:
V ( x ) ≠ χ + { [ w ∗ D S M ] ( q ) − D s c e n e ( x ) } (7) \tag7V(x) \not= \chi^+\{[w\ast D_{SM}](q)-D_{scene}(x)\} V(x)=χ+{[w∗DSM](q)−Dscene(x)}(7)
- 其中:
- [ w ∗ D S M ] ( q ) [w\ast D_{SM}](q) [w∗DSM](q)对 x x x投影到光源视图中的像素位置 p p p的邻域点 q i q_i qi对应的阴影贴图中深度值做加权平均
- 公式(7)可以看出,对阴影贴图进行滤波后再使用符号函数 χ + \chi^+ χ+所得到结果visibility依然是非0即1的. 所以公式(7)无意义.
- 其中:
-
同时PCF也不是对阴影渲染结果进行滤波, 即:
V ( x ) ≠ ∑ q ∈ N ( p ) w ( p , q ) V ( q ) (8) \tag8V(x) \not=\sum_{q\in\Nu(p)}w(p,q)V(q) V(x)=q∈N(p)∑w(p,q)V(q)(8)- 公式(8)其实是抗锯齿的过程
Variance Soft Shadow Mapping
- 思想
- PCSS算法的第三步是利用公式(6)得到所有遮挡物visibility的平均值, 而这个平均值可以看做遮挡该着色点的遮挡物的百分比(即, 在一个区域中,遮挡着色点的遮挡物占整个区域的百分比).
- 该百分比可以使用正态分布近似获得
- 判断一个区域内有多少个遮挡物遮挡着色点, 是利用 D S M ( q ) − D s c e n e ( x ) D_{SM}(q)-D_{scene}(x) DSM(q)−Dscene(x)获得. 从公式(6)中可以看出, 其实就是依次比较该区域所有像素的深度值. 即可以看做寻找该着色点深度值在遮挡区域所有深度值中的排名(百分比).
- 正态分布的定义:
N ( μ , σ 2 ) = 1 2 π σ 2 exp ( − ( x − μ ) 2 2 σ 2 ) (9) \tag9\Nu(\mu, \sigma^2) = \cfrac{1}{\sqrt{2\pi\sigma^2}}\exp(-\cfrac{(x- \mu)^2}{2\sigma^2}) N(μ,σ2)=2πσ21exp(−2σ2(x−μ)2)(9)
其中:- μ \mu μ为均值
- σ 2 \sigma^2 σ2为方差
- exp ( ) \exp() exp()为以自然常数 e e e为底的指数函数
- 从公式(9)可以看出, 已知均值和方差即可获得一个正态分布函数
- 快速计算区域内深度的平均值和方差
- 期望的获得, 即均值
- mipmap
- 局限性: 区域为正方形
- Summed Area Tables (SAT)
- mipmap
- 方差的获得
- 对于任意一个随机变量
X
X
X有:
- X X X的方差 = X X X的平方值的期望 - X X X的期望的平方
- V a r ( X ) = E ( X 2 ) − E 2 ( X ) Var(X) = E(X^2) - E^2(X) Var(X)=E(X2)−E2(X)
- 其中 X 2 X^2 X2获得: 在Pass_1深度贴图其他通道中保存片元深度值的平方即可
- 对于任意一个随机变量
X
X
X有:
- 期望的获得, 即均值
- 如何确定着色点遮挡物的百分比
- PDF 概率密度函数(probability density function)
- PDF指: 描述一个随机变量的输出值, 在某个确定的取值点附近的可能性的函数.
- 对于一维实随机变量
X
X
X, 设它的累计分布函数
F
X
(
x
)
F_X(x)
FX(x). 如果存在可测函数
f
X
(
x
)
f_X(x)
fX(x), 满足:
F X ( x ) = ∫ − ∞ x f X ( t ) d t (10) \tag{10}F_X(x) = \int_{-\infty}^xf_X(t)dt FX(x)=∫−∞xfX(t)dt(10)
那么 X X X是一个连续型随机变量, 并且 f X ( x ) f_X(x) fX(x)是它的概率密度函数
- CDF 累积分布函数 (cumulative distribution function)
- PDF的积分。即: F X ( x ) F_X(x) FX(x),描述一个实随机变量 X X X的概率分布
- 高斯PDF(正态分布PDF)的CDF, 对于PDF 积分值可以打出一张表. 即(error function 误差函数)
- c++的 erf 函数可以获得高斯PDF的数值解(CDF没有解析解, 只有数值解)
- 利用高斯PDF的CDF去估计遮挡物占整个计算区域的百分比, 需要求解CDF. 虽然可以使用打表或者像erf这样的函数. 但是依然较为复杂.
- 利用切比雪夫不等式(Chebychev’s inequality), 可以不用计算CDF, 即可得到一个近似的概率分布
P ( x > t ) ≤ σ 2 σ 2 + ( t − μ ) 2 (11) \tag{11}P(x>t) \le \cfrac{\sigma^2}{\sigma^2 + (t - \mu)^2} P(x>t)≤σ2+(t−μ)2σ2(11)- 一个随机变量超过某个值( t t t)的概率, 不需要知道该随机变量满足的具体分布, 只需要知道这个分布的期望和方差, 即可获得大于 t t t的概率
- 也可以解释为: 对任意分布, 已知方差和期望, 这个分布中超过某个值的面积不会超过上界( σ 2 σ 2 + ( t − μ ) 2 \cfrac{\sigma^2}{\sigma^2 + (t - \mu)^2} σ2+(t−μ)2σ2). 即可近似获得CDF值.
- 该不等式成立的条件: t t t必须在均值的右边
- PDF 概率密度函数(probability density function)
- 如何获得着色点的遮挡物的平均深度(VSSM第一步)
- 可以根据切比雪夫不等式获得遮挡物的占整个检索区域的百分比
- 设遮挡物的平均深度为
Z
o
c
c
Z_{occ}
Zocc, 非遮挡物的平均深度为
Z
u
n
o
c
c
Z_{unocc}
Zunocc, 整个检索区域的平均深度为
Z
A
v
g
Z_{Avg}
ZAvg(可由mipmap获得), 有:
N 1 N Z u n o c c + N 2 N Z o c c = Z A v g (12) \tag{12}\cfrac{N_1}{N}Z_{unocc}+\cfrac{N_2}{N}Z_{occ} = Z_{Avg} NN1Zunocc+NN2Zocc=ZAvg(12)- 由切比雪夫不等式可得 N 1 N = P ( x > t ) \cfrac{N_1}{N} = P(x>t) NN1=P(x>t)
- N 2 N = 1 − P ( x > t ) \cfrac{N_2}{N} = 1-P(x>t) NN2=1−P(x>t)
- Z u n o c c Z_{unocc} Zunocc假设与该着色点的深度相同
- 即可得到遮挡物的平均深度
Z
o
c
c
Z_{occ}
Zocc
- 由于假设 Z u n o c c Z_{unocc} Zunocc与该着色点的深度相同, 因此接收物(阴影接收物体, 如地板)必须是平面。 如果非平面(曲面), 或者光源倾斜时,该估计会有问题。
- 当光源移动或物体移动时, mipmap需要更新
- 如何获得着色点的visibility(VSSM第三步)
- 首先计算遮挡区域的平均深度, 判断遮挡(不遮挡visibility为0)
- 然后估计半影区域
- 获得半影区域内的深度值的期望和方差
- 最后使用切比雪夫不等式获得最终的visibility
v i s i b i l i t y = 1 − ( v i s i b i l i t y ∗ ( 1 − P ( x > t ) ) ) (13) \tag{13}visibility = 1-(visibility *(1-P(x>t))) visibility=1−(visibility∗(1−P(x>t)))(13)
- SAT for Range Query
- SAT数据结构使用了前缀和思想
- 如一维数组的SAT: SAT数组上任何一个元素都是原始数组中从最左边元素一直加到该元素的和.
- 查询原始数组中某一段数据的和:
- SAT中该数据段起点前面一个元素值与SAT中该数据段终点位置元素值的差值.
- 预处理, 即建立SAT数据结构时间复杂度为 O ( n ) O(n) O(n)
- 二维数组的SAT数据结构建立与一维相同, 只需保存数组
[
0
,
0
]
[0, 0]
[0,0]位置到该像素位置围成的方形区域内所有元素之和.
- 实现方式: 每行元素做一维SAT, 然后在此基础上每列做一维SAT
- 可以使用GPU加速获得
- 求二维数组某一区域内所有元素之和只需查表四次, 获得左上、右上、左下、右下四个位置对应的SAT数据
S u m = S A T r i g h t d o w n − S A T l e f t d o w n − S A T r i g h t t o p + S A T l e f t t o p (14) \tag{14}Sum = SAT_{rightdown}-SAT_{leftdown}-SAT_{righttop}+SAT_{lefttop} Sum=SATrightdown−SATleftdown−SATrighttop+SATlefttop(14)
- SAT数据结构使用了前缀和思想
- VSSM的缺陷
- 当遮挡物的深度值不符合正态分布时(其实就是当分布为多峰分布时)
- non-planarity artifact (伪影)(Overly dark)
- Light leaking(漏光)(Overly bright)
- 一般当遮挡物越复杂, 其深度值越接近单峰分布, VSSM效果越好
- 最终可以定义为, 由于分布描述不准确导致VSSM效果不好
- 当遮挡物的深度值不符合正态分布时(其实就是当分布为多峰分布时)
Moment Shadow Mapping
- MSM是为了解决VSSM 分布描述不准确的问题
- 思想: 使用更高阶矩表示分布
- 高阶距就是使用元素
x
x
x、
x
2
x^2
x2、
x
3
x^3
x3、
x
4
x^4
x4
.
.
.
...
... 组成的函数来表示一个分布
- VSSM中使用了 x x x 和 x 2 x^2 x2,所以是一个使用了两阶矩组成的函数来表示分布
- 而MSM是利用更多阶的矩来定义分布函数,以获得描述更准确的分布。(MSM使用四阶矩)
- 高阶距就是使用元素
x
x
x、
x
2
x^2
x2、
x
3
x^3
x3、
x
4
x^4
x4
.
.
.
...
... 组成的函数来表示一个分布
- 实现步骤: VSSM相同
- 在获得光源视图深度值时,不仅保存 x x x 和 x 2 x^2 x2 的值,还需保存 x 3 x^3 x3 和 x 4 x^4 x4
- 计算遮挡区域的平均深度
- 估计半影区域
- 使用高阶矩定义的分布函数估计visibility(略)
- 优缺点
- 优点: 可以解决VSSM漏光和伪影的问题
- 缺点:增加内存开销,复杂分布函数的相关计算更为复杂,会导致程序性能的下降
- 思想: 使用更高阶矩表示分布
Distance Field Soft Shadows
-
Distance functions
- 对于空间中的任何一点,其到某个物体表面上最近的一个点距离(即 该点到场景所有物体表面的最小距离).
-
有向距离场 SDF(signed distance field)
- 可以做任何不同模型的blend(混合)
- 理论: 最优传输(顾险峰老师)
- 可以做任何不同模型的blend(混合)
-
利用距离场做阴影的优缺点
- 优点: SDF阴影比传统阴影(shadow maps) 要更快速
- 缺点: 它需要很高的存储开销
-
距离场的应用
- Ray marching 光线追踪.
- 思想: 追踪距离场, 判断光线与哪个物体表面相交
- 最简单的光线追踪: sphere tracing
- 原理
- 任意一点SDF可以确定该点在SDF距离范围内不与任何物体相交
- 如果不相交, 将该点按照光线方向移动SDF长度
- 查找移动后点的SDF值, 继续判断是否与物体相交
- 重复上述过程, 直到追踪点的SDF小于某个距离(极小), 或光线传播一定距离也没相交
- 缺点
- 空间内任何一点, 都要算出SDF, 需要大量存储空间. (存储压缩(优化))
- 刚性运动物体不影响追踪, 但是物体形变必须重计算SDF
- 计算
- 计算空间中每个点与单个物体SDF
- 计算空间中每个点的SDF就是该点对整个场景所有物体SDF的最小值
- 思想: 追踪距离场, 判断光线与哪个物体表面相交
- 使用SDF估计遮挡(近似估计, 不准确)
- 安全距离-安全角度
- 安全距离: 追踪点的SDF
- 安全角度: 着色点发出的光线与着色点和遮挡顶点形成向量( Sphere Tracing 圆的切线)之间的夹角
- Safe Angle 越小, 能够看到的东西越少, 遮挡物较多. 即visibility越小, 越黑(阴影浓度越大)
- 获得安全角度
- 从着色点出发, Ray Marching, 获取每个SDF的安全角度, 最小的一个是最终安全角度.
arcsin S D F ( p ) ∣ ∣ p − o ∣ ∣ (15) \tag{15} \arcsin\cfrac{{SDF}(p)}{||p-o||} arcsin∣∣p−o∣∣SDF(p)(15)
其中,- p p p 为当前Ray Marching顶点位置(光线移动到哪个点)
- S D F ( p ) {SDF}(p) SDF(p) 为当前Ray Marching顶点与遮挡顶点之间的距离(即: 该顶点的SDF)
- ∣ ∣ p − o ∣ ∣ ||p-o|| ∣∣p−o∣∣为着色点与当前Ray Marching顶点之间的距离
- 避免反三角: 在进行GPU计算时, 尽量减少反三角函数这样的复杂运算
- *我觉得这里使用 arctan \arctan arctan在几何意义上是相对正确的, arcsin \arcsin arcsin有点牵强. 因为当 S D F ( p ) {SDF}(p) SDF(p)大于 ∣ ∣ p − o ∣ ∣ ||p-o|| ∣∣p−o∣∣时(在SDF中不存在 S D F ( p ) {SDF}(p) SDF(p)大于 ∣ ∣ p − o ∣ ∣ ||p-o|| ∣∣p−o∣∣的值)光线与Sphere 相交, 无法确定切线. (个人理解)
- 优化公式(15)
m i n { k ⋅ S D F ( p ) ∣ ∣ p − o ∣ ∣ , 1 } (16) \tag{16}min\{\cfrac{k \cdot SDF(p)}{||p-o||}, 1\} min{∣∣p−o∣∣k⋅SDF(p),1}(16)-
利用 k ⋅ S D F ( p ) ∣ ∣ p − o ∣ ∣ \cfrac{k \cdot SDF(p)}{||p-o||} ∣∣p−o∣∣k⋅SDF(p)近似代替反三角函数, 因为求安全角度是为了获得遮挡物占整个区域的百分比, 而比值即可反应这一问题.
-
k k k为权重
-
k
=
1
k = 1
k=1 时, 比值的取值范围在0-1之间, 即被认定为有阴影
- S D F ( p ) ∣ ∣ p − o ∣ ∣ ≤ 1 \cfrac{SDF(p)}{||p-o||}\le1 ∣∣p−o∣∣SDF(p)≤1.(如果该值等于1, 则安全角度为90度, 此时光线追踪顶点与着色点和遮挡物距离相同(着色点可能就是遮挡物), 大于1时, 安全角度大于90度无意义, 因为无法确定切线)–(这种解释确实牵强, 还是使用 arctan \arctan arctan理解更好一些)
- arctan \arctan arctan解释: 当安全角度大于45度时(即比值大于1时)(着色点到光线当前追踪的顶点 p p p距离小于 p p p到遮挡物的距离. 在SDF ( p ) (p) (p)中不存在这样的值)
- k = 5 k = 5 k=5时, 比值取值范围在0-0.2,即被认定为有阴影(阴影效果: 偏硬阴影)
- k = 100 k = 100 k=100, 过渡带0-0.01
- …
-
k
=
1
k = 1
k=1 时, 比值的取值范围在0-1之间, 即被认定为有阴影
-
k的值大的时候, 很小的安全角度可使公式(16)的值为1. 也表示0-1的过渡带就小, 半影区域越小
-
因此k可以控制阴影的软硬
-
- 从着色点出发, Ray Marching, 获取每个SDF的安全角度, 最小的一个是最终安全角度.
- 安全距离-安全角度
- Ray marching 光线追踪.
-
Distance Field Soft Shadows 优缺点
- 优点:
- 不会有自遮挡和阴影悬浮的问题
- SDF阴影比传统阴影更快速
- 缺点:
- 需要与计算, 存储开销大
- 有artifact
- 使用SDF的模型贴纹理较为困难
- 优点:
小结
对阴影算法进行了强化学习. 重点是从数学模型角度去理解各类阴影算法的实现. 笔记中有些地方增加了一些对阴影算法数学模型的个人理解.(有些理解可能有误)