2700 字
14 分钟
【CG】Games101-09学习笔记 & 作业解析

Barycentric Coordinates#

重心坐标 Barycentric Coordinates,重心坐标我们已经在作业2中介绍过了。
重心坐标有什用呢?在图形学中我们可以通过重心坐标使用三角形的三个顶点进行插值得到三角形内部点的属性。
在三角形的顶点上我们可以定义许多属性,例如:

  • 法线
  • 颜色
  • 纹理坐标
  • 深度
  • 等等
    例如我们想要内部点的法线,那么我们就可以通过重心坐标插值获得内部点的法线
    而具体定义如下
    在三角形 ABCABC 所在的平面内,任何一个点 PP 都可以表示为三个顶点坐标的线性组合:
P=αA+βB+γCP = \alpha A + \beta B + \gamma C

其中 α+β+γ=1\alpha + \beta + \gamma = 1。这三个系数 (α,β,γ)(\alpha, \beta, \gamma) 就是点 PP 的重心坐标。 而对于三角形内部的任何一个点PP,它与三角形三个顶点之间进行连线可以组成三个三角形,而重心坐标 (α,β,γ)(\alpha, \beta, \gamma) 与面积的关系如下:

α=Area(P,B,C)Area(A,B,C)\alpha = \frac{\text{Area}(P, B, C)}{\text{Area}(A, B, C)}β=Area(P,A,C)Area(A,B,C)\beta = \frac{\text{Area}(P, A, C)}{\text{Area}(A, B, C)}γ=Area(P,A,B)Area(A,B,C)\gamma = \frac{\text{Area}(P, A, B)}{\text{Area}(A, B, C)}

对于一个三角形的面积我们可以使用这个三角形的两个边组成的向量进行叉乘然后求模再除以2获得。
有了重心坐标我们就可以通过插值的方式获取三角形内部的属性了。例如:
法线插值 n=αv0.n+βv1.n+γv2.nn = \alpha v_0.n + \beta v_1.n+ \gamma v_2.n 而对于深度值我们需要使用:

IwP=αI0w0+βI1w1+γI2w2\frac{I}{w_P} = \alpha \frac{I_0}{w_0} + \beta \frac{I_1}{w_1} + \gamma \frac{I_2}{w_2}

你可能会问为什么不是 z=αv0.z+βv1.z+γv2.zz = \alpha v_0.z + \beta v_1.z + \gamma v_2.z
这是因为透视投影是非线性的,在 3D 空间中是线性的属性,经过透视投影变换到 2D 屏幕空间后,就不再是线性的了,如果你直接在屏幕空间用重心坐标插值,会导致纹理扭曲或深度错误,为了修正这个问题,我们需要利用齐次坐标中的 ww 分量进行透视矫正插值。在屏幕空间插值任何属性 II。 并且有时候我们需要将插值后获得的深度逆变换到三维空间中使用。
所以在使用顶点的纹理坐标进行插值后我们可以获得内部点的纹理坐标,然后我们使用这个纹理坐标在纹理上查询一下这个纹理的颜色值,最后应用到漫反射的kdk_d系数上,最后配合高光项和环境光就能渲染出一个带有纹理的物体了。
但实际上我们不能这么简单的做,这么做回带来什么问题呢?

Texture Magnification#

双线性插值#

当我们有一个很大的物体,但是纹理图非常小,那么这个物体的纹理就会失真。 这是因为我们的物体上的三角形插值得到的纹理坐标是小数的,为纹理上的每个像素的索引都是整数,所以我们会对插值的到的纹理坐标进行round,就会导致物体上不同的像素使用同一个纹理像素, 所以我们可以通过一种方式对纹理进行模糊操作让其有更高的精度,而这种方式就是双线性插值。

上述图介绍了三种过滤(模糊)方式,分别是

  • Nearest :最近邻过滤,使用纹理坐标最近的纹理像素
  • Bilinear :双线性过滤,使用理坐标最近的 2×2 区域,进行加权平均
  • Bicubic :双三维过滤,使用纹理坐标周围 4×4 的像素矩阵

Bilinear Interpolation#

在介绍双线性插值之前,我们先介绍一下线性插值

Linear Interpolation#

线性插值就是通过两个点和一个参数来获取两个点之间的点的操作,公式如下

lerp(a,b,t)=a+t(b−a)lerp(a, b, t) = a + t(b - a)

例如,例如我们要获取点aa和点bb之间的中点,那么这个点可以表示为:

mid=lerp(a,b,0.5)=a+0.5(b−a)=b+a2mid = lerp(a, b, 0.5) = a + 0.5(b - a) = \frac{b+a}{2}

当然不仅仅可以插值点,还可以插值颜色

Bilinear Interpolation#

而双线性插值就是三次线性插值,如图我们可以分别对u00u_00和u10u_10,u01u_01和u11u_11,使用参数ss,进行一次线性插值得到u0u_0和u1u_1,我们再使用得到的这两个点使用参数tt进行线性插值,最后的到我们要的像素颜色

Mipmap#

