渲染管线基础
该内容基于Games101课程,内容可能有些杂乱,后续会详细整理。建议学习shader之前要看过一遍101
渲染管线基础
所谓渲染就是把三维空间的物体变成一张图

具体绘制流程如下:
模型空间变换到世界空间
世界空间变换到观察空间
观察空间变换到屏幕空间
拿到屏幕空间对应映射的位置后,进行光栅化绘制像素

一、线性代数入门
1.向量(Vectors)
向量最重要的两个属性:方向和大小

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

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

向量点乘 为 a长度 * b长度 * 夹角余弦
点乘可以得到向量之间的夹角
单位向量点乘,就是夹角余弦

点乘运算法则


点乘作用:得到夹角和投影
投影:比如b投影在a上,那么一定是沿着a的。所以b的投影向量 = K*a的单位向量
投影作用:将一个向量分解成两个向量。
点乘判断前后
主要是因为cosθ的值影响正负
如果点乘结果>0 锐角 前方
点乘结果= 0 两向量夹角 直角 方向一致
点乘结果 < 0 钝角 后方
叉乘:向量 X 向量= 向量 得到的向量与叉乘的两个向量都垂直
方向:右手螺旋定则, a X b ,a旋转到b方向用四指去旋转为逆时针,所以结果方向向上


叉乘作用:判断左右(右手螺旋定则抓一下),判断内外
A X B ——》若A在右则为 正 ,左侧为 负

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

2. 矩阵
矩阵的乘积
运算法则

点乘和叉乘的矩阵形式

二、变换
1. 我们为什么要学习变换
模型变换和视图变换
我们要从三维世界的几何物体映射到二维图片上,这一过程就是要进行变换。
2.2D变换
(1)2D Scale变换

写成矩阵为
(2) 对称操作

(3)切变(Shear Matrix)
如图每个点的y坐标没有变,x坐标移动了a*y

(4)旋转变换
默认原点为中心,逆时针为旋转方向
只有旋转矩阵为正交矩阵,即矩阵的逆等于矩阵的转置

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

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

3.齐次坐标和平移变换
有一种变换:
平移变换
。这个变换很特殊,它不能写成线性变换
。但是不想把平移当作特殊情况去处理。所以我们引入齐次坐标。
齐次坐标就是:将原本的
n维向量
或矩阵用n+1维
表示好处1:
可以明确区分点和向量
w=1为点 =0为向量好处2:
可以表示平移变换
为什么要区分点和向量?答:向量具有平移不变性,向量平移后不变。防止点+点,这样是无意义的

齐次坐标表示的2D变换

4.复合变换
将上述所有变换组合起来中进行变换
从右往左
计算,变换顺序为:先缩放、后旋转、再平移

在进行复合运算时,变换的结果依赖于变换的顺序
原因:
矩阵不满足交换律,所以不同的变换顺序,结果是不一样的
5.变换分解
如果我们想按照某一点c旋转该如何处理?
首先平移-c方向,然后旋转,再平移回去

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


3D旋转矩阵

