/ Ch10 信号处理

第10章:信号处理 — 零基础讲义

讲义说明
本讲义基于 Steve Marschner & Peter Shirley 所著《虎书5》第5版第10章(p.205-252)。
本章是图形学的"数学骨架"——它解释为什么"采样率太低"会让远处物体消失、为什么"纹理过滤"能消除锯齿、为什么"mipmap"是 GPU 的标配。
学完本章你将理解抗锯齿、纹理过滤、傅里叶变换等核心概念。
本版插画采用 Guizang 材质插画风格重新绘制。

学习目标

  1. 理解采样和混叠——连续信号变成离散信号的核心问题
  2. 掌握卷积——图形学最核心的数学运算
  3. 理解常用卷积滤波器:box、tent、Gaussian、B-spline
  4. 掌握可分离滤波器——2D 卷积的高效实现
  5. 理解采样理论:Nyquist 定理、抗混叠、重采样
  6. 理解傅里叶变换——频域的"魔法"
  7. 掌握 mipmap 和各向异性过滤的原理


10.1 数字音频:1D 采样入门

10.1.1 采样流程

为什么先讲音频? 音频信号是 1D 的(时间→振幅),比 2D 图像简单得多。所有图像处理的核心概念(采样、混叠、滤波)都可以先在 1D 音频中理解,再推广到 2D。

连续→离散采样
图10-1:连续正弦波信号被离散采样——采样脉冲在特定时间点"捕捉"信号值

数字音频流程

麦克风 → 连续电压信号 → A/D 转换器(采样)→ 离散数字存储 → D/A 转换器(重建)→ 扬声器

A/D 转换器(Analog-to-Digital):把连续电压变成离散数字。采样率(每秒采样次数)决定"能录多高的频率"。

D/A 转换器(Digital-to-Analog):把离散数字变回连续电压。输出是"阶梯形"——需要低通滤波器平滑。

组件输入输出关键问题
麦克风声波(空气振动)连续电压频率响应范围
A/D 转换器连续电压离散数字(每秒 f_s 个样本)采样率 f_s 是多少?
D/A 转换器离散数字连续电压(阶梯形)需要平滑滤波

采样率多少才够? 人耳能听到的最高频率约 20 KHz。根据奈奎斯特定理,采样率必须 > 2 × 最高频率 = 40 KHz。CD 标准的 44.1 KHz 就是基于这个——留了一些余量。

核心洞察:采样前用低通滤波器去掉高于奈奎斯特频率的成分(防混叠);采样后用低通滤波器平滑阶梯形输出(重建)。两个滤波器缺一不可。

10.1.2 混叠(Aliasing)

混叠现象
图10-2:混叠——高频信号被采样后"伪装"成低频信号

混叠 = "高频信号假装成低频信号"

经典例子

  • 钟表以 8 KHz 录音后听起来是 6 KHz 的"钟"——因为 8 KHz 以上的频率被"折叠"到低频
  • 电影中车轮"倒转"效应——车轮旋转频率超过帧率时,看起来像在反转
  • 摩尔纹(Moiré pattern)——细密的网格图案在屏幕上出现奇怪的波纹

混叠的根本原因

原始信号频率 f,采样率 f_s
如果 f > f_s / 2(奈奎斯特频率),高频部分会被"折叠"到 [0, f_s/2] 范围内

// 数值例子
f_s = 100 Hz(每秒采 100 个样本)
奈奎斯特频率 = 50 Hz

// 情况 1:f = 30 Hz(低于奈奎斯特频率)→ 正确采样
30 Hz 的正弦波被正确记录

// 情况 2:f = 80 Hz(高于奈奎斯特频率)→ 发生混叠
80 Hz 的正弦波被采样后"伪装"成 20 Hz
因为:采样得到的离散点恰好和 20 Hz 的波一样!
80 Hz - 100 Hz = -20 Hz → 绝对值 = 20 Hz

数学解释

频率 f 的信号经采样率 f_s 采样后,所有 f ± k·f_s 的频率都不可区分(k 为整数)
🤔 想一想:为什么音乐 CD 用 44.1 KHz 采样率?为什么不是 40 KHz 或 48 KHz?
人耳最高听到约 20 KHz。44.1 > 2×20 = 40,技术上已足够。44.1 这个数字的由来很"历史"——Sony 和 Philips 在制定 CD 标准时,选择了一个既能兼容 PAL/NTSC 视频信号又留有余量的数值。实际上 48 KHz(专业音频标准)也常用。

