OpenFracture
https://github.com/dgreenheck/OpenFracture
概要
提供了比较完善的mesh切分算法,不过切分方式比较单一
好处是可以渐进式切分,异步不断一刀一刀切
不用一次性生成一大堆碎片导致卡顿
大致算法:
1 | mesh入队 |
一些算法细节
Slice
1 | public static void Slice(FragmentData meshData, |
meshData:
- sliceNormal : 切割方向
- sliceOrigin : 切割原点
- textureScale : 纹理缩放比例
- textureOffset : 纹理偏移
- topSlice : 切分后的上半部分数据
- bottomSlice : 切分后的下半部分数据
- FragmentData 切割过程中的辅助数据结构,用于存放Mesh数据
new FragmentData(meshData.vertexCount, meshData.triangleCount);
初始化的时候直接传入顶点数和三角数,避免resize 和GC
切分三角
1 | private static void SplitTriangles(FragmentData meshData, |
v3BelowCutPlane从来标记两种情况
即单独顶点v3处于法线方向还是背向法线方向
1 | private static void SplitTriangle(int v1_idx, |
这里对于法线和UV的处理(等比例划分 s13/s23是切分线段的比例)
1 | var norm13 = (v1.normal + s13 * (v3.normal - v1.normal)).normalized; |
Q:为何要分上下平面?
A 因为要分内外表面(法线方向),并根据这个生成正确的三角形序列(环绕方向,逆时针为正)
填充切面
此处针对上下半平面,顶点和三角数据只需要计算一次,法线相反即可
1 | private static void FillCutFaces(FragmentData topSlice, |
三角化
1 | //1. |
1中,会根据切分平面建立2维坐标系(因为是一刀切的,所以所有点都在一个平面上)
1 | //叉乘找到基向量 |
2中是真正的三角化步骤,这里是用这篇论文提供的CDT算法,这里略过:
[1] Sloan, Scott W. “A fast algorithm for generating constrained Delaunay triangulations.” Computers & Structures 47.3 (1993): 441-450.
其他一些数学相关操作
- 判断线面相交:
- a,b: 线段
- n : 平面法线
- p0 : 平面原点
输出: - bool : 是否发生穿插
- x : 交点
- s : 切分线段比例 (即:x = a+ (b-a) * s )
此处根据(p0->a)和(b-a)投影比例判断是否穿插
(如果穿插,则s位于[0,1]之间)
(这里平面为无限平面)
1 | public static bool LinePlaneIntersection(Vector3 a, |
- 判断是否在某个面上方(法线方向):
- p : 要判断的顶点
- n : 法线方向
- o : 平面原点位置
这里实际上就是用向量方向和法线方向做了一次内积
1 | public static bool IsAbovePlane(this Vector3 p, Vector3 n, Vector3 o) |
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Comment
ValineDisqus