该内容基于Games101课程,内容可能有些杂乱,后续会详细整理。建议学习shader之前要看过一遍101

渲染管线基础

所谓渲染就是把三维空间的物体变成一张图

image-20250508123516010

具体绘制流程如下:

  • 模型空间变换到世界空间
  • 世界空间变换到观察空间
  • 观察空间变换到屏幕空间
  • 拿到屏幕空间对应映射的位置后,进行光栅化绘制像素
image-20250518152728613

一、线性代数入门

1.向量(Vectors)

向量最重要的两个属性:方向和大小

image-20250508124334225

单位向量:向量本身/长度 得到和原始向量同方向长度为1的向量

image-20250508124551181

向量求和

image-20250508124709067

笛卡尔坐标系描述向量,默认向量一个一个往下写(列向量)

image-20250508124858404

向量点乘 为 a长度 * b长度 * 夹角余弦

点乘可以得到向量之间的夹角

单位向量点乘,就是夹角余弦

image-20250508125238676

点乘运算法则

image-20250508125538286 image-20250508125634017

点乘作用:得到夹角和投影

投影:比如b投影在a上,那么一定是沿着a的。所以b的投影向量 = K*a的单位向量

image-20250508130145033

投影作用:将一个向量分解成两个向量。

image-20250508130255958

点乘判断前后 主要是因为cosθ的值影响正负

如果点乘结果>0 锐角 前方

点乘结果= 0 两向量夹角 直角 方向一致

点乘结果 < 0 钝角 后方

image-20250508131100678


叉乘:向量 X 向量= 向量 得到的向量与叉乘的两个向量都垂直

方向:右手螺旋定则, a X b ,a旋转到b方向用四指去旋转为逆时针,所以结果方向向上

image-20250508131750104

image-20250508132229860 image-20250508132357695

叉乘作用:判断左右(右手螺旋定则抓一下),判断内外

A X B ——》若A在右则为 正 ,左侧为 负

image-20250508132729482

判断内外:AP X AB >0 BP X BC >0 CP X CA>0 说明点p在三角形内部 只需判断p点一直在三条边的左边或者右边即可

image-20250508133006603

2. 矩阵

矩阵的乘积

image-20250508133830283

运算法则

image-20250508133953113

点乘和叉乘的矩阵形式

image-20250508134157412

二、变换

1. 我们为什么要学习变换

模型变换和视图变换

我们要从三维世界的几何物体映射到二维图片上,这一过程就是要进行变换。

2.2D变换

(1)2D Scale变换

image-20250508150117645

写成矩阵为

image-20250508150302560

(2) 对称操作

image-20250508150349949

image-20250508150430056

(3)切变(Shear Matrix)

如图每个点的y坐标没有变,x坐标移动了a*y

image-20250508150759053

(4)旋转变换

默认原点为中心,逆时针为旋转方向

只有旋转矩阵为正交矩阵,即矩阵的逆等于矩阵的转置

image-20250508151216823

公式推导:选特殊点,带值。选左上和右下两个点即可

image-20250508151552695

(5)线性变换

能用以下方式表达出的就是线性变换

image-20250508151828691

3.齐次坐标和平移变换

有一种变换:平移变换。这个变换很特殊,它不能写成线性变换。但是不想把平移当作特殊情况去处理。所以我们引入齐次坐标。

image-20250508152219714

齐次坐标就是:将原本的n维向量或矩阵用n+1维表示

好处1:可以明确区分点和向量 w=1为点 =0为向量

好处2:可以表示平移变换

image-20250508152742772

为什么要区分点和向量?答:向量具有平移不变性,向量平移后不变。防止点+点,这样是无意义的

image-20250508153418695

齐次坐标表示的2D变换

image-20250508153703960

4.复合变换

将上述所有变换组合起来中进行变换

从右往左计算,变换顺序为:先缩放、后旋转、再平移

image-20250508154431108

在进行复合运算时,变换的结果依赖于变换的顺序

原因:矩阵不满足交换律,所以不同的变换顺序,结果是不一样的

5.变换分解

如果我们想按照某一点c旋转该如何处理?

首先平移-c方向,然后旋转,再平移回去

image-20250508155122622

6.3D变换

与2D变换大同小异,只是多了一个z轴向

image-20250508155537082 image-20250508155558249

3D旋转矩阵

image-20250508161114339

一般性的旋转如何处理?

绕任何角度,都可以写成绕xyz轴的组合.

为什么绕y轴那个矩阵的副对角线跟其他的两个不一样?

  • 答:因为是z叉乘x 得到y,并不是x叉乘z。

三、视图变换(View/Camera Transformation)

1.什么是视图变换

  • 找一个好的位置,大家摆好姿势(模型空间变换)
  • 找一个好的角度去放置摄像机(视图空间变换)
  • 拍摄(投影变换)