10.2 卷积(Convolution)

10.2.1 卷积的定义

为什么卷积是图形学最重要的运算? 任何形式的滤波(模糊、锐化、边缘检测)、采样重建本质上都是卷积。理解卷积 = 理解信号处理的一半。

生活类比:煮汤

做一锅汤,你不断加调料。每次加调料的影响会"扩散"到之后的汤里——加得越久,扩散得越广。最终的汤味 = 每次加料量 × 该料随时间扩散的函数 的累加。这就是卷积!

离散卷积公式

(a * b)[i] = Σⱼ a[j] · b[i - j]

连续卷积公式

(f * g)(x) = ∫ f(t) · g(x - t) dt

公式拆解(离散版)

符号含义类比
a输入信号(要处理的数组)食材清单
b滤波器(卷积核)调料"扩散"函数
i输出位置尝汤的时间点
j遍历所有位置回顾所有加料时间
b[i-j]位置 j 的输入对位置 i 的贡献权重j 时刻加的料在 i 时刻还剩多少

10.2.2 移动平均 = 卷积的最简形式

如果看不懂公式,先看这个

移动平均:对附近 N 个值求平均,这就是卷积:

c[i] = (1 / (2r + 1)) × Σ_{j=i-r}^{i+r} a[j]

这就是 box 滤波器的卷积形式——每个输出点是对称窗口内输入点的等权平均。

数值例子

输入信号 a = [1, 4, 2, 6, 3, 5]
滤波器 b = [1/3, 1/3, 1/3](半径 r=1 的 box 滤波器)

c[1] = a[0]×b[1] + a[1]×b[0] + a[2]×b[-1]
  // 等等,索引有点绕。用 i=1 代入公式 (a*b)[i]=Σⱼa[j]·b[i-j]
c[1] = a[0]×b[1] + a[1]×b[0] + a[2]×b[-1]
  // b 的索引从 0 开始,所以 b[-1] 不存在
  // 简化方式:输出 c[1] = a[0]×1/3 + a[1]×1/3 + a[2]×1/3
      = 1/3 + 4/3 + 2/3 = 7/3 ≈ 2.33

c[2] = a[1]×1/3 + a[2]×1/3 + a[3]×1/3
      = 4/3 + 2/3 + 6/3 = 12/3 = 4.0

c[3] = a[2]×1/3 + a[3]×1/3 + a[4]×1/3
      = 2/3 + 6/3 + 3/3 = 11/3 ≈ 3.67

// 输出:c = [?, 2.33, 4.0, 3.67, ?, ?]
// 边缘处的 ? 需要"边界处理"(见 10.6.3)

10.2.3 卷积 = "滤波器翻转 + 滑动加权"

视角 1(从输出看):c[i] = "用滤波器 b 对 a 在 i 处求加权平均"

  • 在每个输出位置 i 处"放置"滤波器
  • 滤波器覆盖的输入值乘上对应的滤波器权重
  • 求和得到输出

视角 2(从输入看):(a * b) = "把 b 复制多份,按 a 的值加权后叠加"

  • 每个输入值 a[j] 在输出中"扩散"成滤波器的形状
  • 所有扩散结果叠加
  • GPU 实际用的是这个视角(多个采样求和)
重要洞察:两种视角数学上完全等价,但实现效率不同。视角 1 适合均匀采样(图像处理中的卷积),视角 2 适合非均匀采样(光线追踪中的重建)。理解这两种视角 = 理解一半的信号处理。
卷积运算
图10-3:滑动窗口卷积——滤波器沿着信号移动,在每个位置计算加权求和

10.2.4 卷积的关键性质

性质公式物理意义为什么重要
交换律a * b = b * a滤波器和信号可互换可以选择更容易实现的一方
结合律(a * b) * c = a * (b * c)可分步滤波多个滤波器可以合并为一个
分配律(a + b) * c = a*c + b*c线性性质可以分开处理再合并
恒等元a * δ = aδ = 单位脉冲(一个 1 其余 0)卷积的"零"
// 为什么交换律很重要?
// 如果你有两个滤波器,一个简单一个复杂
// 可以先卷简单的,再卷复杂的 = 先卷复杂的,再卷简单的
// 选择计算量小的顺序!

