Mipmap
空间换时间的优化解法
一句话总结就是,对一张纹理图片进行多层压缩,然后对于MVP变换之后屏幕中显示的像素,GPU会根据一个物体在屏幕中的像素大小调用计算公式,得出运用哪一层级的图
1. 为什么我们需要 Mipmap?(痛点与灾难)
想象一下,我们在 UE5 里铺了一块非常精细的 的高光泽大理石地板(包含 100 万个纹素)。
- 当你站得很远时:这块巨大的地板在屏幕上可能只占据了 (100 个)像素。
- 灾难发生:如果让这 100 个屏幕像素去那 100 万个纹素里“抽卡”采样,它们抽到的颜色会非常稀疏、极其随机。只要相机稍微移动一点点,像素采样的位置就会发生剧烈变化,导致远处的地板疯狂闪烁,甚至出现一圈圈恶心的摩尔纹 (Moiré pattern)!这就是图形学中臭名昭著的走样 (Aliasing)。
2. Mipmap 的核心思想:空间换时间(提前计算)
既然当场“抽卡”会闪烁,那我们不如提前算好远处的像素该长什么样!
当我们把一张贴图导入 UE5 时,引擎会在后台默默地帮你生成一连串越来越小的贴图:
- Level 0: (原图,适合极近距离)
- Level 1: (长宽各缩小一半,相当于四个像素平均成一个)
- Level 2:
- …
- Level 10: (整张图混合成了一个纯色像素,适合无限远)
逻辑链:当相机渲染某个像素时,GPU 会计算这个像素覆盖了贴图上多大的区域。如果覆盖区域很大(说明离得很远),GPU 就不去原图里找了,而是直接去 Level 3 或者 Level 4 那种已经“平均模糊”好的小贴图里去取颜色。这样不仅彻底消灭了闪烁,还能因为小贴图更容易被塞进 GPU 高速缓存里,大幅提高渲染效率!
3. 三线性插值 (Trilinear Interpolation)
如果地面上 Level 1 和 Level 2 的交界处是生硬切换的,画面上就会出现一条明显的“分界线”。
为了解决这个问题,聪明的现代渲染管线不仅会在同一层 Mipmap 里做双线性插值 (Bilinear),还会**把相邻的两层 Mipmap(比如层级 **和层级 )都采样出来,然后根据深度的距离,在层与层之间再做一次线性插值 (Lerp)。
这(双线性 层间线性)合在一起,就是大名鼎鼎的三线性插值 (Trilinear Interpolation) 啦!
4. 经典的代价:多占了多少内存?
天下没有免费的午餐。既然多生成了这么多缩略图,必然会占用更多的显存。那是多少呢?
是一个等比数列求和:
结论:Mipmap 会让贴图多占用原本大小的 内存。但这 的代价换来了极大的抗锯齿效果和性能提升,是绝对稳赚不赔的买卖!
Mipmap的调用时机
GPU 在渲染屏幕上的某一个像素时,它怎么知道这个像素现在该用 Level 0,还是 Level 3?
如何计算 Mipmap 层数?
1. 核心思路:测量“一个屏幕像素,盖住了多少个纹素”
如果 1 个屏幕像素,正好对应贴图上的 1 个纹素,说明不放大也不缩小,用 Level 0 原图。
如果 1 个屏幕像素,因为离得很远,盖住了贴图上的 (共 16 个)纹素,那我们就应该去找那个把 16 个纹素压成 1 个的图,也就是 Level 2(因为 )。
所以,我们的目标是算出屏幕像素在贴图上的“脚印大小” (Footprint),也就是公式里的 。
2. 第一步:找邻居 (微分思想)
看 PPT 左边的图。GPU 在光栅化时,像素从来都不是孤立计算的!它们是以 ** 的像素块 (Quad)** 为单位并行的。
为了知道当前像素 的脚印有多大,GPU 会偷偷看一眼它右边的邻居 和上边的邻居 。
3. 第二步:映射到 UV 空间求距离
看 PPT 右边的图。我们把这三个像素的 UV 坐标找出来,画在贴图空间里。
- 屏幕上往右走 1 个像素,UV 变化了多少?用向量表示就是 。算一下这个向量的长度。
- 屏幕上往上走 1 个像素,UV 变化了多少?用向量表示就是 。算一下这个向量的长度。
4. 第三步:取最大值求 ,对数求
因为受透视影响,像素映射到 UV 空间通常是个扭曲的四边形。为了保守起见,我们取上面两个长度里的最大值作为正方形的边长 :
算出了 (比如 ,意味着这个像素跨越了 4 个纹素的宽度),那该用第几层 Mipmap 呢?
直接求以 2 为底的对数就好啦!
(如果 ,那么 ,所以去查 Level 2 的 Mipmap)
Mipmap小数情况处理
1. 致命的痛点:如果算出来的 是小数怎么办?
还记得上一步我们用 算出了 Mipmap 的层数 吗?
真实的 3D 世界是连续的,所以算出来的 绝大多数情况都是小数!比如 。
- 如果我们像最近邻插值那样,直接四舍五入去第 2 层(Level 2)拿颜色。
- 那当相机稍微往前走一步,哪怕只移动了一毫米, 变成了 ,系统就会瞬间切回第 1 层(Level 1)。
- 灾难后果:因为不同层级的贴图模糊程度不一样,这种“非黑即白”的硬切,会导致游戏画面里的地面上出现一条极其明显的分辨率断层线 (Seam),也就是玩家常说的“贴图加载线”,非常刺眼!
2. 完美的救赎:三步走逻辑链 (Trilinear)
为了彻底抹平这条断层线,现代 GPU 决定同时压榨相邻的两层贴图!这就是 PPT 里的核心逻辑:
- 第一步:向下去找 层 (Level 1)
既然 ,那它的下界就是第 1 层。GPU 会在 Level 1 的贴图里,找到对应的 4 个纹素,做一次双线性插值 (Bilinear),得到一个颜色,我们叫它 。
- 第二步:向上去找 层 (Level 2)
它的上界是第 2 层。GPU 会在 Level 2 的贴图里(注意,Level 2 的网格比 Level 1 稀疏了一倍),再次找到对应的 4 个纹素,做第二次双线性插值 (Bilinear),得到另一个颜色,叫它 。
- 第三步:层与层之间的羁绊 (Lerp)
拿出 的小数部分,也就是 。我们在刚刚算出的两个颜色之间,再做最后一次线性插值 (Linear Interpolation)!
3. 为什么叫“三”线性?性能开销如何?
- 为什么叫三线性 (Tri-linear):因为它在 (水平)、(垂直)两个空间维度上做了插值,又在 (深度/层级)这个第三维度上做了插值。合起来就是 3D 插值!
- 可怕的性能开销:算算看,为了求这一个屏幕像素的最终颜色,GPU 读了多少次贴图?Level 1 读了 4 个纹素,Level 2 读了 4 个纹素,一共读取了 8 个纹素!并且做了一堆乘法和加法。所以,三线性插值的画质是顶级的,但开销也是双线性的两倍哦!
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时






