142 lines
3.7 KiB
Markdown
142 lines
3.7 KiB
Markdown
# 核心算法设计
|
||
|
||
## 目录
|
||
|
||
1. [Delaunay 三角剖分(2D)](#1-delaunay-三角剖分2d)
|
||
2. [NURBS 曲线求值](#2-nurbs-曲线求值)
|
||
3. [GJK 碰撞检测](#3-gjk-碰撞检测)
|
||
4. [网格简化(QEM)](#4-网格简化qem)
|
||
5. [BVH 构建(SAH)](#5-bvh-构建sah)
|
||
6. [2D 多边形布尔运算](#6-2d-多边形布尔运算)
|
||
|
||
---
|
||
|
||
## 1. Delaunay 三角剖分(2D)
|
||
|
||
**算法**:Bowyer-Watson 增量算法
|
||
**复杂度**:O(n log n) 期望,O(n²) 最坏
|
||
|
||
```
|
||
算法步骤:
|
||
1. 构造一个覆盖所有输入点的超级三角形
|
||
2. 逐点插入:
|
||
a. 找到外接圆包含新点的所有"坏"三角形
|
||
b. 提取坏三角形的边界边(只保留不重复的边)
|
||
c. 删除坏三角形
|
||
d. 用新点与每条边界边连接,形成新三角形
|
||
3. 删除包含超级三角形顶点的三角形
|
||
```
|
||
|
||
**关键实现细节**:
|
||
- 三角形预存外接圆圆心和半径,加速包含判断
|
||
- 用哈希集合高效提取边界边(出现两次的边=内部边,删除;出现一次的边=边界边,保留)
|
||
|
||
---
|
||
|
||
## 2. NURBS 曲线求值
|
||
|
||
**算法**:Cox-de Boor 递推公式
|
||
|
||
```
|
||
求值步骤:
|
||
1. find_span(t):二分查找 t 所在的节点区间
|
||
2. basis_functions(t, span):递推计算基函数 N_{i,p}
|
||
3. 加权组合:P(t) = Σ N_i·w_i·cp_i / Σ N_i·w_i
|
||
```
|
||
|
||
**基函数递推**:
|
||
|
||
```
|
||
N_{i,0}(t) = 1 若 knots[i] ≤ t < knots[i+1],否则 0
|
||
|
||
N_{i,p}(t) = (t - knots[i]) / (knots[i+p] - knots[i]) · N_{i,p-1}(t)
|
||
+ (knots[i+p+1] - t) / (knots[i+p+1] - knots[i+1]) · N_{i+1,p-1}(t)
|
||
```
|
||
|
||
**复杂度**:O(p²),p 为阶数
|
||
|
||
---
|
||
|
||
## 3. GJK 碰撞检测
|
||
|
||
**算法**:Gilbert-Johnson-Keerthi
|
||
**用途**:检测两个凸体是否相交
|
||
|
||
```
|
||
核心思想:
|
||
1. 定义 Minkowski 差:C = A ⊖ B = {a - b | a∈A, b∈B}
|
||
2. A 与 B 相交 ⇔ C 包含原点
|
||
3. 迭代构建包含原点的单纯形(点→线→三角形→四面体)
|
||
4. 每步使用 support 函数在 Minkowski 差上采样
|
||
5. 3D 中最多约 40 次迭代即可得到结果
|
||
```
|
||
|
||
**Minkowski 差的 support 函数**:
|
||
```
|
||
support(d) = support_A(d) - support_B(-d)
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 网格简化(QEM)
|
||
|
||
**算法**:Quadric Error Metrics(Garland & Heckbert, SIGGRAPH 1997)
|
||
|
||
```
|
||
算法步骤:
|
||
1. 计算每个顶点的二次误差矩阵 Q(v)
|
||
2. 计算每条边的收缩代价:cost(e) = v_opt^T · (Q_v1 + Q_v2) · v_opt
|
||
3. 将所有边按代价放入最小堆
|
||
4. 贪心循环:
|
||
a. 弹出代价最小的边
|
||
b. 收缩该边到最优位置(或中点)
|
||
c. 更新所有受影响边的代价
|
||
5. 重复直到达到目标面数
|
||
```
|
||
|
||
**Q 矩阵定义**:对每个顶点 v,其 Q 矩阵为相邻面平面方程的外积和:
|
||
```
|
||
Q(v) = Σ K_p^T · K_p,其中 K_p = [a b c d],ax+by+cz+d=0
|
||
```
|
||
|
||
---
|
||
|
||
## 5. BVH 构建(SAH)
|
||
|
||
**算法**:表面积启发式(Surface Area Heuristic)
|
||
|
||
```
|
||
SAH 代价函数:
|
||
C = C_trav + (n_L·area_L + n_R·area_R) / area_total · C_isect
|
||
|
||
构建过程:
|
||
1. 对当前节点计算包围盒
|
||
2. 若图元数 ≤ leaf_size 或深度 ≥ max_depth → 创建叶节点
|
||
3. 否则:
|
||
a. 沿最长轴排序图元(按质心坐标)
|
||
b. 尝试多个分割位置,计算 SAH 代价
|
||
c. 选择代价最低的分割
|
||
d. 如果分割代价 ≥ 不分割的代价 → 创建叶节点
|
||
e. 否则递归构建左右子树
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 2D 多边形布尔运算
|
||
|
||
**算法**:Sutherland-Hodgman 裁剪(当前实现)
|
||
**目标算法**:Vatti 扫描线算法(对标 Clipper2)
|
||
|
||
```
|
||
当前实现(S-H):
|
||
1. 以裁剪多边形为窗口
|
||
2. 对主题多边形的每条边逐一裁剪
|
||
3. 时间复杂度 O(n·m)
|
||
|
||
规划实现(Vatti):
|
||
1. 扫描线遍历所有边交点
|
||
2. 边分割与标记(内部/外部)
|
||
3. 提取结果轮廓
|
||
4. 支持任意多边形(含自交、带孔)
|
||
```
|