// 为什么结合律很重要?
// 高斯模糊 = box * box * box * box (4次box近似高斯)
// 结合律允许先合并为一个大滤波器:gaussian_approx = box * box * box * box
// 然后一次卷积搞定:result = image * gaussian_approx

10.2.4b 卷积的数值计算示例(完整手算)

为了彻底理解卷积,让我们手算一个完整例子:

// 输入信号 a = [0, 1, 0, 1, 0, 1, 0, 1](交替 0/1 信号)
// 滤波器 b = [0.25, 0.5, 0.25](三角形权重,r=1)
// 输出 c = a * b

// 手算每个输出位置(假设零填充边界):

c[0] = a[-1]×0 + a[0]×0.5 + a[1]×0.25
     = 0 + 1×0.5 + 0×0.25 = 0.5

c[1] = a[0]×0.25 + a[1]×0.5 + a[2]×0.25
     = 0×0.25 + 1×0.5 + 0×0.25 = 0.5

c[2] = a[1]×0.25 + a[2]×0.5 + a[3]×0.25
     = 1×0.25 + 0×0.5 + 1×0.25 = 0.5

c[3] = a[2]×0.25 + a[3]×0.5 + a[4]×0.25
     = 0×0.25 + 1×0.5 + 0×0.25 = 0.5

// ... 实际上全部输出都是 0.5!
// 因为"交替 0/1"的高频信号被滤波器完全"抹平"了
// 这证明了:滤波 = 低频通过(低通滤波)

// 如果改用更宽的滤波器 b = [0.2, 0.2, 0.2, 0.2, 0.2](r=2):
c[2] = 1×0.2 + 0×0.2 + 1×0.2 + 0×0.2 + 1×0.2 = 0.6
// 稍微高了一点的 0.6 — 还是被抹平了,因为滤波器比信号周期宽

// 结论:滤波器越宽,抹平效果越强(频率越低)

10.2.5 离散-连续卷积(混合域)

图形学中最常用的卷积形式——一边是离散采样,一边是连续函数:

(a * f)(x) = Σ_i a[i] · f(x - i)

这就是图形学中重采样(resampling)的核心公式

  • a[i]:离散的像素值/纹理值
  • f(x):连续的滤波器函数
  • (a * f)(x):重建出的连续信号在 x 处的值

生活类比:你在听 CD(离散样本),但耳朵需要连续的声音(连续信号)。播放器的 D/A 转换器就是用"卷积"把离散样本变回连续波形。


10.3 卷积滤波器

10.3.1 滤波器的本质

滤波器 = 一个"小函数",它的形状决定了"什么频率的信号被保留/抑制"。

关键权衡

滤波器越平滑 → 越能消除高频混叠 → 但输出越模糊
滤波器越锐利 → 细节保留越好 → 但越容易产生混叠和振铃

10.3.2 常用滤波器对比

滤波器形状表达式特点自然半径主要用途
Box□ 方波1 if |x|<0.5 else 0最简单,但有振铃1/2最快的滤波,预览
Tent△ 三角形1-|x| if |x|<1 else 0比 box 平滑1中等质量,双线性插值
Gaussian∩ 钟形exp(-x²/(2σ²))最平滑,无振铃无固定(σ 控制)高质量模糊
B-spline⌒ 立方多项式分段三次多项式比 Gaussian 还平滑2高质量重采样
卷积滤波器示意图
图10-4:不同滤波器的形状——从方波(box)到钟形(Gaussian),越平滑的滤波器对高频的抑制越好

数值例子:不同滤波器对同一信号的卷积效果

输入信号 a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
位置 i=5 处的输出:

// Box 滤波器(半径 r=1):等权平均
c_box[5] = (a[4] + a[5] + a[6]) / 3 = (4 + 5 + 6) / 3 = 5.0

// Tent 滤波器(半径 r=1):线性衰减权重
c_tent[5] = a[4]×0.5 + a[5]×1.0 + a[6]×0.5
          = 2.0 + 5.0 + 3.0 = 10.0 → 归一化:10 / 2 = 5.0
