2509 字
13 分钟

图形学基础

2025-05-08
无标签
文章目录

渲染管线#

各种缓冲和测试的含义#

执行顺序 alpha test -> stencil test -> depth test

Alpha测试:根据物体的透明度来决定是否渲染
像素值一般是由RGBA四个分量来表示的,其中的A是alpha,表示的是物体的不透明度。1代表完全不透明,0代表完全透明。可选的 alpha 测试可在深度测试执行前在传入片段上运行。片段的 alpha 值与参考值作某些特定的测试(如等于,大于等),如果片段未能通过测试,它将不再进行进一步的处理。 alpha 测试经常用于不影响深度缓存的全透明片段的处理。

深度测试:根据物体的深度决定是否渲染
图形管线会先对每一个位置的像素存储一个深度值,称为深度缓冲,代表了该像素点在3D世界中离相机最近物体的深度值。于是在计算每一个物体的像素值的时候,都会将它的深度值和缓冲器当中的深度值进行比较,如果这个深度值小于缓冲器中的深度值,就更新深度缓冲和颜色缓冲的值,否则就丢弃。

模板测试:根据物体的位置范围决定是否渲染。
模板测试就是用片段指定的参考值与模板缓冲中的模板值进行比较,如果达到预设的比较结果,模板测试就通过了,然后用这个参考值更新模板缓冲中的模板值;如果没有达到预设的比较结果,就是没有通过测试,就不更新模板缓冲。

深度测试在哪个阶段,Early-Z呢,又会存在什么问题?#

 深度测试位于像素处理阶段的测试合并阶段,Early-Z是一种提前深度测试的技术,它位于光栅化阶段之后,像素处理阶段之前,目的是减少进入像素着色阶段的片段,优化性能。

Early-Z会带来透明测试的冲突,例如某个片元A虽然遮挡了另一个片元B,但A却是透明的,GPU应当渲染的是片元B,这就产生了矛盾,这就是透明度测试会导致性能下降的原因(因为无法用Early-Z)

局部光照模型#

由于环境光是常数

经验化的简单光照模型。光栅化算法一次只考虑一个像素的光照强度,因此局部光照模型不能计算某像素受其他像素影响的光照强度部分。也就是说,局部光照模型只对物体进行直接光照的计算,而不考虑其他的间接影响。

Lambert漫反射模型phong光照明模型BlinnPhong光照模型
Lambert光照模型主要是用来模拟粗糙物体表面的光照现象反射强度与光线的入射角度有关系DiffuseLight=I*cosθ,其中cosθ=dot(N,L)(L为入射光线的反向量,N为当前表面的法向量方向)

Phone模型,镜面反射,反射光强度和反射光线与视线夹角有关。

其中 RR 向量可以计算公式为:

R=2(LN)NLR=2*(L \cdot N)*N - L

则整体公式为

Spec=(LightColorSpecularColor)(VR)GlossinessSpec = (LightColor*SpecularColor)(V \cdot R)^{Glossiness}

BlinPhone基本和Phone一致,只是将反射向量 RR 换成半程向量 HH 其中

H=(V+L)/V+HH = (V+L)/||V+H||

全局光照,像素会受到其他像素影响,光线追踪。

着色#

Gouraud Shading 计算顶点光照,然后通过插值计算像素的着色 Phone Shading 每一个图元逐像素的法线进行光照计算,计算量较大,但是效果最好

AO#

粗略的全局光照算法。用于计算没一点是如何接受环境光的。

SSAO:对于屏幕空间(Screen-filled Quad)上的每一个片段,我们都会根据周边深度值计算一个遮蔽因子(Occlusion Factor)。这个遮蔽因子之后会被用来减少或者抵消片段的环境光照分量。遮蔽因子是通过采集片段周围球体/半球体核心(Kernel)的多个深度样本,并和当前片段深度值对比而得到的。高于片段深度值样本的个数就是我们想要的遮蔽因子。

抗锯齿#

光栅化的时候,是以像素中心点是否被三角形覆盖来决定是否生成片段,因此有些片段覆盖了采样点就生成,有些没有覆盖就不生成,最终导致了锯齿现象。

MVP#

模型矩阵M(Model):将局部坐标变换到世界坐标;

观察矩阵V(View):将世界坐标转换为观察坐标,或者说,将物体的世界坐标,转换为在相机视角下的坐标;

投影矩阵P(Projection):将顶点坐标从观察空间变换到裁剪空间(clip space) ,后续的透视除法操作会将裁剪空间的坐标转换为标准化设备坐标系中(NDC)。 一旦顶点位于相机空间中,最终可以通过应用投影变换将其变换到裁剪空间。投影矩阵通过定义相机视图的范围来编码场景中有多少被捕获在渲染中。两种最常见的投影类型是透视投影和正交投影。