一般性的旋转如何处理?
绕任何角度,都可以写成绕xyz轴的组合.
为什么绕y轴那个矩阵的副对角线跟其他的两个不一样?
- 答:因为是z叉乘x 得到y,并不是x叉乘z。
三、视图变换(View/Camera Transformation)
1.什么是视图变换
- 找一个好的位置,大家摆好姿势(模型空间变换)
- 找一个好的角度去放置摄像机(视图空间变换)
- 拍摄(投影变换)
2 .如何进行视图变换
- 定义摄像机
- 把相机锁死在(0,0,0)处,把相机放置在标准观察位置上
- 摄像机防止在标准位置上操作
3.透视投影和正交投影
透视投影:有近大远小的特性。
正交投影:没有近大远小,所有东西不管远近最后渲染的大小都一样。
正交变换:把远处和进处的物品全都挤到一个平面上
- 1.把相机放到远点上,看-z方向
- 2.扔掉z轴
- 3.就能得到正交变换的图像
- 2和3步其实就是把
长方形视锥体的xyz坐标范围
映射在(-1,1)长宽高为2的正方体
中这一步叫做正则![]()
![]()
注:因为是沿着-z(要保证左手坐标系)所以
近大于远
透视变换:
将透视视锥体挤成一个长方体
近裁剪面上面所有点保持不变
远裁剪面上的z值不变和中心点不变
远裁剪面宽高映射成近裁剪面宽高
- 然后再正交投影
![]()
- 从一个侧视图看,我们可以看到一个相似三角形,即可得出缩放后y‘的值
![]()
- xy同理,会被映射到如下向量
![]()
- 得到一个不完全的变换矩阵
- 因为z与xy无关,所有第三行前两个位置为0。
- 带入远平面中心点。
四、屏幕空间变换(这里指的就是视口变换)
就是把视图变换后得到的(-1,1)范围的立方体中的内容,映射为二维屏幕中的屏幕坐标。并得不到图像
学术上说就是将裁剪空间的坐标映射到屏幕坐标系,确定图像在屏幕上的显示区域。
如果要得到图像需要把这个阶段得到的数据打散成像素才行
这个过程就是光栅化
。
1.定义屏幕空间
![]()
注:在unity中左下角像素为(0,0),右上角像素坐标就是屏幕分辨率
- 视口变换:把立方体映射到屏幕坐标上
![]()
- 到这一步仍然还只是一些三角形,一些数据,我们接下来要把这些打散成像素,变成真正的图。
- 视口转换只是确定了图像在屏幕上的位置和缩放,真正的图像内容生成还需要后续处理,包括光栅化和着色。
五、光栅化
1.什么是光栅化
把三维空间的几何形体显示在屏幕上就是光栅化,得到像素。
我们在屏幕变换中已经得到图像显示在屏幕上的坐标,这一步就是为了把像素画在上面。
实时:能达到30FPS画面就是实时
- 经过MVP变换后拿到屏幕上的视口坐标,现在做的就是把坐标围成的三角形变成像素
- 这里通过采样去处理。采样就是:函数离散化,把一个连续的轴拆成一个一个。我们利用像素中心对屏幕空间进行采样。
- 1.判断像素中心是否在三角形内,如果碰巧在边界,自行设置规则处理即可。
- 2.使用包围盒把三个点所围成的最小长方形,只在把包围盒内部进行光栅化处理
- 3.我们把包围盒中的像素方块填充完得到如下。这和想得到的三角形不一致,所以我们要抗锯齿(反走样)
2.抗锯齿
- 为什么会出现锯齿?
- 答:屏幕空间采样精度不够。
采样带来的问题:
- 锯齿
- 摩尔纹
- 回答这些现象:信号变化的速度太快了,以至于采样的速率跟不上。
- 如何解决抗锯齿?
- 答:在对屏幕空间进行采样之前,先对其进行模糊(加滤波)后,再进行采样。这样我们得到一些比较模糊点,我们缩小之后就会有轮廓,不会出现很明显的锯齿。大概了解即可
3.深度测试
- 当有很多三角形叠在一起,互相遮挡如何解决????
- 解决方法:
深度缓存/深度缓冲
- 为什么画家算法不行???从远到近画
- 如下图三个互相遮挡,这就没法定义深度关系
深度缓存
生成效果图的同时,生成一张深度图。这个图只存像素的最浅的深度信息。
比如我们那正方体上一个像素点举例:
我们先画后面地板像素,并且深度缓存记录地板像素的深度信息
在画正方体,发现正方体会遮挡到。当前的正方体的深度要小于地板的深度,那就要把正方体像素画上去
并且要把深度缓存更新为更浅的。
流程:
- 开始深度缓存都是记录无限远的。
- 然后如果光栅化的像素深度比之前的小,就会更新
六、着色(shading)
1.什么是着色
就是给像素根据
光照
和明暗
添加上不同的颜色和阴影