目录
重心坐标
三角形内部进行插值使用重心坐标来完成。
重心坐标的计算
三角形内的任意点可以由三角形的三顶点加权平均表示,且权重和为1。这个权重就是三角形内顶点的重心坐标。
比如,A的重心坐标为(1,0,0)
重心坐标也可由面积来计算,计算下图三个三角形的面积,面积占总面积的比重就是重心坐标系数。
三角形的重心是三个顶点的算术平均,即
x
c
=
1
/
3
(
x
A
+
x
B
+
x
C
)
x_c=1/3(x_A+x_B+x_C)
xc=1/3(xA+xB+xC),重心的坐标为
(
1
/
3
,
1
/
3
,
1
/
3
)
(1/3,1/3,1/3)
(1/3,1/3,1/3)。
任意点的重心坐标可由下式计算
重心坐标插值
直接使用重心坐标进行插值。
需要注意,3D物体投影到2D屏幕后,点的重心坐标会发生变化,这样会导致一定的误差。为了避免这种误差,需要在3D上做插值。
比如,求投影后三角形内所有点的深度信息时,不能用2D空间中顶点深度信息做插值,要计算出3D空间中的三角形内每个点的重心坐标,根据3D空间中的深度信息和重心坐标进行计算,最终将深度信息填到对应的2D位置上。
Simple Texture Mapping: Diffuse Color
简单的纹理映射,在光栅化过程中,对当前扫描到的点的UV坐标进行采样,将得到的颜色直接赋值给像素。
for each rasterized screen sample (x,y):
(u,v) = evaluate texture coordinate at (x,y)
texcolor = texture.sample(u,v);
set sample’s color to texcolor;
纹理过小
当纹理分辨率过小,而物体较大,多个像素坐标都会采样到同一个纹素,会产生锯齿。可以使用最近邻插值,双线性插值,双三次插值解决这个问题,效果如下图。
Nearest Interpolation 最近邻插值
红点为像素对应的纹理像素坐标,把离红点最近的纹素分配给该像素。
Bilinear Interpolation 双线性插值
找红点周围最近的四个纹素进行插值。
插值方法:在两个方向上分别进行插值
- 对
u
01
u_{01}
u01和
u
11
u_{11}
u11进行插值得到
u
1
u_1
u1,对
u
00
u_{00}
u00和
u
10
u_{10}
u10进行插值得到
u
0
u_0
u0
- 对
u
0
u_{0}
u0和
u
1
u_{1}
u1进行插值得到最终要求的纹素
Bicubic Interpolation 双三次插值
双三次插值考虑了最近的16个采样点,具体插值方法与双线性插值相同。
纹理过大
当纹理分辨率过大时,以某种角度或者由于物体过远,对纹理使用相同的采样率进行采样得到的结果会不同。
对远处的物体采样率过高时,会产生摩尔纹。
对近处的物体采样率过低时,会产生锯齿。
一个像素所覆盖的纹理区域是不同的,所以当发生这种变化或者一个像素覆盖纹理区域过大时,不应该用同样的采样率对纹理进行采样。
使用mipmap解决这个问题。
Mipmap
将一张纹理(正方形纹理)分辨率进行改变,生成不同层次的多个纹理:
开销较小,每次将纹理分辨率缩小
1
/
4
1/4
1/4,取极限额外总开销为原图的
3
/
4
3/4
3/4。
假定mipmap定义了D层纹理,如何确定像素P对应的层级?
找到P点和相邻像素点在纹理上的映射点,计算映射点之间的距离,将距离的中点作为该像素对应的纹素范围(下图红色框内)。
对于不规则区域,可以进行一个正方形近似,正方形变长为L,层级可由
D
=
l
o
g
2
L
D=log_2L
D=log2L得出。((因为随着层数增加,纹理分辨率是以4倍的速度减小,所以L以2倍的速度增加的))
得到该像素点的层级后,在这一层上进行纹理映射即可。在同一场景中,不同像素可能在不同的层级中,各个层级是离散的,这样会使得最终纹理结果是割裂的,如下图:
因此,每次得到该像素的层级D后,先在D上进行纹理插值,再在D+1层进行纹理插值,最终将两层结果进行插值。
这样可得到平滑的结果:
但mimap也有问题,mipmap范围限定在正方形范围内,会产生模糊的问题,如下图远处的结果:
这是因为mipmap是正方形的,在查询一些矩阵区域时会有问题。
各向异性
各向异性滤波能解决这个问题,因为它的范围不限定在正方形内,而是矩形范围。沿对角线方向将图片进行缩小,水平和竖直压缩的比例会不同。