三维扫描、建模导出或物理仿真得到的网格模型,常常带有高频噪声:顶点位置出现微小抖动,表面看起来"毛糙",法向计算不稳定,进而影响渲染质量与后续的曲面重建。平滑处理(Mesh Smoothing / Denoising)的目的就是抑制这些噪声,让曲面更加光顺。最经典的两种做法是拉普拉斯平滑(Laplacian Smoothing)和双边滤波(Bilateral Filtering)。前者实现简单、速度快,但容易"连细节一起抹平";后者计算量更大,却能在去噪的同时保留棱角等几何特征。本文将从原理、实现、效果三个层面对两者做深入对比。

拉普拉斯平滑:原理与实现
拉普拉斯平滑的核心思想非常直观:把每个顶点向其邻居顶点的"重心"方向移动。对于网格中某个顶点 v,设其一环邻域(直接相邻的顶点集合)为 N(v),邻居数量为 n,则平滑公式为:
# 拉普拉斯平滑单次迭代(均匀权重)
import numpy as np
def laplacian_smooth(vertices, adjacency, iterations=5, lam=0.5):
verts = vertices.copy()
for _ in range(iterations):
new_verts = verts.copy()
for i in range(len(verts)):
neighbors = adjacency[i]
if len(neighbors) == 0:
continue
# 计算邻居重心
centroid = np.mean(verts[neighbors], axis=0)
# 顶点向重心方向移动
new_verts[i] = verts[i] + lam * (centroid - verts[i])
verts = new_verts
return verts
公式中的 lam 是松弛因子,控制每次移动的步长。权重方案除了均匀权重外,还可以采用余切权重(cotangent weights),即按邻接三角形内角计算权重,这样得到的重心更符合曲面度量,平滑效果在各向异性网格上更均匀。基于余切权重的拉普拉斯算子也叫离散拉普拉斯-贝尔特拉米算子,是微分几何在网格上的经典离散化。
拉普拉斯平滑最大的问题是体积收缩和特征丢失。想象一个立方体:顶点不断向邻居重心移动,棱角会逐渐被磨圆,多次迭代后立方体明显变小。理论研究表明,高频迭代下拉普拉斯平滑会使网格收敛到质心一点。缓解手段包括:降低迭代次数与步长、采用 Taubin 的 λ|μ 算法(先用 λ 收缩再用负系数 μ 膨胀,交替执行以抵消收缩),或者使用 HC 算法约束顶点偏移。但这些方法只能减缓,无法从根本上解决特征模糊的问题。
双边滤波:在去噪的同时保留特征
双边滤波源自图像处理领域。在图像中,双边滤波同时考虑像素之间的空间距离和像素值差异:距离越近且灰度越接近的像素权重越大,因此在平坦区域强力去噪、在边缘处自动降低平滑强度。将这一思想迁移到网格上时,"像素值差异"被替换为顶点在法向上的投影偏差。
经典的网格双边滤波(以 Jones 等人提出的算法为代表)分两步执行。第一步是法向平滑:对每个面的法向,用邻域面法向做双边加权平均(权重同时考虑面的空间距离和法向夹角),得到更光滑但仍保留特征的法向场。第二步是顶点更新:对每个顶点,沿其法向方向移动一个双边加权的偏移量,公式形式为:
# 顶点双边滤波的简化实现思路
import numpy as np
def bilateral_vertex_update(v, normal_v, neighbors, sigma_s, sigma_n):
# v: 当前顶点, normal_v: 顶点法向
# neighbors: (位置数组, 法向数组)
# sigma_s: 空间高斯衰减, sigma_n: 法向偏差高斯衰减
positions, normals = neighbors
total_w = 0.0
offset = 0.0
for q, nq in zip(positions, normals):
dist = np.linalg.norm(q - v) # 空间距离
proj = np.dot(q - v, normal_v) # 法向投影偏差
w_s = np.exp(-(dist * dist) / (2 * sigma_s ** 2))
w_n = np.exp(-(proj * proj) / (2 * sigma_n ** 2))
w = w_s * w_n
offset += w * proj
total_w += w
if total_w > 1e-12:
return v + normal_v * (offset / total_w)
return v
关键在于两个参数:空间标准差 sigma_s 决定滤波的空间范围(类似邻域半径),而法向标准差 sigma_n 决定"多大的偏差算特征"。当一个邻居顶点与当前顶点的法向投影偏差很大(比如跨过一条棱边)时,w_n 趋近于零,该邻居几乎不参与平均,棱边因此得以保留。这种自适应权重机制正是双边滤波优于拉普拉斯平滑的根本原因。
双边滤波的代价是计算复杂度更高:每个顶点需要计算两两距离与投影,参数选择也更敏感。sigma_n 设置过大时退化为普通高斯平滑,特征照样被抹掉;设置过小时噪声又难以去除。此外,双边滤波对法向质量依赖较大,如果原始法向本身噪声严重,通常需要先做多轮法向平滑。
效果对比与场景选择建议
从实际效果看,两者可以用三个维度衡量。第一是噪声抑制能力:在相同迭代强度下,拉普拉斯平滑对高频抖动的抑制更彻底,表面会明显变"松";双边滤波去噪相对保守。第二是特征保留程度:在带有明显棱边、尖角的机械零件模型上,拉普拉斯平滑几轮之后棱线就开始模糊发圆,而双边滤波能长时间保持锐利的特征边。第三是体积与形状保持:拉普拉斯平滑存在系统性收缩,细长结构(如天线、薄壁)变形最严重;双边滤波基本维持原始形状。下表总结了主要差异:
| 对比项 | 拉普拉斯平滑 | 双边滤波 |
|---|---|---|
| 实现难度 | 简单,十几行代码 | 较复杂,需法向处理 |
| 计算开销 | 低,可实时交互 | 较高,大规模网格需加速结构 |
| 特征保留 | 差,棱角变圆 | 好,边角自适应保留 |
| 体积收缩 | 明显 | 基本无 |
| 参数敏感性 | 迭代次数与步长,较直观 | sigma_s 与 sigma_n,需要调参 |
基于这些特性,可以给出场景化建议。对于有机曲面模型(人物、动物、雕塑),本身没有锐利特征,追求表面光顺,拉普拉斯平滑或其改进版 Taubin 算法性价比最高,交互式建模软件中的平滑笔刷通常也是这个思路。对于扫描或逆向工程模型,既有噪声又需要保住机械结构的棱线、孔口边缘,双边滤波或更现代的保特征去噪算法(如引导法向滤波)是更合适的选择。对于动画角色网格,可以在绑骨前对低噪网格做少量拉普拉斯平滑,而绑定后应避免大面积平滑,防止破坏与权重、 Blendshape 的对应关系。
最后补充一点实践经验:无论用哪种算法,都建议在原始网格上保留备份,平滑处理尽量以"多次小幅迭代"代替"一次大幅处理",每轮迭代后旋转观察特征区域(棱线、孔洞边缘、细小结构件),一旦出现不希望的变形就回退。在工程化实现中,还可以把两种方法组合使用:先用法向双边滤波修正法向场,再用小步长拉普拉斯平滑做最终抛光,兼顾效率与质量。掌握这两种基础算法的思想后,再去理解引导滤波、各向异性扩散等更先进的网格去噪方法也会水到渠成。