Ver Fonte

feat: 添加 Shadow Mapping 的解释

NiceTry12138 há 7 meses atrás
pai
commit
2396b9f0f8

BIN
图形学/OpenGL学习/Image/046.png


BIN
图形学/OpenGL学习/Image/047.png


BIN
图形学/OpenGL学习/Image/048.png


BIN
图形学/OpenGL学习/Image/049.png


BIN
图形学/OpenGL学习/Image/050.png


BIN
图形学/OpenGL学习/Image/051.png


BIN
图形学/OpenGL学习/Image/052.png


BIN
图形学/OpenGL学习/Image/053.png


BIN
图形学/OpenGL学习/Image/054.png


BIN
图形学/OpenGL学习/Image/055.png


BIN
图形学/OpenGL学习/Image/056.png


BIN
图形学/OpenGL学习/Image/057.png


BIN
图形学/OpenGL学习/Image/058.png


BIN
图形学/OpenGL学习/Image/059.png


+ 158 - 0
图形学/OpenGL学习/OpenGLDemo.md

@@ -1198,4 +1198,162 @@ MASS 并没有消除锯齿,而是通过插值计算的方法使得观察物体
 
 ![](Image/045.png)
 
+## 高级光照
+
+### Blinn-Phong 
+
+针对普通的 `Phong` 模型,计算**漫反射分量**模拟光线在表面上的均匀散射。当**光源方向**和**表面法线**的夹角大于 90° 时,表示光源在表面下面,此时设置漫反射分量为 0
+
+针对普通的 `Phong` 模型,计算**镜面高光分量**模拟光现在光滑表面上的反射两点。取决于**观察向量**和**反射向量**的夹角
+
+![](Image/046.png)
+
+```
+镜面光分量 = 光源强度 * (max(dot(R,V),0.0))^反光度
+```
+
+大部分情况下,使用 Phong 模型计算计算是没问题的,但是当物体表面的反光度参数非常小,即**非常粗糙**时,镜面高光会扩散到更大范围
+
+在粗糙表面上,即使观察向量和反射向量的夹角大于 90°,实际仍存在较微弱的**高光散射**(物理上称为 **后向散射**)。如果直接使用 `max(dot(R,V),0.0)` 会丢失掉这部分光能
+
+所以,在粗糙物体表面,使用 Phong 模型会导致高光边缘出现明显断层
+
+于是,在 `Phong` 模型的基础之上,引入了 `Blinn-Phong` 模型
+
+`Blinn-Phong` 模型修改了高光分量的计算,不使用**反射向量**和**观察向量**,而是使用**法线**和**半程向量**的夹角
+
+> **半程向量**:光线与视线夹角一半方向上的一个单位向量
+
+![](Image/047.png)
+
+使用 Phong 模型和 Blinn-Phong 模型渲染的区别如下图所示,很明显高光边缘过度柔和
+
+![](Image/048.png)
+
+### Gamma 校正
+
+Gamma 也叫灰度系数,每个显示设备都有自己的 Gamma 值
+
+有一个公示:设备输出亮度 = 电压的 Gamma 次幂
+
+任何设备的 Gamma 基本上都不等于 1,等于 1 是一个理想的线性过程,所以无法做到多少电压等于多少亮度
+
+人类感知的亮度的 Gamma 值大概是 2.2,所以人类感知亮度并不是线性的
+
+![](Image/049.png)
+
+上图中,第一行是人类感知到的正常灰阶,需要增加一倍亮度才能感知到明显变化。比如从 `0.1 -> 0.2` 和 `0.4 -> 0.8`
+
+物理上,也就是第二行的灰阶显示出的才是物理世界真是的亮度
+
+第一行是人眼感知,第二行是物理亮度,人眼对比较暗的颜色变化更敏感,所以两个看起来有差异
+
+![](Image/050.png)
+
+- 按照上图,灰色点线就是当 Gamma 值为 1 时显示的颜色,这是理想情况
+- 按照上图,粉色实线表示显示器实际显示的颜色
+
+当我们设置颜色为 `(0.5, 0, 0)` 时,想要把颜色翻倍得到 `(1, 0, 0)`,这是理想情况。但是在显示器中,颜色是从 `(0.218, 0, 0)` 变成了 `(1, 0, 0)`,翻了 4.5 倍多
+
+Gamma校正(Gamma Correction)的思路是在最终的颜色输出到显示器之前先将 Gamma 的倒数作用到颜色上。回顾本章前面的伽马曲线图,我们看到另一条虚线,它与显示器的伽马曲线相反。我们将每个线性输出颜色乘以这个逆伽马曲线(使它们更亮),一旦颜色显示在显示器上,显示器的伽马曲线就被应用,结果颜色就变成线性的。我们有效地使中间颜色变亮,这样一旦显示器变暗,它们就会平衡
+
+### 阴影(Shadow)
+
+#### 阴影映射(Shadow Mapping)
+
+阴影是光线被阻挡的结果,当一个光源的光线由于其他物体的阻挡不能道道一个物体的表面的时候,那么这个物体就在阴影中
+
+阴影能够使场景看起来真实很多,并且明确空间关系
+
+`Shadow Mapping`(阴影映射贴图)使比较常用的技术,并且容易扩展成高级算法:`Omnidirectional Shadow Maps`(点光源阴影) 和 `Cascaded Shadow`(级联阴影)
+
+`Shadow Mapping` 的思路非常简单:以光的位置为视角进行渲染,看到的东西都将被点亮,看不到的在阴影之中
+
+![](Image/051.png)
+
+> 上图中,蓝色表示光源可以看到,黑色表示光源看不到
+
+从光源的视角,可以计算得到一个**深度贴图**,在进行着色计算的时候根据**点**和**光源**的坐标计算距离,再通过**深度贴图**可以判断点是否在阴影中
+
+![](Image/052.png)
+
+以上图为例,渲染目标点 `P`,将 `P` 转换到光源的坐标空间,然后计算得到 `P` 在光源的坐标空间下深度值为 0.9,大于深度贴图中存储的 0.4,所以点 `P` 在阴影中
+
+> 如果光线是平行光,那么需要使用正交投影矩阵
+
+##### 改进阴影贴图
+
+![](Image/053.png)
+
+以上图为例
+
+- 红色箭头表示光的射线,红色方框框出的是阴影贴图中的一个像素
+- 蓝色箭头表示观察视角,蓝色方框表示渲染出来的一个像素
+
+> 黄色斜坡表示深度贴图的一个纹理
+
+所以很明显可以发现,由于阴影贴图是离散数据,并且受限于分辨率,导致多个片段可能从深度贴图的同一个像素去采样
+
+那么从观察视角来看,两个相邻蓝色方框一个处于阴影中,一个不处于阴影中,最后得到下面这个结果
+
+![](Image/054.png)
+
+为了解决这个问题,最快的方法就是使用 **阴影偏移**,直接对深度贴图应用一个偏移量,这样片段就不会被错误的认为在表面之下了
+
+![](Image/055.png)
+
+##### 悬浮
+
+前面使用 **阴影偏移** 解决了阴影贴图的问题,但是随之而来的是新的问题
+
+![](Image/056.png)
+
+由于对**阴影贴图**使用了**阴影偏移**,如果偏移的值设置的过大会出现**悬浮**的情况
+
+明明物体就在平面上,但是阴影却出现了偏移,导致物体看起来**悬浮(Peter Panning)**起来
+
+解决方法是:不计算物体相对光源的正面深度,而是背面深度,如下图所示
+
+![](Image/057.png)
+
+阴影的计算公式是 **物体深度 + 偏移值** 与 **深度贴图存储值** 进行比较
+
+对光源来说,物体正面的深度值小,物体背面的深度值大,相对来说物体背面的深度允许的**偏移值**更多
+
+所以绘制阴影贴图时,使用物体的背面渲染更为合适
+
+但是,这也引入了新的问题,那就是对于一个 `Plane` 或者特别薄的物体 来说,正面和背面的深度信息其实是一样大的
+
+##### PCF
+
+由于深度贴图采样到的是离散数据,所以很容易出现**锯齿**
+
+![](Image/058.png)
+
+跟之前的原因一样,由于阴影贴图是离散数据,并且受限于分辨率,导致多个片段可能从深度贴图的同一个像素去采样
+
+解决方法有几种
+
+1. 增加深度贴图的分辨率(增加采样率)
+2. 让光的视锥接近场景(尽量让片段不从同一个深度贴图的像素中采样)
+3. PCF(percentage-closer filtering)
+
+PCF 核心思想就是从深度贴图中多次采样,每一次采样的纹理坐标都稍有不同,然后将每次计算的结果结合起来进行平均化,得到柔和阴影
+
+![](Image/059.png)
+
+> 远处看过度不生硬,近处看会有不真实感,适用于大多数场景
+
+##### 正交 VS 投影
+
+| 光源类型 | 光线特性 | 投影矩阵 | 原因 |
+| --- | --- | --- | --- |
+| 平行光(Directional Light)| 光线完全平行(如太阳光) | 正交投影 | 无透视变形,场景受光均匀,适合大范围场景 |
+| 点光源(Point Light)| 光线从一点向所有方向辐射 | 透视投影 | 需要模拟光线衰减,必须使用透视投影(或立方体贴图) |
+| 聚光灯(Spot Light)| 光线呈锥形辐射 | 透视投影 | 需要模拟锥形光照区域(类似手电筒) |
+
+针对**天光**,通常使用**预计算光照**(如 `Light Probe`)或**屏幕空间技术**(`SSAO`)
+
+#### 点光源阴影
+