// 注意:Tent 的权重和是 2(0.5+1.0+0.5),需要归一化

// Gaussian 滤波器(σ=1,半径 r=2)
权重: w[3]=exp(-4/2)=0.135, w[4]=exp(-1/2)=0.607, w[5]=exp(0)=1.0
      w[6]=0.607, w[7]=0.135
c_gauss[5] = (3×0.135 + 4×0.607 + 5×1.0 + 6×0.607 + 7×0.135)
           / (0.135 + 0.607 + 1.0 + 0.607 + 0.135)
          = (0.405 + 2.428 + 5.0 + 3.642 + 0.945) / 2.484
          = 12.42 / 2.484 ≈ 5.0
// 对于线性信号,所有滤波器输出相同(因为信号本身是线性的)
// 对于非线性的真实图像,不同滤波器的效果差异会非常明显

10.3.3 关键概念

1. 积分 = 1 的归一化

∫ f(x) dx = 1 或 Σ b[j] = 1

如果滤波器积分不是 1,它会改变信号的整体亮度(图像变亮或变暗)。

2. 连续滤波器 vs 离散滤波器

类型优点缺点
离散滤波器有限个值,精确控制,快速精度受分辨率限制
连续滤波器任意形状,无限精度计算需要积分/采样

3. 插值滤波器f(0) = 1, f(i) = 0(对所有非零整数 i)。重建后的函数精确通过样本点

4. 纹波自由(ripple-free):滤波器在所有整数偏移处累加 = 1。对常数信号无影响。

🤔 想一想:为什么 box 滤波器有"振铃"?
Box 滤波器在频域是 sinc 函数(sin(πω)/πω)。sinc 有"副瓣"(side lobes)——在截止频率之外还有振荡。这些副瓣会让某些频率成分被错误地保留或抑制,在图像上表现为"振铃"(ringing artifact)。越平滑的滤波器(如 Gaussian)副瓣越小。

10.3.4 2D 滤波器与可分离性

问题:图像是 2D 的,2D 卷积复杂度是 O(r² × N²),太大!

解决:如果滤波器是可分离的,就能分解成两次 1D 卷积:

b₂(i, j) = b₁(i) × b₁(j)
(a * b₂)[i, j] = Σᵢ' Σⱼ' a[i', j'] × b₁(i-i') × b₁(j-j')

先卷积行,再卷积列

// 不可分离的 2D 卷积:O(r² × N²)
for each pixel (i, j):
    for each offset (di, dj) in [-r, r]²:
        sum += a[i+di][j+dj] * b_2d[di][dj]

// 可分离的 2D 卷积:O(r × N²) —— 快多了!
// 先对每行做 1D 卷积
for each row j:
    temp[i][j] = Σ a[i+di][j] * b_1d[di]
// 再对每列做 1D 卷积
for each column i:
    result[i][j] = Σ temp[i][j+dj] * b_1d[dj]

// 性能对比:半径 r=10
// 不可分离:每个像素需要 (2×10+1)² = 441 次乘加
// 可分离:每个像素只需要 2×(2×10+1) = 42 次乘加
// 加速比:441/42 ≈ 10.5 倍!

只有 Gaussian 同时是"可分离"和"径向对称"的

G₂(x, y) = (1/2π)·exp(-(x²+y²)/2) = G₁(x) · G₁(y)

这让 Gaussian 在 2D 图像处理中最高效——一次处理行,一次处理列,效果完全等价于 2D 高斯模糊。

10.3.5 滤波器的实际选择指南

在实际图形学应用中,如何选择合适的滤波器?以下是实用建议:

场景推荐滤波器理由
纹理采样(最近邻)Box速度最快,像素风格效果
纹理采样(双线性)Tent速度与质量平衡,硬件直接支持
高质量模糊Gaussian最平滑,无振铃
图像放大(上采样)B-spline / Mitchell比双线性更平滑,不会产生方块感
图像缩小(下采样)Gaussian + 降采样预模糊后再采样,抗混叠效果好
抗锯齿(采样前)Gaussian频域衰减快,混叠抑制好
光线追踪重建Gaussian / Mitchell平衡锐度和平滑
重要洞察:没有"万能"滤波器。每种滤波器在不同维度上有不同的权衡:
  • 速度 vs 质量:Box → Tent → B-spline → Gaussian(越来越慢,但质量越来越高)
  • 锐度 vs 平滑:Gaussian → B-spline → Tent → Box(Box 最锐但也最容易混叠)
  • 频域特性:Gaussian → B-spline → Tent → Box(Gaussian 的频域最干净)

