在 CAD 和计算机图形学中,Tessellation 通常可以翻译为:
在 CAD 渲染场景中,更容易理解的说法是:
Tessellation 是将 CAD 中的精确几何表示离散成 Triangle Mesh 的过程。
例如 CAD Kernel 中可能存在一个精确的圆柱面:
BRep Face
↓
Cylinder Surface
但是 WebGL/GPU 并不能直接绘制 Cylinder Surface、NURBS Surface 或 B-Spline Surface。
GPU 最终绘制的通常是:
position buffer
normal buffer
index buffer
↓
Triangle Mesh
↓
WebGL
因此 CAD 模型真正进入渲染系统之前,一般需要经过:
BRep
↓
Tessellation
↓
Triangle Mesh
↓
WebGL / GPU
这里需要特别注意:
BRep 是精确几何模型,而 Triangle Mesh 通常只是 BRep 的近似渲染表示。
例如 Boolean、Fillet、Offset 等几何运算通常还是针对 BRep 执行,而不是针对渲染 Mesh 执行。
Tessellation 经常和 Triangulation(三角化 / 三角剖分) 混在一起使用。
在 CAD 场景下可以简单理解为:
Tessellation
↓
决定在哪里采样
↓
得到离散点和边界
↓
Triangulation
↓
连接成 Triangle
Triangulation 更关注:
已经有了一组二维点和边界以后,怎么把这个区域划分成三角形。
而 Tessellation 还需要解决:
为了用 Mesh 足够准确地逼近原来的精确曲面,应该在哪里生成采样点?生成多少采样点?
因此:
Triangulation 可以看作 Tessellation 过程中的一个核心步骤。
对于 CAD Face,可以把整个过程理解为:
精确 BRep Face
↓
确定边界
↓
几何采样
↓
Triangulation
↓
Triangle Mesh
BRep 中一个重要概念是:
Face 不等于 Surface。
例如一个 Plane Surface 理论上可以是无限大的:
────────────────────────
────────────────────────
────────────────────────
────────────────────────
但一个 BRep Face 可能只使用其中一小块:
┌──────────────┐
│ │
│ Face │
│ │
└──────────────┘
因此不能简单地:
Surface
↓
全部三角化
而应该根据 Face 的拓扑边界决定有效区域:
Face
├── Surface
├── Outer Wire
└── Inner Wires
Tessellation 最终只应该覆盖:
Outer Wire 内部,并且排除所有 Inner Wire 表示的孔洞区域。
例如下面这个 Face:
┌─────────────────────────┐
│ │
│ ┌─────────┐ │
│ │ Hole │ │
│ └─────────┘ │
│ │
└─────────────────────────┘
其中:
外矩形 → Outer Wire
内矩形 → Inner Wire
如果只是随意在 Face 上采样一些点,再执行普通三角化:
采样点
↓
Triangulation
三角形可能跨过 Hole。
因此 CAD Face 的三角化通常需要把:
Outer Wire
Inner Wire
作为约束边界。
也就是说:
三角形不能跨越 BRep Edge,Inner Wire 内部也不能产生三角形。
这类问题属于 Constrained Triangulation(约束三角剖分)。
参数曲面可以写成:
[ P=S(u,v) ]
其中:
u、v
是 Surface 参数。
例如一个圆柱在三维空间中看起来是:
_______
/ \
/ \
| |
| |
| |
\ /
但它具有二维 UV 参数空间:
v
↑
│
│ ┌──────────────────┐
│ │ │
│ │ │
│ │ │
│ └──────────────────┘
│
└────────────────────────→ u
BRep Face 的 Edge 又通常可以拥有对应 Surface 上的 P-Curve。
因此可以形成这样一个过程:
BRep Face
│
├── Surface
│
└── Wire / Edge
↓
P-Curve
↓
UV 参数空间
↓
Outer / Inner Boundary
↓
二维约束三角化
↓
UV Triangles
↓
S(u,v)
↓
3D Triangles
例如二维三角形的三个顶点:
(u1, v1)
(u2, v2)
(u3, v3)
通过 Surface 求值得到:
[ P_1=S(u_1,v_1) ]
[ P_2=S(u_2,v_2) ]
[ P_3=S(u_3,v_3) ]
最终得到 GPU 可以绘制的三维 Triangle。
对于平坦区域:
────────────────────────
使用比较大的 Triangle 就已经能很好地逼近真实 Surface。
但如果曲率很大:
____
__/ \__
__/ \__
如果 Triangle 仍然很大:
●────────────────●
\ /
\ /
●────────
Mesh 和真实曲面之间就可能出现明显偏差。
因此实际 Tessellation 往往采用:
Adaptive Tessellation,自适应细分。
基本原则是:
平坦区域
↓
少量采样
↓
较大 Triangle
高曲率区域
↓
增加采样
↓
较小 Triangle
从而在:
几何精度
↕
Triangle 数量
↕
GPU 性能
之间取得平衡。
Chordal Deviation 可以翻译为:
弦偏差、弦高误差
在一些 CAD Kernel 中也经常看到类似:
Linear Deflection,线性偏差。
它主要用于控制:
离散 Mesh 与真实几何之间的位置误差。
以曲线为例:
真实曲线
*********
*** ↑ ***
●────────│────────●
d
弦
两个采样点之间最终使用线段近似。
真实曲线和线段之间的最大距离 d 就可以理解为弦偏差。
假设 Tessellation 参数要求:
Chordal Deviation <= 0.1 mm
如果:
当前误差 = 0.5 mm
那么说明当前离散结果太粗:
继续增加采样点
↓
进一步细分
直到满足误差要求。
因此:
Chordal Deviation 越小
↓
要求越严格
↓
采样越密
↓
Triangle 越多
↓
Mesh 越接近真实 Surface
反之:
Chordal Deviation 越大
↓
允许误差越大
↓
Triangle 越少
↓
渲染性能越高
Angular Deviation 通常翻译为:
角偏差。
它主要用于控制:
Surface 方向或者法向变化是否被 Mesh 足够准确地表达。
例如曲面不同位置的法向:
N1 ↑
↗ N2
→ N3
如果一个 Triangle 覆盖整个区域:
●────────────●
\ /
\ /
●
虽然位置误差可能没有超过 Chordal Deviation,但真实 Surface 的方向变化可能已经非常明显。
因此还可以检查:
[ \theta = \angle(N_1,N_2) ]
如果:
θ > AngularDeviation
就继续进行细分。
可以简单记:
Chordal Deviation
↓
控制位置误差
↓
Mesh 离真实几何有多远
Angular Deviation
↓
控制方向误差
↓
曲面的弯曲变化是否表达充分
Chordal Deviation 和 Angular Deviation 都可以作为:
决定 Tessellation 采样密度和是否继续细分的误差判据。
假设两个 BRep Face:
Face A
│
│ Shared Edge E
│
Face B
它们共享同一条拓扑 Edge。
如果 Face A 自己对 Edge 采样:
●────●────●────●
而 Face B 自己重新采样:
●──●──────●──●─●
那么最终两个 Face 的 Mesh 边界:
Face A
────●────●────●────
Face B
──●──────●──●──────
顶点无法对应。
这样可能出现:
Crack / Seam,即 Mesh 裂缝。
比较合理的设计是:
BRep Shared Edge
↓
统一进行 Curve Tessellation
↓
P0 P1 P2 P3 P4
│
┌───┴───┐
↓ ↓
Face A Face B
两个 Face 的 Triangle Mesh 都必须使用:
P0
P1
P2
P3
P4
作为公共边界。
即:
Face A
────●────●────●────
Face B
────●────●────●────
这体现了一个非常重要的 CAD 思想:
Tessellation 不能完全脱离 BRep Topology 单独处理 Surface。
Topology 已经告诉我们:
Face A
Face B
共享:
Edge E
那么 Mesh 层也应该保持这层共享关系,从而保证模型 watertight,避免视觉裂缝。
经过 Tessellation 后,一个 Face 最终可能得到:
struct FaceMesh {
std::vector<Vec3> positions;
std::vector<Vec3> normals;
std::vector<Vec2> uvs;
std::vector<uint32_t> indices;
FaceId faceId;
};
然后上传到 WebGL:
positions
normals
uv
indices
↓
BufferGeometry
↓
GPU
对于 CAD 系统,还应该尽量保留:
Triangle
↓
FaceId
这样的对应关系。
因为 Picking 后:
Mouse
↓
Ray
↓
Triangle
↓
FaceId
↓
BRep Face
才能从渲染 Mesh 找回真正的 CAD 拓扑对象。
CAD 的 Triangle Mesh 虽然主要用于渲染,但也经常参与 Picking。
例如:
BRep Face
↓
Tessellation
↓
Triangles
↓
BVH
用户点击模型:
Mouse
↓
Ray
↓
BVH
↓
Triangle
↓
FaceId
↓
BRep Face
因此 Tessellation 不仅需要生成 Triangle,还最好保留:
Triangle → Face
Face → Entity
映射。
这也是 CAD Render Model 和普通 Three.js 场景之间一个很重要的区别。
LOD 是:
Level of Detail,细节层次。
核心思想是:
同一个 CAD 几何准备多个不同精细程度的 Mesh,根据当前观察距离或者屏幕尺寸选择不同版本。
例如:
BRep
│
├── LOD 0
│ 100,000 triangles
│
├── LOD 1
│ 20,000 triangles
│
└── LOD 2
2,000 triangles
近距离观察:
Camera
↓
████████████
模型占据大量屏幕像素
→ LOD 0
远距离观察:
Camera
↓
▪
Model
→ LOD 2
因为模型在屏幕上可能只剩几十个像素,即使继续使用几十万个 Triangle,用户也无法看到区别。
LOD 本身不是 Tessellation 算法。
可以理解成:
LOD 是对多个不同 Tessellation 精度结果进行管理和选择的渲染策略。
例如:
BRep
│
┌─────────────┼─────────────┐
▼ ▼ ▼
精细 Tessellation 中等 Tessellation 粗 Tessellation
│ │ │
▼ ▼ ▼
LOD0 LOD1 LOD2
可以使用不同的 Chordal Deviation:
LOD0
Chordal Deviation = 0.01 mm
LOD1
Chordal Deviation = 0.1 mm
LOD2
Chordal Deviation = 1 mm
允许的几何误差越大:
Triangle 越少
如果用户只是:
Zoom In
Zoom Out
Rotate Camera
BRep 几何本身并没有改变。
因此通常不希望:
每次 Camera 改变
↓
重新 Tessellate BRep
↓
重新生成 Mesh
↓
重新上传 GPU
因为这一过程成本比较高。
一种更常见的设计是:
提前或者按需生成:
LOD0
LOD1
LOD2
↓
缓存
运行时:
Camera
↓
计算物体屏幕尺寸
↓
选择合适 LOD
↓
直接渲染已有 Mesh
这样 Camera 运动时只进行 Mesh 切换,而不是不断重新执行几何算法。
例如两个零件:
Part A:10000 mm
Part B:10 mm
虽然它们离 Camera 的距离相同,但最终屏幕尺寸完全不同。
真正影响用户能否看到几何误差的是:
Mesh 的误差最终投影到屏幕后占多少像素。
因此大型 CAD 系统可以考虑:
Tessellation 几何误差
↓
Camera Projection
↓
Screen Space Error
↓
选择 LOD
例如:
当前误差投影到屏幕 < 0.5 px
→ 当前 LOD 已经足够
这样比简单判断:
distance < 100
更加合理。
从职责上看,Tessellation 更适合属于:
Geometry Kernel / Geometry Processing 层。
因为 Tessellation 需要理解:
BRep
Face
Edge
P-Curve
Surface
UV
Tolerance
Topology
这些都是 Geometry Kernel 的核心数据。
因此比较自然的架构是:
Geometry Kernel
│
│ BRep
↓
Tessellation
│
│ Triangle Mesh
↓
Render Engine
│
↓
WebGL
Render Engine 不需要真正理解:
NURBS
B-Spline
TopoDS_Face
P-Curve
它主要消费:
Position
Normal
UV
Index
EntityId
FaceId
等渲染数据。
云 CAD 中 Geometry Kernel 不一定只存在于某一个地方。
架构:
Server
BRep
↓
Geometry Kernel
↓
Tessellation
↓
Triangle Mesh
↓
Network
↓
Browser
↓
WebGL
优点:
缺点:
例如把 C++ Geometry Kernel 编译成 WASM:
Browser
BRep
↓
WASM Geometry Kernel
↓
Tessellation
↓
Triangle Mesh
↓
WebGL
优点:
缺点:
实际云 CAD 可以采用混合方案:
首次打开大型模型
↓
Server 直接提供已有 Mesh
↓
快速首屏
用户修改当前零件
↓
Browser WASM
↓
局部 Tessellation
复杂 Boolean / 几何计算
↓
Server Kernel
最终根据:
几何计算成本
网络传输量
首屏速度
交互延迟
客户端性能
缓存策略
决定任务放在哪里执行。
最终可以把整个过程总结成:
BRep Face
│
┌───────────┴───────────┐
↓ ↓
Surface Topology
│
Outer / Inner Wire
│
Edge
│
P-Curve
│ │
└───────────┬───────────┘
↓
UV 参数空间
│
↓
建立约束边界
│
↓
根据几何误差进行采样
│
┌────────────┴────────────┐
↓ ↓
Chordal Deviation Angular Deviation
控制位置误差 控制方向误差
│ │
└────────────┬────────────┘
↓
Adaptive Tessellation
│
↓
Constrained Triangulation
│
↓
UV Triangles
│
S(u,v)
│
↓
3D Triangles
│
┌─────────┴─────────┐
↓ ↓
Position Normal
│ │
└─────────┬─────────┘
↓
Index Buffer
│
↓
Triangle Mesh
│
↓
WebGL / GPU
CAD 中的 Tessellation 可以概括为:
将精确的 BRep 几何按照一定误差要求离散成 Triangle Mesh,使其能够被 GPU 实时绘制。
其中几个最重要的概念是:
不能只对无限 Surface 三角化,而需要根据:
Outer Wire
Inner Wire
确定 Face 的真正有效区域。
可以利用:
Surface + P-Curve
把复杂三维曲面的边界转化到二维 UV 空间,在二维空间完成约束三角剖分,再映射回三维。
不是所有区域采用同样密度:
平坦区域 → 少量 Triangle
高曲率区域 → 更多 Triangle
控制:
Mesh 与真实几何之间的位置误差。
控制:
Mesh 对真实 Surface 方向变化的表达误差。
两者都是决定采样密度和是否继续细分的重要标准。
两个相邻 BRep Face 的公共 Edge 应该统一离散,并共享相同边界采样点,从而避免:
Crack / Seam
同一个 BRep 可以拥有多个不同 Tessellation 精度的 Mesh:
LOD0
LOD1
LOD2
根据屏幕尺寸或 Screen Space Error 选择适当版本,而不是用户每次 Zoom 都重新 Tessellate。
最终需要建立一个非常重要的认识:
BRep
↓
精确几何模型
Tessellation
↓
几何离散化
Triangle Mesh
↓
近似渲染表示
WebGL
↓
GPU 实时显示
对于同时涉及几何建模和 WebGL 渲染的 CAD 系统而言,Tessellation 正是连接 Geometry Kernel 和 Render Engine 的关键桥梁。
(完)