光照相关渲染技术
传统光照模型
Lambert 模型
规定漫反射光照如何计算。
兰伯特余弦定理:物体表面受光照影响 = 法线与光线夹角的 cos 值
漫反射光计算公式:L_d = K_d × (I/r^2) × max(cos\theta, 0)
- K_d 是漫反射材质系数,反映物体会反射多少比例的光
- I 是光源强度,r 是光源距离(高中时我们学过,球状辐射的能量以平方速度衰减)
- \theta 是法线与光线的夹角
如果法线向量和光线向量都为单位向量,那么公式可变为:
如果光源是平行光,则不考虑衰减(或者根据需要更改衰减函数),公式可变为:
半 Lambert 光照
Lambert 光照下侧面暗部太暗了,这里改进了光照计算公式,将 cos 值映射到 0.5 ~ 1.0 范围。
Phong
环境光+漫反射+高光=最终物体颜色
环境光(Ambient)计算:
其中 K_a 是环境光反射系数(由材质决定),I_a 是环境光强度。
漫反射(Diffuse)计算:使用的就是兰伯特或者半兰伯特。
高光(Specular)计算:
- K_s 是镜面反射系数(由材质决定)。
- I 是光源强度,r 是光源距离
- \theta 是视线与反射光线的夹角。
phong 模型使用 reflect 函数,输入入射光线向量和法线向量计算出射光线向量。reflect 计算方式:
- I 是入射光线,需归一化。N 是法线向量,也需要归一化。
- (I\cdot N)\cdot N 对应向量 I 在 N 上的投影向量。
Blinn-Phong
在 Phong 模型上改进了高光的计算公式,不再使用视线与反射光线的夹角,而是改为计算“半程向量”与法线的夹角。所谓“半程向量”就是视线与入射光线的角平分线上的单位向量,直接相加入射光线向量和视线向量即可得到,避免了 reflect 函数的计算开销。此外,由于入射光线以一定的权重混入计算,高光的衰减变得更缓,更符合视觉直觉。
前向渲染
在每个片段上立刻计算光照。
特点:
- 图元在片元着色阶段立即进行光照计算。
- 容易因大量光源导致计算开销增大。
- 直接支持透明度和混合操作。
延迟渲染
光照计算推迟到所有几何体处理完毕之后进行。
分为两个pass:
- G-buffer pass 先进行一次渲染得到深度图、漫反射颜色图、法线图...
- Lighting pass,对于每个像素,遍历光源,并执行以下流程:1.判断是否在光照体积中。2.计算漫反射与高光(如何计算取决于选取了什么光照模型)3.计算阴影,如果这个光源有阴影贴图。4.将光照计算结果累加到帧缓冲,这里光照计算结果是 HDR,通常以 vec3 或者 half3 表示,不需要归一化。
Shadow Map 阴影贴图
以光源位置为摄像机位置进行一次渲染得到深度图(点光源或聚光灯用透视矩阵,平行光用正交矩阵),这个深度图就是光源能够看到的“表面”,名叫阴影贴图(Shadow Map)。
在片元着色时,对于屏幕空间的每个像素,将屏幕空间坐标逆变换为世界坐标,然后再变换到光照视角的屏幕空间坐标,用 xy 值采样 Shadow Map 得到“表面”深度值,比对 z 值与“表面”深度值以判断其对于光源是否可见,如果不可见,则对应像素应被渲染为阴影。
从屏幕空间坐标到世界坐标的全流程(以 OpenGL 为例):
先计算出ndc,注意 OpenGL 中裁切空间 z 轴取值范围是 [-1, 1]。
vec2 ndc;
ndc.x = (screenPos.x / width) * 2.0 - 1.0;
ndc.y = (screenPos.y / height) * 2.0 - 1.0;
float z = depth * 2.0 - 1.0; // depth buffer → clip space depth
重投影
对于某个光源,漫反射计算时,背光面已经被拉低了亮度,不应再因为投影渲染降低亮度。故而在进行投影计算时应该剔除掉背向光源的像素。同一个光源因为一些管线的设计失误重复计算阴影也称为重投影。
阴影痤疮
由于浮点运算的精度丢失,物体表面虽然暴露给光源,但某些像素转换得到的深度却略小于 shadow map 中对应像素,导致本该被照亮的表面产生许多阴影黑点,类似于痤疮。
解决方法是给计算得到的深度或者 shadow map 增加一个固定偏移,让表面转换后的深度值能稳定大于 shadow map 的采样值。这个固定偏移不宜过大,一般 0.01 即可,如果太大则会导致“阴影悬空”问题(即物品与地面交界的地方阴影产生断层)
级联阴影映射 (CSM) 与 PCF(Percentage-Closer Filtering)软阴影
https://zhuanlan.zhihu.com/p/1910444536964030540
PBR
PBR 是“物理基础渲染”(Physically Based Rendering)的缩写,是一系列计算机图形学中用于创建更加逼真的材质和光照效果的技术方法。
PBR 引入了更多的材质属性:
- 金属度(Metalness):指示材质是否具有金属特性,影响反射的颜色。金属度高的材质反射受自有颜色影响大,受环境光颜色影响小(绿色的金属在红光中呈现暗色或黑色,而非红色)。在镜面反射和高光计算中,金属度高的材质也会让镜面反射和高光的颜色变成金属自有色。
- 粗糙度(Roughness):表面的光滑程度,影响高光的大小和模糊程度、镜面反射的的程度。
- 环境遮蔽
- 高度
- ...
高度如何表现
常用的几种渲染技术:视差映射(Parallax Mapping, PM)、视差遮蔽映射(Parallax Occlusion Mapping, POM)、置换映射(真实几何,通过真实的网格实现)。
视差映射:以 u 方向(x)、v 方向(y)、垂直方向(z)三轴构成坐标系(这个坐标系名为切线空间),将视线向量转换到这个坐标系下,然后正比于 xy·height 对 uv 应用偏移。
视差遮蔽映射(POM):以一定粒度(步数)沿视线方向,步进探测与高度图的交点,从而得出 uv 的偏移,类似于碰撞检测。
置换映射:用真实的几何网格展示凹凸细节。
色调映射 & gamma 校正
Reinhard色调映射
公式:
将 \left [ 0, ∞ \right ) 亮度数值映射到 \left [ 0,1 \right ) 。该函数曲线在靠近 0 的部分斜率接近 1,即对画面暗部进行接近线性的映射。亮度超过 0.5 时斜率降低至 0.5 以下,即对高亮部分强烈压缩,对过曝有一定抑制作用。
Gamma 校正和 sRGB
早期使用阴极射线管(Cathode Ray Tube)的显示器显示的亮度与施加在射线管上的电压并不是线性关系,而是:
这个亮度与信号的变化关系称为 gamma 变换。
为了以正确的亮度显示图片,工程师们发明了 sRGB 色彩空间,将线性的颜色映射为 pow(color, 1/2.2),来抵抗显示设备的 gamma 变换。这个映射成为 gamma 校正。
除了抵抗 gamma 变换,在使用整数表示颜色时,gamma 校正后的颜色空间给予了低亮度部分更多的码位,使得图片可以承载更多的暗部细节,这符合人眼观察事物的特性:即对于较暗的光线变化更为敏感,更容易注意到较暗的细节。