10.4 图像的信号处理

10.4.1 图像滤波的应用

1. 模糊(Blur)

// box 模糊 → 块状效果,有锯齿
// tent 模糊 → 中等平滑
// Gaussian 模糊 → 自然平滑(最常用)

2. 锐化(Sharpening)

锐化 = 原图 + α × (原图 - 模糊图)

先做模糊,再从原图减去模糊结果得到"高频细节",再加回原图。α 控制锐化强度。

3. 软阴影(Soft Drop Shadow)

阴影 = (原图 × 偏移脉冲) * Gaussian

先把原图偏移(模拟阴影偏移),再做高斯模糊(让阴影边缘柔和)。

4. 抗混叠(Antialiasing)

// 先模糊再采样 = 抗混叠的本质
anti_aliased = downsample(blur(image, kernel_size))
重要洞察:图像处理中几乎所有"效果"都是卷积的变体。模糊 = 低通滤波(保留低频,抑制高频)。锐化 = 高频增强(从原图中提取并加强高频)。边缘检测 = 高通滤波(只保留高频)。卷积是图形学的"万能工具"。

10.4.2 图像混叠

图像混叠 = "采样率不足以表达图像"

两种典型表现

现象原因例子
Moiré 图案周期纹理和采样网格"打架"细条纹衬衫在屏幕上出现彩色波纹
锯齿(Jaggies)高频边缘被离散化成"楼梯"形斜线看起来像阶梯

解决方案:在采样前用低通滤波器(抗混叠)去掉高于奈奎斯特频率的高频成分。

10.4.3 重采样(Resampling)

重采样 = 改变图像的分辨率(放大/缩小)

两步法

  1. 重建:用连续滤波器把离散样本变成连续函数
  2. 采样:在新网格上采样这个连续函数

"采样间距"决定滤波器大小

  • 下采样(缩小):滤波器应基于输出间距——需要更大的滤波器来避免混叠
  • 上采样(放大):滤波器应基于输入间距——只需平滑插值
// 可分离重采样——先处理所有行,再处理所有列
// 把 2D 重采样变成 2 次 1D 重采样,效率极高

function resample(image, new_width, new_height):
    // 第一步:水平方向重采样
    temp = new Image(new_width, image.height)
    for each pixel (x, y) in temp:
        temp[x][y] = sample_1d(image, x, y, direction="horizontal")

    // 第二步:垂直方向重采样
    result = new Image(new_width, new_height)
    for each pixel (x, y) in result:
        result[x][y] = sample_1d(temp, x, y, direction="vertical")

    return result
🤔 想一想:最简单的"缩小"方法是什么?直接扔掉多余的像素行不行?
这就是"像素丢弃"(pixel dropping)——扔掉不需要的像素。速度最快,但会产生严重的锯齿。仅用于预览或缩略图。正确做法是:先做低通滤波(模糊)再采样,即抗混叠。

10.5 采样理论

10.5.1 傅里叶变换(Fourier Transform)

傅里叶变换
图10-5:傅里叶变换——时域中的复杂波形可以分解为频域中不同频率的简单正弦波

核心思想任何函数都可以表示为不同频率正弦波的叠加

f(x) = ∫ f̂(ω) · e^{2πiωx} dω

公式拆解

符号含义直觉
f(x)时域信号随时间变化的信号值
f̂(ω)傅里叶变换(频域)频率 ω 处的"成分"强度
ω频率每秒振荡次数
e^{2πiωx}复正弦波频率为 ω 的"纯净"正弦波

生活类比:食谱

一道菜(时域信号 f)可以用"配方"(频域 f̂)来描述——面粉多少克(低频成分)、盐多少克(中频)、辣椒多少克(高频)。傅里叶变换就是从"成品菜"反推出"配方"。

10.5.2 傅里叶变换的关键性质