欧拉角、矩阵和四元数表示旋转的区别和优缺点#

(1)欧拉角:定义了绕着三个坐标轴的旋转角,来确定刚体的旋转位置的方式,包括俯仰角pitch,偏航角yaw和滚动角roll;它的优点是比较直观,而且单个维度上的角度也比较容易插值;缺点是它不能进行任意方向的插值,而且会导致万向节死锁的问题,旋转的次序对结果也有影响。
万向锁的原因是内轴无法带动外轴旋转。
无伤理解欧拉角中的“万向死锁”现象_哔哩哔哩_bilibili

(2)矩阵:优点是不受万向节死锁的影响,可以独一无二的表达任意旋转,并且可以通过矩阵乘法来对点或矢量进行旋转变换;现在多数CPU以及所有GPU都有内置的硬件加速点积和矩阵乘法;缺点是不太直观,而且需要比较大的存储空间,也不太容易进行插值计算。

(3)四元数:四元数的好处是能够串接旋转;能把旋转直接作用于点或者矢量;而且能够进行旋转插值;另外它所占用的存储空间也比矩阵小;四元数可以解决万向节死锁的问题。

判断点在凸多边体内#

  1. 射线法,延点和任意多边体顶点方向做射线,偶数则在多边体外,奇数则在多边体内
  2. 平面向量,对于没一个平面,沿法线向量和点与平面任一点的向量做内积,若均大于0则在多面体内部

法线贴图和切线空间#

切线空间:顶点原点是顶点位置,Z轴是切线,一般指定纹理方向作为XY(且与Z轴垂直) 法线贴图的rgb为什么呈现出蓝色 (0.5, 0.5, 1) ,因为法线某一个轴的范围在 (-1, 1)之间,需要和rgb的 (0,1)做映射。那么默认的法线是(0,0,1),映射公式为 (tangent+1)/2(tangent+1)/2,这时候结果就是(0.5,0.5,1)。

主要是光照计算一般放在切线空间中

  1. 与模型无关,可以重用和变形(发生形变时,法线可以自适应变换)
  2. 切线空间法线Z分量始终为正,这样,就可以从XY重建,节省通道
  3. 切线空间允许容易地混合多个法线贴图: 基础法线贴图(如皮肤的主要特征) 细节法线贴图(如毛孔、皱纹等微观细节) 程序化生成的法线(如动态伤痕、积水效果)

Lerp#

Lerp是圆上弦的等分,而Slerp是弧的等分

Linear interpolation : 线性插值

Normalized Linear interpolation : 归一化线性插值(唯一做的事情就是线性插值之后进行归一化) 由于是按照弦长的比例来插值的,即在弦上是匀速的,故在角速度或弧上并不匀速。

Spherical Linear interpolation : 球面线性插值,对四元数做这个操作能保证角速度均匀

SLerp(v0,v1,t)=sin(1t)θsinθv0+sintθsinθv1SLerp(v_{0},v_{1},t)=\frac{\sin(1-t)\theta}{\sin \theta}v_{0}+\frac{\sin t\theta}{\sin \theta}v_{1}

Alpha混合#

Blend Src Dst Blend SrcAlpha OneMinusSrcAlpha 其中Src为片元颜色,Dst为缓存颜色

Blend DstColor Zero Multiply 正片叠底 Blend DstColor SrcColor 两倍相乘

BlendOp Min Blend One One 变暗

BlendOp Max Blend One One 变亮

透明物体渲染需要关闭深度写入,否则会导致后面的物体无法正常渲染

延迟渲染#

先进行深度测试,再进行着色渲染。且将光照计算从三维空间放到二维空间。 GBuffer-存储像素位置,法线,漫反射信息,方便直接在像空间进行逐像素光照处理。

1、几何处理阶段(Geometry Pass)。这个阶段中,我们获取对象的各种几何信息,并将第二步所需的各种数据储存(也就是渲染)到多个G-buffer中;

2、光照处理阶段(Lighting Pass)。在这个pass中,我们只需渲染出一个屏幕大小的二维矩形,使用第一步在G-buffer中存储的数据对此矩阵的每一个片段计算场景的光照;光照计算的过程还是和正向渲染以前一样,只是现在我们需要从对应的G-buffer而不是顶点着色器(和一些uniform变量)那里获取输入变量了。

优点:复杂度仅O(m+n),而前向渲染为O(m*n) 缺点:透明渲染存在问题

顺序无关渲染#

深度剥离算法N个Pass