上面是纹理比模型小的问题,下面我们来看看纹理比模型大的问题 当我们直接使用插值得到的纹理坐标进行纹理映射,那么我们会得到上面这幅图的情形,摩尔纹和锯齿,也就是走样问题。
我们来分析一下这个问题,在近处一个像素覆盖到纹理上的区域相对较小,而远处一个像素覆盖到一个纹理的区域相对较大,如果一个近处的像素我们使用他的像素的中心查询纹理的值,由于这个像素覆盖的纹理的大小和像素差不多大,那么我们得到的就是我们想要的值。可是如果一个远处的像素,我们他在纹理上覆盖了很大的位置,而我们只使用这个区域的中心的纹理像素颜色作为查询结果,这就会导致这些问题。我们可以使用SSAA来解决这个问题,但是太费时间了! 这是一个走样的问题,走样的问题是由于信号变化太快而我们采样的速度跟不上而导致的, 而在这里就是远处的一个像素覆盖了很大的一部分纹理区域,而纹理区域很大代表着信号频率变化快,意味着我们不能使用一个采样点进行采样,也就是一个远处的像素内部有非常高频的信号,我们需要一个更高频率的采样方法。但是我们还有另一种思路,既然我们的采样点跟不上信号变化的频率,那我们让信号跟上采样的频率不就行了,也就是修改纹理,让一个采样点能获取其覆盖区域的平均值就行了,也就是我们需要一个方法,给你一个点能获取其区域平均值,这个方法叫做范围查询。
而在图形学中我们经常使用一个叫做Mipmap的范围查询方法,它很快,但是是近似的,且只能是方形的范围查询,Mipmap就是使用一张图生成一系列图,第 ii level 的图片是第 i−1i-1 level 的图片的一半。 而我们生成了这么多新的图片,我们引入了多少额外的存储量呢?也就是相对于原始图片,我们需要多少额外的存储量呢?很简单这是一个等比级数求和的问题,公比是q=14q = \frac{1}{4},根据等比数列求和公式 S=a1−qS = \frac{a}{1-q},其中 aa 是初始值,也就是初始图片的大小我们假设为N×NN\times N,那么所有图片占用的空间就是

S=N21−14=43N2S = \frac{N^2}{1-\frac{1}{4}} = \frac{4}{3}N^2

那么额外的存储量S′S^\prime就是

S′=43N2−N2=13N2S^\prime = \frac{4}{3}N^2 - N^2 = \frac{1}{3}N^2

也就是多出了13\frac{1}{3}的存储空间,可以看到非常的省空间,无论原始图片多大,Mipmap生成的图片都只多出原来的13\frac{1}{3}

对于这些图片,我们可以在使用之前提前计算好,Mipmap有多层,要用哪一层就使用索引就行了

那么我们怎么得到一个像素在纹理上覆盖多大的区域呢? 如上图,我们选择一个像素以及这个周围的邻居,然后我们将这些点映射到纹理空间中去,然后我们通过图片上计算L的公式可以获得在纹理空间中,我们选择的一个点距离其他的领域的最大距离,我们使用这个最大距离以选择的这个点的中心做一个正方形,我们使用这个正方形代表我们这个像素在纹理上覆盖的区域,而在这里计算区域的面积不是关键,关键是我们怎么通过这个正方形,通过我们计算好的Mipmap查询纹理像素大小对应的值,例如如果我们这里得到的正方形是1x1的,那么我们就可以直接去原始图形中查询,如果正方形是4x4的并且在Mipmap的第2层上这个对应的4x4区域会变成1x1,刚好能对应回我们的屏幕空间。所以我们可以通过图片中的这个公式

D=log⁡2LD = \log_{2}L

来获得这个正方形的Mipmap层数,然后使用这一层的图片进行采样。 而下面这张图使用颜色可视化了不同的像素需要使用的 Mipmap Level等级 可以看到不同的颜色之间是直接突变的,这是由于我们的Mipmap的层级是整数的,没有1.8层,所以我们为了解决这个问题可以用插值。
假如说我们要查询DD和D+1D+1之间的值,那么我们可以同时查询DD和D+1D+1,使用双线性插值得到结果,再将两个结果再进行一次线性插值,不用做范围查询了!这个方法叫做三线性插值 下面是三线性插值的实际应用

Anisotropic Filtering#

但是我们现在了解的mipmap做出的效果是下面的样子,可以看到远处被过度模糊了,这是由于我们的mipmap是使用正方形进行以及三线性插值导致的 而为了避免这种情况,我们引入了一个新的方法 anisotropic filtering 各向异性过滤 Mipmap是同时对图片的长和宽进行缩小,但是各项异性过滤是分别对长和宽进行缩小,存储大小是原来的3倍 这种方式就能解决我们实际上的问题,实际上我们的像素在纹理空间上覆盖的往往是长方形而不是正方形 但是各向异性过滤还是没能解决问题,他只能使用”横平竖直”的矩形区域,但是对于斜着的区域还是没有方法 解决这个问题的有一种方法叫做 EWA Filtering

Games101

已完结

第 9 篇,共 14 篇本文属于系列

【CG】Games101-09学习笔记 & 作业解析
https://blog.cglab.top/posts/games_series/games101_09/
作者
Artichoke
发布于
2026-04-01
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取

最后更新于 ,距今已过 206 天

部分内容可能已过时