性质公式含义
能量守恒∫|f(x)|²dx = ∫|f̂(ω)|²dω时域和频域的能量总和相等
卷积定理F{f*g} = f̂·ĝ时域卷积 = 频域乘法
对偶性F{f·g} = f̂*ĝ时域乘法 = 频域卷积
重要洞察:卷积定理是图形学中最"强大"的公式之一。频域让卷积变成乘法。这意味着:在频域中分析滤波器效果非常简单——只需看滤波器的傅里叶变换即可。这也是为什么"傅里叶变换"是图形学的"魔法"。

10.5.3 傅里叶变换的"画廊"

不同函数在时域和频域的对应关系:

时域函数时域形状频域函数频域形状
Box方波sinc(sin(πω)/πω)振荡衰减,有副瓣
Tent三角形sinc²比 sinc 平滑,副瓣更小
Gaussian钟形还是 Gaussian!指数衰减,无副瓣
B-spline平滑多项式sinc⁴更平滑,副瓣极小
δ(脉冲)单根竖线常数(所有频率等强)水平直线
// 为什么 Gaussian 的傅里叶变换还是 Gaussian?
// 这是数学上的一个巧妙的巧合(固定点性质)
// 这意味着 Gaussian 在时域和频域都是"最平滑"的——
// 没有副瓣(sinc 的问题),没有振铃(box 的问题)

// 方波 → sinc 的直观理解:
// 一个"方"的脉冲包含了很多高频成分(突然跳变)
// 所以频域中除了主瓣还有副瓣——"振铃"的来源

10.5.4 采样和混叠(频域视角)

采样在频域中是什么? 乘法变卷积:

时域:f(t) × s_T(t) (s_T = 脉冲串,每隔 T 一个脉冲)
频域:f̂(ω) * ŝ_T(ω) (ŝ_T 也是脉冲串,每隔 1/T 一个脉冲)

这意味着

// 采样在频域中的效果:复制+平移
// 原始频谱 f̂(ω) 被"复制"了无数份,每份中心在 k×f_s 处(k 为整数)

// 如果原始信号的最高频率 f_max < f_s/2:
  f̂(ω)        ŝ_T(ω)        结果
  ____         | | |         ____  ____  ____
 /    \        | | |  →     /    \/    \/    \
/      \       | | |       /      \/  ^  \/    \
  原始频谱    采样脉冲      复制频谱不重叠  → 可恢复!

// 如果原始信号的最高频率 f_max > f_s/2:
  f̂(ω)        ŝ_T(ω)        结果 = 混叠!
  __/\__       | | |        __/\__/\__/\__
 /      \      | | |  →    /  \  /  \  /  \
/        \     | | |       /    \/ {} \/    \
  太宽的频谱                  ↑ 重叠部分 = 混叠!
重要洞察:采样 = 频域中"复制频谱"。每个复制 = "奈奎斯特幽灵" = 潜在混叠。如果原始信号超过奈奎斯特频率,复制频谱重叠 → 无法区分哪些成分来自哪个副本 → 混叠。

10.5.5 理想滤波器 vs 实用滤波器

理想滤波器 = sinc 函数

  • 频域是完美的 box(截止频率 f_c 之外全为 0)
  • 时域无限延伸(从 -∞ 到 +∞)——不实用!

实用滤波器(box、tent、Gaussian、B-spline):

  • 都是有限支撑(在有限范围内≠0,之外=0)
  • 频域有泄漏(不能完全截止高频)
  • 实际可计算
滤波器时域支撑频域泄漏混叠抑制模糊程度
理想 sinc无限(不实用)完美
Box有限(1)大(副瓣多)轻微
Tent有限(2)中等中等中等
Gaussian近似有限(3σ)极小(指数衰减)明显
B-spline有限(4)极小明显

10.6 实用考虑

10.6.1 Mipmap = "纹理的金字塔"

Mipmap纹理金字塔
图10-6:Mipmap 金字塔——同一纹理的多个分辨率版本,从 1024² 到 1²

为什么需要 mipmap?

  • 远处的物体在屏幕上只占几个像素
  • 用高分辨率纹理采样 → 浪费计算和内存
  • 用低分辨率版本 → 够用且快

Mipmap 层级

