本文说了有关光栅化的事情
光栅化是什么
光栅化的基础单位是最简单的多边形:三角形。
光栅化做的事就是如下:
遍历屏幕中所有的点,判断点是否在三角形内
如果在三角形内,通过重心坐标计算出此点的z坐标,并且对其他顶点属性进行插值
将点传给片段着色器进行着色
其主要功能就是对三角形进行采样,确定其中的点传给片段着色器。
判断点是否在三角形内
首先要做的第一步就是判断点是否在三角形内。
我们光栅化的做法是这样:假设三角形坐标为,对屏幕上的每个点,判断其是否在三角形对XoY平面投影的区域内。
假设三角形的三个顶点是
Edge Equation
Edge Equation算法使用叉积来判断:
当Q点在三角形外面时,
注意这里向量的顺序一定是按照顺时针或逆时针,不要搞什么
使用重心坐标
重心坐标主要是用来插值出点的z坐标,但是这里也可以使用它来判断三角形在不在内部。
首先看一下重心坐标的定义:
如果一个点
这里第二个式子告诉我们,其实可以只使用
当
那么接下来就是求解这三个未知数,有两种方法:
使用面积比来计算
第一种是通过重心坐标的性质:
这样
推导出公式来计算
第二种是我们自己推导:
把左边的
因为这里的所有向量都是二维向量,所以我们有:
任意的线性方程组都可以写成矩阵形式,那么我们有:
$$ \begin{cases}
= 0 \
= 0
\end{cases} $$
那么这就意味着
那就好做了,直接对上面方程组右边两个向量做叉积:
$$
\times
=
=
c
这里我们算出来的向量是
这个时候必须考虑
$$
c =
\left|
\right|
\left|
上述行列式为0说明
这里你可以抛弃三角形,或者绘制这条直线。
显然,方法二比起方法一更好,他只需要做一次叉乘就能得到结果。
使用三角形AABB包围盒加速判断
这里我们可以加速这一步骤:我们找到三角形的AABB包围盒,然后遍历屏幕上的点时先判断在不在包围盒内,不在就直接丢弃:
对三角形内的每个点求出z坐标
我们确定了三角形内的所有点,现在需要对每个点计算其z坐标。
平面方程法(推荐仅在平行投影中使用)
可以使用平面方程来解:
三角形所在平面的方程为:
而
那么就可以很容易求得此三角形所在平面的方程。然后对屏幕上的点
当
z坐标的透视校正(透视投影中使用)
平面方程法只能在平行投影中使用,因为正交投影会让三角形“变形”,导致其z坐标和其他点并不是线性关系。所以我们需要对z坐标进行透视校正。
上图解释了为何需要透视校正。在屏幕上,c点位于a,b的中间,但在透视投影的情况下真正的点C并不位于AB之间,如果这时候还用线性关系去运算就会带来错误的结果。
接下来我们来算透视校正:
我们先从侧面看整个场景,研究二维的情况,然后将其推广到三维情况。
这里我们的摄像机看向z的正方向,近平面到摄像机的z距离为d。
首先,通过相似三角形可得:
然后由s的计算公式可以得到:
同理,通过t的计算公式可以得到:
将
再将
将
化简得
然后将
化简得:
然后对
这说明z的倒数之间是成正比的,也就是说,记
这就是二维空间中的透视校正。
推广到三维空间中,我们就需要找到和
所以推广到3D的公式就是这样:
其中
重心坐标在透视投影的情况下会发生改变,那么其他的属性值也会发生改变。对于任意的属性值,我们可以用如下公式进行透视校正:
编程小技巧
这里因为
$$
\Rightarrow
所以我们可以提前保留下