2 .如何进行视图变换

  • 定义摄像机image-20250517233250769
  • 把相机锁死在(0,0,0)处,把相机放置在标准观察位置上
  • image-20250517233428046
  • 摄像机防止在标准位置上操作
  • image-20250517233621443

3.透视投影和正交投影

透视投影:有近大远小的特性。

正交投影:没有近大远小,所有东西不管远近最后渲染的大小都一样。

image-20250518094151721

正交变换:把远处和进处的物品全都挤到一个平面上

  • 1.把相机放到远点上,看-z方向
  • 2.扔掉z轴
  • 3.就能得到正交变换的图像
  • 2和3步其实就是把长方形视锥体的xyz坐标范围映射在(-1,1)长宽高为2的正方体中这一步叫做正则
image-20250518094623934 image-20250518095305461

注:因为是沿着-z(要保证左手坐标系)所以近大于远

透视变换:

  • 将透视视锥体挤成一个长方体
  • 近裁剪面上面所有点保持不变
  • 远裁剪面上的z值不变和中心点不变
  • 远裁剪面宽高映射成近裁剪面宽高
  • 然后再正交投影
image-20250518100214422
  • 从一个侧视图看,我们可以看到一个相似三角形,即可得出缩放后y‘的值
image-20250518100411646
  • xy同理,会被映射到如下向量
image-20250518100657062
  • 得到一个不完全的变换矩阵

image-20250518100900353

  • 因为z与xy无关,所有第三行前两个位置为0。
  • 带入远平面中心点。
  • image-20250518101649206
  • image-20250518101829270
  • image-20250518101900065

四、屏幕空间变换(这里指的就是视口变换)

就是把视图变换后得到的(-1,1)范围的立方体中的内容,映射为二维屏幕中的屏幕坐标。并得不到图像

学术上说就是将裁剪空间的坐标映射到屏幕坐标系,确定图像在屏幕上的显示区域。

如果要得到图像需要把这个阶段得到的数据打散成像素才行这个过程就是光栅化

1.定义屏幕空间

image-20250518103223146

注:在unity中左下角像素为(0,0),右上角像素坐标就是屏幕分辨率

  • 视口变换:把立方体映射到屏幕坐标上
image-20250518103820088
  • 到这一步仍然还只是一些三角形,一些数据,我们接下来要把这些打散成像素,变成真正的图。
  • 视口转换只是确定了图像在屏幕上的位置和缩放,真正的图像内容生成还需要后续处理,包括光栅化和着色。

五、光栅化

1.什么是光栅化

把三维空间的几何形体显示在屏幕上就是光栅化,得到像素。

我们在屏幕变换中已经得到图像显示在屏幕上的坐标,这一步就是为了把像素画在上面。

实时:能达到30FPS画面就是实时

  • 经过MVP变换后拿到屏幕上的视口坐标,现在做的就是把坐标围成的三角形变成像素
  • image-20250518141157639
  • 这里通过采样去处理。采样就是:函数离散化,把一个连续的轴拆成一个一个。我们利用像素中心对屏幕空间进行采样。
  • 1.判断像素中心是否在三角形内,如果碰巧在边界,自行设置规则处理即可。
  • image-20250518141538997
  • 2.使用包围盒把三个点所围成的最小长方形,只在把包围盒内部进行光栅化处理
  • image-20250518142112519
  • 3.我们把包围盒中的像素方块填充完得到如下。这和想得到的三角形不一致,所以我们要抗锯齿(反走样)
  • image-20250518142850700

2.抗锯齿

  • 为什么会出现锯齿?
  • 答:屏幕空间采样精度不够。

采样带来的问题:

  • 锯齿
  • 摩尔纹
  • 回答这些现象:信号变化的速度太快了,以至于采样的速率跟不上。
  • image-20250518143351399
  • 如何解决抗锯齿?
  • 答:在对屏幕空间进行采样之前,先对其进行模糊(加滤波)后,再进行采样。这样我们得到一些比较模糊点,我们缩小之后就会有轮廓,不会出现很明显的锯齿。大概了解即可
  • image-20250518143833240

3.深度测试

  • 当有很多三角形叠在一起,互相遮挡如何解决????
  • 解决方法:深度缓存/深度缓冲
  • 为什么画家算法不行???从远到近画
    • 如下图三个互相遮挡,这就没法定义深度关系
  • image-20250518150922105

深度缓存

生成效果图的同时,生成一张深度图。这个图只存像素的最浅的深度信息。

比如我们那正方体上一个像素点举例:

  • 我们先画后面地板像素,并且深度缓存记录地板像素的深度信息

  • 在画正方体,发现正方体会遮挡到。当前的正方体的深度要小于地板的深度,那就要把正方体像素画上去

    并且要把深度缓存更新为更浅的。

  • 流程:

    • 开始深度缓存都是记录无限远的。
    • 然后如果光栅化的像素深度比之前的小,就会更新
  • image-20250518151335447
  • image-20250518152046280

六、着色(shading)

1.什么是着色

就是给像素根据光照明暗添加上不同的颜色和阴影