M0: 1024 × 1024(原始纹理,最精细)
M1: 512 × 512(1/2 宽高,1/4 像素数)
M2: 256 × 256
M3: 128 × 128
...
M10: 1 × 1(单个像素)

选择规则:根据屏幕投影大小选择 mipmap 层级。

层级 = log₂(纹理像素数 / 屏幕像素数)
// 数值例子
// 一个纹理在屏幕上占 200 像素宽,纹理本身 1024 像素宽
// 层级 = log₂(1024 / 200) = log₂(5.12) ≈ 2.36
// → 在 M2(256²)和 M3(128²)之间插值(三线性过滤)

// 如果只占 2 个像素:
// 层级 = log₂(1024 / 2) = log₂(512) = 9
// → 直接用 M9(2²=4像素? 不对,M9=1024/2⁹≈2,所以是 2×2 版本)

10.6.2 各向异性过滤(Anisotropic Filtering)

问题:远处倾斜的表面在屏幕上投影成"长方形"——水平方向和垂直方向需要的采样密度不同。

  • 水平方向需要更多采样(纹理压缩得更严重的一个方向)
  • 垂直方向需要更少采样

各向异性 = "在水平/垂直方向用不同大小的滤波器"

实现:从 mipmap 中采样多个点,沿倾斜方向做非均匀采样。

// 各向异性过滤采样模式
// 从 mipmap 沿椭圆形区域采样多个点并加权平均

 anisotropic_samples = 4  // 采样点数(质量参数)
 for i = 0 to anisotropic_samples:
   offset = compute_anisotropic_offset(i, anisotropic_samples)
   color += sample_mipmap(uv + offset, mip_level)
 color /= anisotropic_samples
重要洞察:各向异性过滤是 mipmap 的"升级版"——它解决了 mipmap 的一个假设:屏幕投影是正方形的。对于倾斜表面,各向异性过滤显著提升纹理质量,是现代 GPU 的标配。

10.6.3 边界处理

问题:滤波时,图像边缘的滤波器会"伸出"图像边界——外面的像素是什么?

方法规则适用场景
零填充超出边界的像素 = 0科学计算,纯学术
夹紧(Clamp)超出边界的像素 = 边界像素值大多数图像处理(现代 GPU 默认模式)
环绕(Wrap)超出边界的像素 = 对侧像素无缝纹理(可平铺的贴图)
// 以 1D 信号 [1, 4, 2, 6, 3] 为例,半径 r=1 的 box 滤波器
// 在 i=0 处卷积:

// 零填充:c[0] = (0 + 1 + 4) / 3 = 1.67
// 夹紧:c[0] = (1 + 1 + 4) / 3 = 2.0
// 环绕:c[0] = (3 + 1 + 4) / 3 = 2.67

// 三种方式在 i=2(中间)处输出相同:c[2] = (4 + 2 + 6) / 3 = 4.0
// 差异只在边缘出现

全章总结

核心洞察:信号处理是图形学的"数学骨架"——

  • 卷积 = 滤波(平滑/锐化/阴影/抗锯齿)
  • 采样定理:奈奎斯特频率 = 采样率 / 2
  • 混叠:高频信号"假装"成低频信号
  • 抗混叠:采样前必须用低通滤波器
  • 可分离卷积:2D 滤波器 = 两次 1D 滤波器
  • 傅里叶变换:把卷积变成乘法
  • mipmap:远距离物体的"金字塔"采样

关键公式速查

公式表达式
离散卷积(a * b)[i] = Σⱼ a[j]·b[i-j]
连续卷积(f * g)(x) = ∫ f(t)·g(x-t) dt
傅里叶变换f̂(ω) = ∫ f(x)·e^{-2πiωx} dx
奈奎斯特定理f_max < f_sampling / 2
可分离 GaussianG₂(x,y) = G₁(x)·G₁(y)
卷积定理F{f*g} = f̂·ĝ

一步到位:连续信号 → 采样(奈奎斯特定理约束) → 离散表示 → 卷积滤波 → 重建 → 连续输出。图形学中处处是这个过程。

下一步:第11章将讲解纹理映射——把图像"贴"到 3D 物体表面。配合本章的卷积和采样理论,你将真正理解 mipmap、各向异性过滤等核心概念。

目录 X
章节 X