📄️ AABB 树构建与最近邻查询加速
提供 MR::AABBTree,然后调用其搜索接口来加速最近邻计算,这显著提升了点到面或点到点查找的效率(源码相关实现位于 MRMeshIntersect.h、MRMeshDistance.h 等文件中)。
📄️ 核心数据结构
Mesh、点、边、三角形
📄️ 封闭线选择三角面并分割网格
在通过封闭曲线分割网格时,一般先将用户绘制的二维闭合线投影到三维网格表面上,得到对应的三维边路径(EdgePath)。具体实现通常是对每个 2D 线段沿视线投射到网格上,求交点并连接形成网格上的闭合路径。接下来使用 MeshTopology 中的区域提取工具:例如 MR::fillContourLeft(topology, contourEdges) 可以计算出位于边路径左侧(或右侧)的所有三角面。这样就得到被闭合线包围的面集合。最后需要根据该边界将网格拆分:一种做法是在边路径处对原三角形进行分割插入新边,然后把路径一侧的面与另一侧的面区分开来。例如,可以调用 mesh.topology.deleteFaces(outsideFaces) 删除路径外的三角面,使网格只保留选中的部分,或反之;任意拓扑修改后同样要调用 mesh.invalidateCaches() 以更新缓存。总之,利用投影得到的 EdgePath 结合 fillContourLeft(和后续的删除/复制操作),即可实现基于用户封闭线的网格分割。
📄️ 孔洞填充实现细节
在 MeshTopology 中,孔洞由只有一个邻接面的边(裸边)定义。函数 MeshTopology::fillHole(mesh, edge, params),该函数根据边界顶点自动生成一组三角形来填充孔洞。其内部流程大致是:首先从给定边出发沿孔洞边界形成多边形链,接着根据填充策略将该多边形三角化。填充策略由参数 FillHoleParams 控制,例如 maxPolygonSubdivisions(默认20)限制多边形细分的最大深度,而 FillHoleMetric 可用来评价三角形质量。最终,新生成的三角形被加入到 MeshTopology 中,消除原有的孔洞开口。简单示例代码:
📄️ 顶点/边/面 ID 的连续分配与重映射
网格元素(顶点 VertId、边 EdgeId、面 FaceId)都是以连续整数索引分配的。构造网格时(如使用 MeshTopology::deleteFaces(faceSet))会从拓扑中移除对应面,系统自动更新有效面的集合;如果直接修改了拓扑(如删面或拆分边),则需调用 mesh.invalidateCaches() 来重建缓存的法线、邻接等信息。通过这些机制,保证所有 ID 始终指向有效元素,必要时进行压缩或重建,以保持索引与底层结构一致。
📄️ 点到网格投影与 AABB 加速
点到网格最近点投影的功能通常利用 AABB 树进行加速。典型流程是:首先为整个网格构建一个 MR::AABBTreePoints,原理类似:构建一个顶点的 AABB 树,再在树上进行邻近查询。整个点到面的函数链通常跨越 MRMeshIntersect、MRMeshDistance 等模块,从顶层接口到底层的 AABB 查询依次调用。
📄️ Fix Undercuts(消除倒凹)
在 MR::FixUndercuts 命名空间下提供了消除“下凹”区域的函数。主要函数是: