重心坐标插值(Barycentric interpolation)
重心坐标 Barycentric Coordinates
三角形所在平面任一点坐标可以用三个顶点的坐标的线性组合表示,且三个系数相加为1。
如果三个系数均为非负数则点在三角形内,否则在三角形外
三个系数可以用点和三个顶点连成的线围成的三角形面积表示
而三角形重心则理所当然的可以表示为
(
x
,
y
)
=
1
3
α
+
1
3
β
+
1
3
γ
(x, y)=\frac{1}{3}\alpha+\frac{1}{3}\beta+\frac{1}{3}\gamma
(x,y)=31α+31β+31γ
而任一点的重心坐标可以由点坐标(x, y)得到
其实上面也是在用面积求出三个系数。
分母为三角形两边向量的叉积的模,即为三角形面积两倍。
分子为点和对面组成的三角形的两个向量的叉积的模,也是组成的三角形的面积的两倍。
所以比值即为对应的系数值。
而任一点的在三角形中的属性插值(深度、颜色、法向量)都可以用重心坐标进行插值。
但这个插值在屏幕空间中进行时,需要进行纠正,否则结果不正确。(因为透视投影是非线性投影,投影前后对x,y,z,w的线性插值结果不一样)
透视纠正公式:
I
t
Z
t
=
α
I
a
Z
a
+
β
I
b
Z
b
+
γ
I
c
Z
c
\frac{I_t}{Z_t}=\alpha \frac{I_a}{Z_a}+\beta \frac{I_b}{Z_b}+\gamma \frac{I_c}{Z_c}
ZtIt=αZaIa+βZbIb+γZcIc
其
中
I
为
插
值
的
属
性
值
,
α
,
β
,
γ
为
屏
幕
空
间
重
心
坐
标
,
a
,
b
,
c
为
三
角
形
三
个
顶
点
其中 I为插值的属性值,\alpha, \beta, \gamma为屏幕空间重心坐标,a,b,c为三角形三个顶点
其中I为插值的属性值,α,β,γ为屏幕空间重心坐标,a,b,c为三角形三个顶点
1
Z
t
=
α
1
Z
a
+
β
1
Z
b
+
γ
1
Z
c
\frac{1}{Z_t}=\alpha \frac{1}{Z_a}+\beta \frac{1}{Z_b}+\gamma \frac{1}{Z_c}
Zt1=αZa1+βZb1+γZc1
Simple Texture Mapping
对屏幕上每个光栅化的采样点(屏幕像素中心),计算出uv坐标(用重心坐标插值),再在纹理中用uv坐标采样出颜色
Texture Magnification (纹理放大,即纹理过小)
当纹理太小的时候,uv坐标对应的位置很有可能不是纹理的像素点,而使用临近点采样会导致锯齿感明显, 因此会用到双线性插值(Bilinear),即横坐标进行一次插值,计算出u1,u0的采样值,再用纵坐标进行一次插值,计算出采样点的值。
如果纹理过大,而投影的面片过小
由于远处的一个像素点覆盖的uv范围很大,因此导致采样失真。解决的办法是求出覆盖uv面积的平均值作为采样值,经典方法则是mipmap
Mipmap
提前对纹理计算各层级的mipmap(即每次在宽高减半),然后在采样的时候根据像素覆盖的uv面积大小,在对应的层级的mipmap中进行采样,即完成了对采样区域求平均。
Mipmap生成的所有图加起来内存只会增加为原来的4/3(等比数列求和)
计算一个像素对应的采样Mipmap层级
计算像素点和周围像素点的uv坐标,近似求出映射点之间的距离L(取边长为映射uv点的距离的最大值(向右向上取))。当距离值和mipmap的像素之间的距离相等时,则是完全的一一映射,即像素点和临近的像素点正好对应纹理中的两个像素点。
因为mimmap的每一层是长宽折半生成的,因此这一级的2x2区域,会在下一级变成1x1的一个像素点,而这个像素点正是想要获得的区域平均值。同理可知当长度L经过几次折半才会变为1时,对应的层级D即为采样层级。因此
D
=
l
o
g
2
L
D=log_2L
D=log2L
当然不可能每次计算L都正好为2的幂次,当D不为整数时,则需要进行Trilinear Interpolation(三次线性插值)
三次线性插值
先在邻近的两个层级间进行双线性插值获取采样值,再进行一次层之间的线性插值得到最终采样值。
Mipmap的局限
在远处模糊很严重,原因是考察远处部分点覆盖的纹理范围,其形状并不是一个标准的正方形,如果还用正方形近似,计算正方形区域的平均值,明显是不对的。此时有个优化方案,各向异性过滤(Anisotropic Filtering)
通过计算长折半和宽折半的情况,得到点覆盖区域为长方形的平均值。