CG·概念复习
着色方法
漫反射分量
一般使用的是Lambert模型——漫反射的光强与入射光方向和反射点处表面法向量的夹角余弦值成正比。
公式表达为——反射光强 = 入射光强 *(入射光 × 顶点法线)
(今天才发现这个模板没法用markdown写公式…先凑合吧
镜面反射分量
常用模型为Phong,公式表达为——镜面反射光强 = 入射光强 * 反射光方向 * 视线方向
三种着色处理方法
-
Flat Shading,平滑着色:三角面共用同一个颜色
-
Gouraud Shading,高洛德着色:逐顶点线性插值
-
Phong Shading:根据顶点法线逐像素计算颜色,开销最大效果最好
对比图如下——
透明渲染和透明排序
两种基本的排序方法
-
Z-buffer⚠️
-
油画家算法
也称有限填充算法,将场景中的多边形根据深度排序,由远到近绘制。
优点——准确,缺点——排序开销大。
两种高级的排序算法
-
加权平均值算法:一种无序透明渲染算法。每个像素位置上可能有多个颜色,以这些颜色的alpha值作为权重,求和,然后取平均值,用得到的加权平均值替换该像素位置的颜色,可以得到近似准确的透明结果。优点——十分高效,缺点——得到的是近似效果。
-
深度剥离算法:对深度值进行排序,第一轮计算先获取z值最小的点并输出(这一波得到的就是表层可视的一层),第二轮计算“剥离”第一轮中的点,z值“第二小”的点并输出,…以此类推,分多个pass分别渲染/剥离出距离摄像机第N近的片元。下面这图解释得挺好👇🏼这一算法适合解决物体循环覆盖的情况(如,克莱因瓶)。
伽玛校正
为图像进行伽玛编码的目的是用来对人类视觉的特性进行补偿,从而根据人类对光线或者黑白的感知,最大化利用表示黑白的数据位/带宽。
纹理贴图及相关技术
纹理管线
图像纹理中的像素通常被称为纹素(Texels),区别于屏幕上的像素。
通过将投影方程运用于空间中的点 ,从而得到一组称为参数空间值的关于纹理的数值。这个过程就称为纹理映射。
以下是一个纹理管线,也就是为单个纹理应用纹理贴图的过程👇🏼
S1. 通过投影方程将三维空间中的点坐标变换为值域在0到1的二维空间uv坐标
S2. 使用映射函数将uv转换到纹理空间坐标(如,图像分辨率为256x256,则转换后的纹理空间坐标为(256×u,256×v),小数向下取整)
S3. 使用纹理空间坐标作为索引获取纹理中对应的像素值
S4. 对检索后的像素值进行变换,获取新值用于改变材质、法线、着色等表面属性
投影函数
投影函数的功能就是将空间中的三维点转化为二维空间的uv坐标。一般投影函数通常在美术建模阶段使用,并将投影结果存储于顶点数据中。当然也有特殊情况:
-
OpenGL提供一些不同的投影函数,利用空闲时间让图形加速器执行投影过程,这样可以节省带宽,避免了输送纹理坐标到图形加速器的步骤
-
在顶点、像素着色器中使用投影函数(比如triplanar mapping、环境贴图)
映射函数
映射函数(The Corresponder Function)的作用是将参数空间坐标(parameter-space coordinates)转换为纹理空间位置(texture space locations)。
uv坐标的值域在(0,1),超出这个值域的纹理,其显示方式由映射函数决定。OpenGL中称这些映射函数为封装模式(Wrap Mode),常见的映射函数有:repeat,mirror,clamp…
体纹理💗
体纹理(Volumn Texture)又称三维纹理。体纹理由许多张2D纹理组成,用于描述三维空间数据的图片,体纹理通过三维纹理坐标进行访问。
其优势在于——①可以避免二维参数化中常发生的变形和接缝问题②用于表示诸如木材和大理石等材料的提及结构,表现更逼真。
💗 备注:切割面贴图
其劣势在于——作为表面纹理时非常低效,因为绝大多数样本未起作用。
Cubemap
Cubemap利用6幅二维纹理图像构成一个以原点为中心的纹理立方体。根据三维向量来索引纹素,例如给定矢量(-3.2,5.1,-8.4,取最大绝对值对应的面——-Z面,对剩余两个坐标值(-3.2,-8.4)进行uv映射计算——到((-3.2 / 8.4 + 1)/ 2,(5.1/ 8.4 + 1)/ 2) ≈ (0.31,0.80),然后索取对应纹理像素值渲染。
纹理缓存※
纹理压缩※
程序化贴图纹理
程序化贴图纹理适合创建诸如木材、石材、金属、石头等材质,通常使用到噪音函数、扰动函数等随机性函数来进行材质生成。
程序贴图纹理通常用于离线渲染应用程序,而图像纹理在实时渲染中更为常见。但随着GPU的发展,程序纹理在实时应用程序中也变得愈加常见,但他们不可能完全替代图像纹理。
凹凸贴图
几种凹凸贴图与其改进方法的总结对比。
-
移位贴图:也称高度图。
-
法线贴图:将法线值存入纹理中,图片纹理的颜色表示法线坐标,rgb分别对应法线的xyz通道,因此大多数时候法线贴图呈现偏蓝色。
-
视差贴图:视差贴图能弥补法线贴图无法营造巨大的高度落差和明显遮挡效果的不足。
基本的视差贴图的算法如下,其实也只是一种近似的算法:
vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir)
{
float height = texture(depthMap, texCoords).r;
vec3 p = viewDir.xy / viewDir.z * (height * height_scale);
return texCoords - p;
}
进一步的优化方法如下图所示,将总深度分层,然后逐层比对(从0到1),如下图分5层则要对比3次获得比较准确的位移向量。
4.浮雕贴图:relief mapping。
高级着色
BRDF
延迟渲染
正向渲染
与之对应的正向渲染,则意味着在场景中根据所有光源计算某一物体的渲染,之后再根据所有光源计算下一物体的渲染…一次类推遍历所有物体,计算量可想而知。复杂度呈O(光源数×物体数)。假如计算过程中出现任何纰漏,整个场景的着色计算都会收到影响。
延迟着色
延迟着色(Deferred Shading),是将着色计算延迟到深度测试之后进行处理的一种渲染方法。
现将所有物体绘制到屏幕空间的缓冲,即需要处理的仅仅是屏幕空间有限的像素,再逐光源对该缓冲进行着色。如此复杂度降至O(物体数+光源数)。
几何缓冲区
G-buffer,Geometric buffer。用于存储每个像素对应的位置、法线、漫反射颜色、材质参数等信息。根据这些信息,可以在二维空间对每个像素进行光照处理。
延迟渲染过程
分为两个Pass——
- 几何处理阶段,将场景数据存储到G-buffer
- 光照处理阶段,光照计算过程和正向渲染一样,但是只需从G-buffer获得输入变量
延迟渲染(相对于正向)的优势在于——
- 计算量骤减
- 在深度测试后进行,避免了无用计算
- 对后处理支持良好
- 对采用大量光源的场景优势尤为明显
缺点在于——
- 内存开销大,G-buffer读写是性能瓶颈
- 因为使用了MRT,导致使用内存的带宽比直接渲染多(现代图形硬件的数学计算比内存的访问快。再加上在未来的硬件中,可能数学计算和内存的表现会有更大的偏重, 这就导致了延迟着色技术可能不是一个长久的解决方案)
- 透明物体渲染上存在问题,需要正向渲染
- 对MSAA支持不友好⚠️
- 无法支持多shader(材质)
延迟渲染改进
1.延迟光照(Deffered Lighting),也称Light Pre-Pass,旨在减少传统延迟渲染使用G-buffer时占用过多开销。
- 渲染不透明物体。首次渲染只逐像素将法线向量和镜面扩展因子写入缓冲区。包含信息更少,更轻量,适合单个输出颜色缓冲区,不需要MRT(多渲染目标)支持
- 渲染光照。只计算漫反射和镜面着色
- 对不透明物体进行第二次渲染。读取材质的光照数据进行计算(支持多材质),集合之前的计算写入最终颜色缓冲区
- 使用非延迟着色渲染半透明几何体🌼
优势——
- G-buffer的尺寸减小
- 多材质友好,可以对不同几何体使用不同的shader(因为第二次渲染光照时其实是正向渲染)
缺点——
- 需要绘制场景两次。
2.分块延迟渲染(Tile-Based Deferred Rendering,TBDR)⚠️。将屏幕拆分为细小的栅格,计算每个分块会受到的光源影响,然后将光源索引存储在分块的光源列表里,最后逐个分块着色。
每个G-buffer只会被读取1次,写入颜色buffer也是1次,大幅降低了内存带宽用量。不过需要多计算的是各个光源会影响哪些分块(光剔除)。
环境映射⚠️
Environment Mapping,是使用IBL(使用基于图像的光照)技术,是一种预先计算的纹理图像模拟复杂镜面的高效方法。这种方法是实际反射的一种近似,没有考虑自反射(无法看到物体反射自身的某一部分)。