34 KiB
geometry3Sharp 空间数据结构集成方案
1. 背景与动机
1.1 当前碰撞检测的性能瓶颈
NavisworksTransport 项目在物流路径动画中实现了碰撞检测功能,但存在以下性能问题:
当前实现的问题:
// ClashDetectiveIntegration.cs - DetectCollisions()
// 线性遍历所有几何对象,O(n) 复杂度
foreach (var item in allGeometryItems)
{
if (IsColliding(animatedObject, item))
{
collisions.Add(item);
}
}
性能数据(来自实际日志):
- 场景对象总数:290 个
- 潜在碰撞对象:108 个(经过路径包围盒预过滤)
- 每帧碰撞检测:遍历 108 个对象
- 动画总帧数:300 帧
- 总计算量:300 × 108 = 32,400 次包围盒检测
优化空间:
- 空间查询仍然是线性遍历(即使经过预过滤)
- 包围盒距离计算不精确(AABB vs 实际几何距离)
- 没有层次化空间索引加速
- 动态查询效率低(物体移动时重新遍历)
1.2 空间数据结构的必要性
需求场景:
- 动画碰撞检测:物体每帧移动,需要快速查询"当前位置附近有哪些障碍物"
- 潜在碰撞对象过滤:在路径规划前,快速找到路径沿途的所有可能碰撞物体
- 精确距离计算:计算物体到障碍物的真实距离(不是包围盒距离)
- 路径可达性验证:检查两点间的直线是否被障碍物阻挡
理想的解决方案特征:
- ✅ O(log n) 或 O(1) 平均查询复杂度
- ✅ 支持动态位置的范围查询
- ✅ 精确的几何距离计算
- ✅ 商业友好的许可证
- ✅ 与 .NET Framework 4.8 兼容
2. geometry3Sharp 库概述
2.1 基本信息
项目信息:
- 官方名称:geometry3Sharp (本项目使用的是 fork: geometry4Sharp)
- GitHub:https://github.com/gradientspace/geometry3Sharp (原版)
- GitHub:https://github.com/NewWheelTech/geometry4Sharp (fork)
- 许可证:Boost Software License 1.0(商业友好,无需开源衍生代码)
- 维护状态:原版活跃度降低(2019后),fork 有维护
- 平台兼容:.NET Standard 2.0, .NET Framework 4.8, .NET 6.0
- 语言:纯 C#,无 C++ 互操作
代码来源:
- 核心算法移植自 David Eberly 的 WildMagic5 和 GTEngine(几何计算领域的经典库)
- MeshSignedDistanceGrid 基于 Christopher Batty 的 SDFGen C++ 代码
- 经过多年实战验证,代码质量高
2.2 与体素网格方案的关系
重要说明:geometry3Sharp 不是替代体素网格方案,而是互补关系。
| 模块 | 用途 | 应用场景 |
|---|---|---|
| 体素网格 (MeshSignedDistanceGrid, Bitmap3, DSparseGrid3) | 3D 空间离散化,路径规划 | 生成可通行网格,3D A* 路径规划 |
| 空间索引 (DMeshAABBTree3, PointHashGrid3d) | 快速空间查询,碰撞检测 | 动画碰撞检测,范围查询优化 |
| 距离查询 (DistPoint3Triangle3) | 精确几何距离 | 碰撞容差计算,最近点查询 |
| 相交查询 (IntrRay3Triangle3) | 射线-几何相交 | 路径可达性验证,视线检测 |
集成策略:
- 体素网格用于路径规划(已在
体素网格路径规划方案.md中详细设计) - 空间索引用于碰撞检测加速(本文档重点)
- 两者共用 geometry3Sharp 的基础数学类型(Vector3d, AxisAlignedBox3d 等)
3. 高价值模块详细分析
3.1 DMeshAABBTree3 - 层次化 AABB 树
功能描述
DMeshAABBTree3 是三角网格的层次化轴对齐包围盒树,提供 O(log n) 复杂度的空间查询。
核心特性:
- 自底向上或自顶向下构建策略(可选)
- 支持三角形级别的精确相交测试
- 多种空间查询接口
- 泛型遍历接口(DoTraversal)
可用查询:
// 1. 最近三角形查找
int FindNearestTriangle(Point3d point, double maxDistance);
// 2. 射线-网格最近命中
int FindNearestHitTriangle(Ray3d ray, double maxDistance);
// 3. 射线-网格所有命中
List<int> FindAllHitTriangles(Ray3d ray, double maxDistance);
// 4. 三角形相交测试
bool TestIntersection(Triangle3d triangle);
// 5. 树-树相交测试
bool TestIntersection(DMeshAABBTree3 otherTree);
// 6. 树-树所有相交
List<Tuple<int,int>> FindAllIntersections(DMeshAABBTree3 otherTree);
// 7. 树-树范围内最近三角形
List<Tuple<int,int>> FindNearestTriangles(DMeshAABBTree3 otherTree, double maxDist);
// 8. 点包含测试
bool IsInside(Point3d point);
// 9. 缠绕数(Winding Number)
double WindingNumber(Point3d point);
应用场景
场景 1:优化 GetPotentialColliders()
当前实现(线性遍历):
// PathAnimationManager.cs - GetPotentialColliders()
foreach (var item in allGeometryItems)
{
double distance = CalculateDistance(pathCenter, item);
if (distance <= detectionGap)
{
potentialColliders.Add(item);
}
}
使用 AABB 树优化(对数查询):
// 1. 预构建场景的 AABB 树(一次性)
var sceneTree = BuildSceneAABBTree(allGeometryItems);
// 2. 快速范围查询
var potentialColliders = sceneTree.FindNearestTriangles(
animatedObjectTree,
detectionGap
);
性能提升预估:
- 当前:O(n) = 290 次包围盒测试
- 优化后:O(log n) ≈ log₂(290) ≈ 8 次树节点遍历
- 加速比:约 36 倍
场景 2:精确碰撞检测
替代简单包围盒检测,使用三角形级别的精确相交:
// 检查动画对象是否与场景相交
bool hasCollision = animatedObjectTree.TestIntersection(sceneTree);
// 获取所有相交的三角形对
var intersections = animatedObjectTree.FindAllIntersections(sceneTree);
构建策略选择
public enum BuildStrategy
{
TopDownMidpoint, // 最快(默认)
BottomUpFromOneRings, // 平衡但慢 2.5 倍
TopDownMedian // 更平衡但慢 2-4 倍
}
// 推荐:快速构建 + 大量查询场景
var tree = new DMeshAABBTree3(mesh, autoBuild: false);
tree.Build(BuildStrategy.TopDownMidpoint);
技术挑战
挑战 1:Navisworks Geometry → DMesh3 转换
Navisworks 的 ModelItem 不直接暴露三角网格,需要通过几何提取:
// 方案 A:使用 GeometryExtractor(项目已有)
// 需要扩展为输出 geometry3Sharp 的 DMesh3 格式
// 方案 B:使用包围盒代替精确网格(简化版)
// 优点:实现简单,性能好
// 缺点:精度降低(但对预过滤足够)
推荐方案:渐进式实现
- Phase 1:使用包围盒近似(快速验证)
- Phase 2:实现精确几何提取(提升精度)
3.2 PointHashGrid3d - 空间哈希网格
功能描述
PointHashGrid3d<T> 是泛型的 3D 空间哈希表,提供 O(1) 平均时间复杂度的范围查询。
核心特性:
- 基于网格单元的哈希索引
- 支持动态插入/删除/更新
- 线程安全(SpinLock)
- 泛型设计,可存储任意类型
关键方法:
// 初始化(cellSize = 查询半径的 1-2 倍)
var grid = new PointHashGrid3d<ModelItem>(cellSize: 2.0, invalidValue: null);
// 插入点(线程安全)
grid.InsertPoint(modelItem, position);
// 删除点
grid.RemovePoint(modelItem, position);
// 更新点(移动)
grid.UpdatePoint(modelItem, oldPosition, newPosition);
// 范围查询(核心功能)
var nearby = grid.FindNearestInRadius(
queryPosition,
radius,
distanceFunc: (item) => Distance(queryPosition, item.Position)
);
// 批量查询
List<T> FindPointsInBox(AxisAlignedBox3d box);
应用场景
场景 1:加速动画碰撞检测
当前问题:
- 动画每帧都要遍历 108 个潜在碰撞对象
- 300 帧 × 108 对象 = 32,400 次检测
使用空间哈希优化:
// === 初始化阶段(动画开始前)===
var spatialGrid = new PointHashGrid3d<ModelItem>(
cellSize: vehicleRadius * 2, // 格子大小 = 车辆直径
invalidValue: null
);
// 索引所有障碍物(一次性)
foreach (var obstacle in potentialColliders)
{
spatialGrid.InsertPoint(obstacle, obstacle.BoundingBox().Center);
}
// === 动画每帧 ===
// 快速查询当前位置附近的障碍物
var nearbyObstacles = spatialGrid.FindNearestInRadius(
currentPosition,
vehicleRadius + safetyMargin,
(item) => Vector3d.Distance(item.Position, currentPosition)
);
// 只检测附近的对象(通常 < 10 个)
foreach (var obstacle in nearbyObstacles)
{
if (IsColliding(animatedObject, obstacle))
{
collisions.Add(obstacle);
}
}
性能提升预估:
- 当前:每帧检测 108 个对象
- 优化后:每帧检测 5-15 个对象(仅邻近格子)
- 加速比:约 7-20 倍
场景 2:动态场景更新
支持障碍物动态添加/移动:
// 添加新障碍物
spatialGrid.InsertPoint(newObstacle, newObstacle.Position);
// 移动障碍物
spatialGrid.UpdatePoint(movingObstacle, oldPosition, newPosition);
// 删除障碍物
spatialGrid.RemovePoint(removedObstacle, removedObstacle.Position);
格子大小选择
原则:cellSize 应该接近查询半径
// 推荐设置
double vehicleRadius = 0.3; // 米
double safetyMargin = 0.1; // 米
double detectionRadius = vehicleRadius + safetyMargin;
// cellSize = 查询半径 * 1.5
double cellSize = detectionRadius * 1.5; // 约 0.6 米
var spatialGrid = new PointHashGrid3d<ModelItem>(cellSize, null);
权衡:
- cellSize 过小 → 格子太多,内存和查询开销大
- cellSize 过大 → 每个格子对象太多,退化为线性查询
3.3 DistPoint3Triangle3 - 精确距离查询
功能描述
计算点到三角形的最短距离及最近点位置。
核心方法:
var query = new DistPoint3Triangle3(point, triangle);
double distance = query.Get(); // 最短距离
Vector3d closestPoint = query.TriangleClosest; // 三角形上最近点
int closestType = query.TriangleClosestType; // 最近点类型(顶点/边/面)
相关类:
DistPoint3Circle3 // 点到圆的距离
DistPoint3Cylinder3 // 点到圆柱的距离(带符号)
DistLine3Triangle3 // 线段到三角形的距离
DistSegment3Triangle3 // 线段到三角形的距离
DistTriangle3Triangle3 // 三角形到三角形的距离
应用场景
场景 1:精确碰撞容差
当前问题:
// BoundingBoxGeometryUtils.cs - CalculateDistance()
// 只计算包围盒中心的距离,不精确
double distance = Vector3.Distance(bbox1.Center, bbox2.Center);
使用精确距离:
// 计算物体表面到障碍物表面的真实距离
foreach (var triangle1 in animatedObjectMesh.Triangles)
{
foreach (var triangle2 in obstacleMesh.Triangles)
{
var query = new DistTriangle3Triangle3(triangle1, triangle2);
double distance = query.Get();
if (distance < collisionThreshold)
{
// 记录碰撞,包含精确距离和接触点
collisions.Add(new CollisionInfo
{
Distance = distance,
ContactPoint1 = query.Triangle1Closest,
ContactPoint2 = query.Triangle2Closest
});
}
}
}
场景 2:碰撞报告增强
在碰撞报告中显示:
- 精确的间隙距离(而非包围盒距离)
- 最近接触点的 3D 坐标
- 可视化最短距离向量
3.4 IntrRay3Triangle3 - 射线相交查询
功能描述
计算射线/线段与三角形的相交。
核心方法:
// 射线-三角形相交
var query = new IntrRay3Triangle3(ray, triangle);
bool intersects = query.Find(); // 是否相交
double rayParameter = query.RayParameter; // 射线参数 t (交点 = ray.Origin + t * ray.Direction)
Vector3d intersectionPoint = ray.PointAt(rayParameter);
// 线段-三角形相交
var segmentQuery = new IntrSegment3Triangle3(segment, triangle);
bool intersects = segmentQuery.Find();
相关类:
IntrLine2Line2 // 2D 直线相交
IntrSegment2Segment2 // 2D 线段相交
IntrTriangle3Triangle3 // 3D 三角形相交
IntrRay3Box3 // 射线-AABB 相交
IntrRay3AxisAlignedBox3 // 射线-轴对齐盒相交
应用场景
场景 1:路径可达性验证
检查两点间的直线路径是否被障碍物阻挡:
/// <summary>
/// 检查直线路径是否可达(无障碍物阻挡)
/// </summary>
public bool IsPathClear(Point3D start, Point3D end, IEnumerable<DMesh3> obstacles)
{
Vector3d direction = (end - start).Normalized;
double distance = Vector3d.Distance(start, end);
var ray = new Ray3d(start, direction);
foreach (var obstacleMesh in obstacles)
{
foreach (var triangleId in obstacleMesh.TriangleIndices())
{
var triangle = GetTriangle(obstacleMesh, triangleId);
var query = new IntrRay3Triangle3(ray, triangle);
if (query.Find() && query.RayParameter < distance)
{
// 射线在到达终点前与障碍物相交
return false;
}
}
}
return true; // 路径畅通
}
场景 2:视线检测
判断两个物体之间是否有遮挡:
// 检查从起重机到目标物体的视线是否被遮挡
bool hasLineOfSight = IsPathClear(crane.Position, targetObject.Position, obstacles);
场景 3:改进 A 路径规划*
在 A* 算法中增加射线检测,避免规划出会穿模的路径:
// 生成路径后,后处理优化
var optimizedPath = new List<Point3D>();
optimizedPath.Add(path[0]);
for (int i = 0; i < path.Count - 1; i++)
{
// 尝试直接连接当前点和后续点
for (int j = path.Count - 1; j > i + 1; j--)
{
if (IsPathClear(path[i], path[j], obstacles))
{
optimizedPath.Add(path[j]);
i = j - 1;
break;
}
}
}
4. 中等价值模块(可选)
4.1 Polygon2d - 2D 多边形操作
功能:
- 点在多边形内测试(Contains)
- 多边形简化(Simplify)
- 多边形裁剪
- 多边形布尔运算
应用场景:
- 楼层区域判断(路径点是否在楼层边界内)
- 2D 路径规划(作为 3D 规划的补充)
4.2 ConvexHull2 - 2D 凸包
功能:
- 计算点集的 2D 凸包
应用场景:
- 楼层边界自动识别
- 路径覆盖区域计算
4.3 MeshPlaneCut - 网格平面切割
功能:
- 用平面切割三角网格
- 返回切割边界(EdgeLoop)
应用场景:
- 楼层切片(按高度切分建筑模型)
- 断面分析(生成路径断面视图)
5. 集成架构设计
5.1 整体架构
┌─────────────────────────────────────────────────────────────┐
│ Navisworks API │
│ (ModelItem, BoundingBox3D, Geometry) │
└────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ NavisworksGeometryAdapter (新) │
│ - ModelItem → DMesh3 │
│ - Point3D ↔ Vector3d │
│ - BoundingBox3D ↔ AxisAlignedBox3d │
└────────────────────────┬────────────────────────────────────┘
│
┌────────────┴────────────┐
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ SpatialIndexCache │ │ CollisionQueryHelper│
│ (新) │ │ (新) │
│ │ │ │
│ - SceneAABBTree │ │ - DistanceQuery │
│ - ObstacleHashGrid │ │ - IntersectionQuery │
│ - 缓存管理 │ │ - 精确碰撞检测 │
└──────────┬──────────┘ └──────────┬──────────┘
│ │
│ ┌─────────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ ClashDetectiveIntegration (改进) │
│ - GetPotentialColliders() → 使用 SpatialIndexCache │
│ - DetectCollisions() → 使用 CollisionQueryHelper │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ PathAnimationManager (无需修改) │
└─────────────────────────────────────────────────────────────┘
5.2 核心类设计
5.2.1 NavisworksGeometryAdapter - 适配层
/// <summary>
/// Navisworks API 与 geometry3Sharp 之间的转换适配器
/// </summary>
public static class NavisworksGeometryAdapter
{
#region 坐标转换
/// <summary>
/// Navisworks Point3D → geometry3Sharp Vector3d
/// </summary>
public static Vector3d ToVector3d(this Point3D point)
{
return new Vector3d(point.X, point.Y, point.Z);
}
/// <summary>
/// geometry3Sharp Vector3d → Navisworks Point3D
/// </summary>
public static Point3D ToPoint3D(this Vector3d vector)
{
return new Point3D(vector.x, vector.y, vector.z);
}
/// <summary>
/// Navisworks BoundingBox3D → geometry3Sharp AxisAlignedBox3d
/// </summary>
public static AxisAlignedBox3d ToAxisAlignedBox3d(this BoundingBox3D bbox)
{
return new AxisAlignedBox3d(
bbox.Min.ToVector3d(),
bbox.Max.ToVector3d()
);
}
#endregion
#region 几何提取
/// <summary>
/// 从 ModelItem 提取三角网格(简化版:使用包围盒)
/// </summary>
public static DMesh3 ExtractMeshSimple(ModelItem item)
{
var bbox = item.BoundingBox();
var mesh = new DMesh3();
// 将包围盒转为 8 个顶点 + 12 个三角形
// (简化实现,适用于快速验证)
AddBoxToMesh(mesh, bbox.ToAxisAlignedBox3d());
return mesh;
}
/// <summary>
/// 从 ModelItem 提取精确三角网格(完整版,Phase 2 实现)
/// </summary>
public static DMesh3 ExtractMeshAccurate(ModelItem item)
{
// TODO: 使用 GeometryExtractor 获取实际三角形
// 需要遍历 Navisworks Geometry API
throw new NotImplementedException("Phase 2");
}
#endregion
}
5.2.2 SpatialIndexCache - 空间索引缓存
/// <summary>
/// 场景空间索引缓存管理器
/// 在动画开始前预构建空间索引,动画过程中复用
/// </summary>
public class SpatialIndexCache
{
private static SpatialIndexCache _instance;
public static SpatialIndexCache Instance => _instance ??= new SpatialIndexCache();
// 场景 AABB 树(用于精确查询)
private DMeshAABBTree3 _sceneAABBTree;
// 障碍物空间哈希网格(用于快速范围查询)
private PointHashGrid3d<ModelItem> _obstacleHashGrid;
// 缓存版本(检测场景变化)
private int _cacheVersion = 0;
#region 构建方法
/// <summary>
/// 构建场景的空间索引
/// </summary>
public void BuildSpatialIndex(
IEnumerable<ModelItem> obstacles,
double hashGridCellSize)
{
LogManager.Info("[空间索引] 开始构建...");
var sw = Stopwatch.StartNew();
// 1. 构建 AABB 树
var sceneMesh = CombineMeshes(obstacles);
_sceneAABBTree = new DMeshAABBTree3(sceneMesh, autoBuild: true);
LogManager.Info($"[空间索引] AABB 树构建完成,节点数: {_sceneAABBTree.MaxLeafSize}");
// 2. 构建空间哈希网格
_obstacleHashGrid = new PointHashGrid3d<ModelItem>(hashGridCellSize, null);
foreach (var obstacle in obstacles)
{
var center = obstacle.BoundingBox().Center.ToVector3d();
_obstacleHashGrid.InsertPoint(obstacle, center);
}
LogManager.Info($"[空间索引] 哈希网格构建完成,格子大小: {hashGridCellSize}m");
_cacheVersion++;
sw.Stop();
LogManager.Info($"[空间索引] 构建完成,耗时: {sw.ElapsedMilliseconds}ms");
}
#endregion
#region 查询方法
/// <summary>
/// 快速范围查询(使用哈希网格)
/// </summary>
public List<ModelItem> FindNearbyObstacles(Point3D center, double radius)
{
if (_obstacleHashGrid == null)
throw new InvalidOperationException("空间索引未初始化");
var centerVec = center.ToVector3d();
var nearby = new List<ModelItem>();
// 哈希网格范围查询
// 注意:PointHashGrid3d 没有直接的 FindNearestInRadius 方法
// 需要手动实现或使用 FindPointsInBox
var searchBox = new AxisAlignedBox3d(centerVec, radius);
// 遍历搜索框内的所有格子(简化实现)
// 实际应该调用哈希网格的范围查询方法
// 这里需要根据 geometry3Sharp 的实际 API 调整
return nearby;
}
/// <summary>
/// 精确相交查询(使用 AABB 树)
/// </summary>
public bool TestIntersection(DMesh3 objectMesh)
{
if (_sceneAABBTree == null)
throw new InvalidOperationException("空间索引未初始化");
var objectTree = new DMeshAABBTree3(objectMesh, autoBuild: true);
return _sceneAABBTree.TestIntersection(objectTree);
}
#endregion
#region 辅助方法
private DMesh3 CombineMeshes(IEnumerable<ModelItem> items)
{
var combinedMesh = new DMesh3();
foreach (var item in items)
{
var itemMesh = NavisworksGeometryAdapter.ExtractMeshSimple(item);
var editor = new MeshEditor(combinedMesh);
editor.AppendMesh(itemMesh);
}
return combinedMesh;
}
#endregion
}
5.2.3 CollisionQueryHelper - 碰撞查询助手
/// <summary>
/// 精确碰撞查询辅助类
/// </summary>
public static class CollisionQueryHelper
{
/// <summary>
/// 计算物体到障碍物的最短距离
/// </summary>
public static double CalculateMinDistance(
ModelItem movingObject,
ModelItem obstacle)
{
var mesh1 = NavisworksGeometryAdapter.ExtractMeshSimple(movingObject);
var mesh2 = NavisworksGeometryAdapter.ExtractMeshSimple(obstacle);
double minDistance = double.MaxValue;
// 遍历所有三角形对,找到最短距离
foreach (var tri1Id in mesh1.TriangleIndices())
{
var tri1 = GetTriangle(mesh1, tri1Id);
foreach (var tri2Id in mesh2.TriangleIndices())
{
var tri2 = GetTriangle(mesh2, tri2Id);
var query = new DistTriangle3Triangle3(tri1, tri2);
double distance = query.Get();
if (distance < minDistance)
{
minDistance = distance;
}
}
}
return minDistance;
}
/// <summary>
/// 检查射线路径是否畅通
/// </summary>
public static bool IsPathClear(
Point3D start,
Point3D end,
DMeshAABBTree3 sceneTree)
{
var direction = (end.ToVector3d() - start.ToVector3d()).Normalized;
var distance = Vector3d.Distance(start.ToVector3d(), end.ToVector3d());
var ray = new Ray3d(start.ToVector3d(), direction);
// 使用 AABB 树快速查询射线相交
int hitTriangle = sceneTree.FindNearestHitTriangle(ray);
if (hitTriangle == DMesh3.InvalidID)
return true; // 无相交
// 检查相交点是否在起终点之间
// TODO: 需要获取相交点位置并比较距离
return false;
}
private static Triangle3d GetTriangle(DMesh3 mesh, int triangleId)
{
var tri = mesh.GetTriangle(triangleId);
var v0 = mesh.GetVertex(tri.a);
var v1 = mesh.GetVertex(tri.b);
var v2 = mesh.GetVertex(tri.c);
return new Triangle3d(v0, v1, v2);
}
}
5.3 集成到现有系统
修改 ClashDetectiveIntegration.cs
// 在 GetPotentialColliders() 中使用空间索引
private List<ModelItem> GetPotentialColliders()
{
// 1. 计算路径包围盒
var pathBounds = CalculatePathBounds();
var pathCenter = GetBoundingBoxCenter(pathBounds);
var detectionRadius = GetBoundingBoxDiagonal(pathBounds) / 2;
// 2. 使用空间哈希网格快速查询
var potentialColliders = SpatialIndexCache.Instance.FindNearbyObstacles(
pathCenter,
detectionRadius
);
LogManager.Info($"空间索引查询结果: {potentialColliders.Count} 个潜在碰撞对象");
return potentialColliders;
}
6. 实施方案
6.1 分阶段实施
Phase 1: PointHashGrid3d 集成(2-3 天,立即可用)
目标:使用空间哈希网格优化动画碰撞检测。
任务:
- 创建
NavisworksGeometryAdapter类(坐标转换) - 创建
SpatialIndexCache类(仅哈希网格部分) - 修改
ClashDetectiveIntegration.GetPotentialColliders()使用哈希网格 - 修改动画碰撞检测使用哈希网格查询
- 性能测试和日志记录
验收标准:
- ✅ 动画碰撞检测速度提升 5-10 倍
- ✅ 日志显示每帧实际检测的对象数量减少
- ✅ 功能正确性不变(碰撞结果与原方案一致)
Phase 2: DMeshAABBTree3 优化(1 周)
目标:构建场景 AABB 树,优化范围查询和相交检测。
任务:
- 实现
NavisworksGeometryAdapter.ExtractMeshSimple()(使用包围盒) - 在
SpatialIndexCache中添加 AABB 树构建 - 使用 AABB 树优化
FindNearestTriangles()查询 - 实现精确相交检测(替代简单包围盒测试)
- 性能对比测试
验收标准:
- ✅ AABB 树构建时间 < 5 秒(中等场景)
- ✅ 范围查询速度提升 10-30 倍
- ✅ 支持精确三角形级别的碰撞检测
Phase 3: 精确距离和相交查询(可选,3-5 天)
目标:使用精确几何查询提升碰撞报告质量。
任务:
- 创建
CollisionQueryHelper类 - 实现精确距离计算(DistTriangle3Triangle3)
- 实现路径可达性验证(IntrRay3Triangle3)
- 在碰撞报告中显示精确距离和接触点
- (可选)实现
ExtractMeshAccurate()精确几何提取
验收标准:
- ✅ 碰撞报告显示精确距离(非包围盒距离)
- ✅ 支持路径可达性验证功能
- ✅ 性能可接受(精确查询耗时 < 2x 简化查询)
6.2 时间与资源估算
| 阶段 | 任务 | 工作量 | 依赖 |
|---|---|---|---|
| Phase 1 | PointHashGrid3d 集成 | 2-3 天 | geometry3Sharp |
| Phase 2 | DMeshAABBTree3 优化 | 5-7 天 | Phase 1 |
| Phase 3 | 精确查询(可选) | 3-5 天 | Phase 2 |
| 总计 | 10-15 天 |
7. 技术挑战与缓解
7.1 Navisworks API 限制
挑战:Navisworks 的 ModelItem 不直接暴露三角网格数据。
缓解措施:
- ✅ Phase 1:使用包围盒代替精确网格(快速验证)
- ✅ Phase 2:研究
GeometryExtractor提取实际几何 - ✅ Phase 3:实现 Navisworks Geometry API → DMesh3 转换器
7.2 坐标系转换
挑战:Navisworks API 和 geometry3Sharp 使用不同的类型系统。
缓解措施:
- ✅ 创建
NavisworksGeometryAdapter适配层 - ✅ 统一使用模型单位(避免米制/英制混淆)
- ✅ 单元测试验证转换正确性
7.3 性能权衡
挑战:空间索引构建有初始开销。
缓解措施:
- ✅ 在动画开始前预构建(用户点击"生成动画"时)
- ✅ 缓存索引(场景不变时复用)
- ✅ 显示进度条(让用户知道正在构建)
8. 性能预期
8.1 性能对比(预估)
基于类似规模的空间索引系统经验:
| 操作 | 当前实现 | Phase 1 (哈希) | Phase 2 (AABB树) |
|---|---|---|---|
| 范围查询 | O(n) = 290次 | O(1) ≈ 10次 | O(log n) ≈ 8次 |
| 碰撞检测 | 32,400次/动画 | 3,000次/动画 | 2,400次/动画 |
| 构建开销 | 0 秒 | 0.1 秒 | 2-5 秒 |
| 内存占用 | 0 MB | +10 MB | +50 MB |
场景假设:
- 对象总数:290 个
- 动画帧数:300 帧
- 潜在碰撞对象:108 个(经过预过滤)
8.2 预期加速比
Phase 1 完成后:
- 每帧碰撞检测:108 对象 → 10 对象
- 加速比:约 10 倍
Phase 2 完成后:
- 范围查询:O(n) → O(log n)
- 加速比:约 30-50 倍(组合效果)
9. 与体素网格方案的关系
9.1 互补关系说明
| 方案 | 主要用途 | 数据结构 | 查询类型 |
|---|---|---|---|
| 体素网格 | 路径规划 | 3D 网格 + SDF | 可通行性、路径搜索 |
| 空间索引 | 碰撞检测 | AABB树、哈希网格 | 范围查询、相交测试 |
9.2 共用基础设施
两个方案共享 geometry3Sharp 的基础组件:
- 数学类型(Vector3d, AxisAlignedBox3d)
- 坐标转换适配器(NavisworksGeometryAdapter)
- 几何提取工具
9.3 集成策略
geometry3Sharp 基础库
├── 体素网格模块 (用于路径规划)
│ ├── MeshSignedDistanceGrid
│ ├── Bitmap3 / DSparseGrid3
│ └── VoxelGrid (自定义)
│
└── 空间索引模块 (用于碰撞检测)
├── DMeshAABBTree3
├── PointHashGrid3d
└── Distance/Intersection 查询
10. 不适用的模块
以下 geometry3Sharp 模块不适用于本项目:
10.1 网格编辑类
- Remesher, Reducer, MeshEditor
- 原因:Navisworks 是只读查看器,不支持修改网格几何
10.2 曲线生成类
- NURBSCurve2, BezierCurve
- 原因:项目使用折线路径,不需要复杂曲线拟合
10.3 网格修复类
- MeshAutoRepair, RemoveDuplicateTriangles
- 原因:Navisworks 模型已优化,无法运行时修改
10.4 布尔运算类
- MeshBoolean
- 原因:文档明确说"不是健壮的布尔运算",且 Navisworks API 不支持
11. 实施建议
11.1 推荐的实施优先级
立即实施(高优先级):
- ✅ PointHashGrid3d → 快速见效,大幅提升动画碰撞检测性能
短期实施(中优先级): 2. ✅ DMeshAABBTree3 → 进一步优化,支持精确相交检测
长期考虑(低优先级): 3. ⚠️ 精确距离查询 → 功能增强,非关键路径 4. ⚠️ 射线相交查询 → 路径验证功能,可选
11.2 风险提示
不要全盘集成 geometry3Sharp,应该:
- ✅ 只提取需要的类(避免依赖膨胀)
- ✅ 创建适配层(隔离外部依赖)
- ✅ 渐进式验证(每个 Phase 独立验收)
12. 参考资料
12.1 geometry3Sharp 资源
- GitHub(原版):https://github.com/gradientspace/geometry3Sharp
- GitHub(fork):https://github.com/NewWheelTech/geometry4Sharp
- NuGet:geometry4Sharp 1.0.0
- 原作者:Ryan Schmidt (@rms80)
- 算法来源:WildMagic5/GTEngine (David Eberly)
12.2 理论基础
-
空间哈希网格:
- "Spatial Hashing for 3D Grids" - Teschner et al., 2003
- "Optimized Spatial Hashing for Collision Detection of Deformable Objects"
-
AABB 树:
- "OBBTree: A Hierarchical Structure for Rapid Interference Detection" (Gottschalk et al., 1996)
- "Fast Collision Detection Using AABB Trees" - Real-Time Rendering
-
距离查询:
- "Distance Between Point and Triangle in 3D" - David Eberly, Geometric Tools
- "Fast Distance Queries for Triangles, Lines and Points using SSE"
12.3 相关文档
- 《体素网格路径规划方案.md》- 路径规划部分
- 《PATHFINDING_DESIGN.md》- A* 算法设计
- 《寻路算法的对比.md》- 算法选型依据
13. 总结
13.1 核心价值
- ✅ 显著的性能提升:碰撞检测加速 10-50 倍
- ✅ 商业友好许可证:Boost License,无需开源
- ✅ 成熟稳定的代码:源自经典几何库 WildMagic5
- ✅ 渐进式集成:分阶段实施,风险可控
- ✅ 互补体素方案:两者协同,各司其职
13.2 建议行动
立即行动:
- 安装 geometry4Sharp NuGet 包
- 实施 Phase 1(PointHashGrid3d)
- 测试性能提升
后续行动:
- Phase 1 验证后,评估是否继续 Phase 2
- 与体素网格方案协同推进
13.3 成功标准
- ✅ 动画碰撞检测速度提升 10 倍以上
- ✅ 构建开销可接受(< 5 秒)
- ✅ 内存占用增加 < 100 MB
- ✅ 功能正确性保持不变
- ✅ 代码可维护性良好
文档版本: v1.0 创建日期: 2025-10-14 最后更新: 2025-10-14 作者: NavisworksTransport 开发团队 相关文档: 《体素网格路径规划方案.md》