9-SOFA_Collision Model(碰撞模型)与 Collision Pipeline(碰撞流水线)

发布时间:2026/7/23 21:45:43

9-SOFA_Collision Model(碰撞模型)与 Collision Pipeline(碰撞流水线) 11-collision-pipeline.scn?xml version1.0? !-- Step 1: add the global collision pipeline -- Node nameroot dt0.01 gravity0 0 0 Node nameplugins RequiredPlugin pluginNameSofa.Component.AnimationLoop/ RequiredPlugin pluginNameSofa.Component.Collision.Detection.Algorithm/ RequiredPlugin pluginNameSofa.Component.Collision.Detection.Intersection/ RequiredPlugin pluginNameSofa.Component.Collision.Geometry/ RequiredPlugin pluginNameSofa.Component.Collision.Response.Contact/ RequiredPlugin pluginNameSofa.Component.Constraint.Projective/ RequiredPlugin pluginNameSofa.Component.IO.Mesh/ RequiredPlugin pluginNameSofa.Component.LinearSolver.Iterative/ RequiredPlugin pluginNameSofa.Component.Mapping.Linear/ RequiredPlugin pluginNameSofa.Component.Mass/ RequiredPlugin pluginNameSofa.Component.ODESolver.Backward/ RequiredPlugin pluginNameSofa.Component.SolidMechanics.FEM.Elastic/ RequiredPlugin pluginNameSofa.Component.StateContainer/ RequiredPlugin pluginNameSofa.Component.Topology.Container.Constant/ RequiredPlugin pluginNameSofa.Component.Topology.Container.Dynamic/ RequiredPlugin pluginNameSofa.Component.Visual/ RequiredPlugin pluginNameSofa.GL.Component.Rendering3D/ /Node DefaultAnimationLoop computeBoundingBoxfalse/ VisualStyle displayFlagsshowVisualModels showBehaviorModels showCollisionModels/ !-- Global collision pipeline -- CollisionPipeline/ BruteForceBroadPhase/ BVHNarrowPhase/ MinProximityIntersection nameProximity alarmDistance0.5 contactDistance0.25/ CollisionResponse nameResponse responsePenalityContactForceField/ MeshGmshLoader namemeshLoaderCoarse filenamemesh/liver.msh/ MeshOBJLoader namemeshLoaderFine filenamemesh/liver-smooth.obj/ Node nameLiver EulerImplicitSolver/ CGLinearSolver iterations200 tolerance1e-09 threshold1e-09/ TetrahedronSetTopologyContainer nametopo src../meshLoaderCoarse/ TetrahedronSetGeometryAlgorithms templateVec3d nameGeomAlgo/ MechanicalObject templateVec3d nameMechanicalModel showObject1 showObjectScale3/ TetrahedronFEMForceField nameFEM youngModulus1000 poissonRatio0.4 methodlarge/ MeshMatrixMass massDensity1 topologytopo/ !-- 老师视频旧名称是 FixedConstraint -- FixedProjectiveConstraint indices1 3 50/ Node nameVisual OglModel nameVisualModel src../../meshLoaderFine/ BarycentricMapping nameVisualMapping input../MechanicalModel outputVisualModel/ /Node /Node /Node一个完整物体可以具有三种表示Liver│├── Mechanical Model│ 负责力学计算和变形│├── Visual Model│ 负责显示外观│└── Collision Model负责碰撞检测力学模型保存真正参与求解的状态视觉模型可以使用光滑表面碰撞模型由适合检测的几何图元组成。三个表示不一定使用同一套网格但需要通过 Mapping 同步。1.Collision Pipeline 的整体流程SOFA 的碰撞流水线负责调度碰撞重置、碰撞检测和碰撞响应这一节主要按“粗检测—窄检测—响应”的直观顺序讲。碰撞过程分成Broad Phase宽阶段、粗检测↓Narrow Phase窄阶段、精细定位↓Intersection Response确认接触并产生响应也可以概括成先找可能碰撞的物体↓再找可能接触的局部区域↓检查具体图元是否接触↓创建接触响应2.CollisionPipelineCollisionPipeline/CollisionPipeline 的作用是组织碰撞系统中各个阶段按照正确顺序执行。可以类比成AnimationLoopDefaultAnimationLoop仿真总负责人↓ 发出“开始处理碰撞”的命令CollisionPipeline碰撞子流程负责人↓调用粗检测、窄检测、接触响应也就是AnimationLoop 管整个时间步CollisionPipeline 管时间步里的碰撞部分3.BruteForceBroadPhase第一种算法组件BruteForceBroadPhase/它先比较不同碰撞物体的整体包围盒物体A包围盒 物体B包围盒┌────────┐ ┌────────┐│ A │ │ B │└────────┘ └────────┘如果包围盒相距很远直接排除不再做更细的检查如果包围盒相交或非常接近把这一对物体交给 Narrow Phase。4.BVHNarrowPhase第二个组件BVHNarrowPhase/BVH是Bounding Volume Hierarchy 包围体层次结构假设整个 liver 外面有一个大盒子┌──────────────────┐│ Liver │└──────────────────┘仅凭这个盒子只能知道可能发生碰撞不能知道到底是 liver 的哪个区域于是 BVH 会继续分层它通过从大盒子逐步进入小盒子快速定位接触大概发生在哪个局部区域。官方说明BVHNarrowPhase会遍历碰撞图元的层次结构继续排除不可能相交的图元对最后把剩下的候选对交给相交检测方法。4.MinProximityIntersection第三个检测组件MinProximityIntersection nameProximity alarmDistance0.5 contactDistance0.25/BVH 负责精确定位可能接触的位置而MinProximityIntersection最终检查primitive against primitive图元对图元例如球体 against 三角形点 against 三角形线段 against 线段4.1.alarmDistancealarmDistance0.5当两组碰撞图元的距离小于0.5时认为它们已经足够接近 需要继续进行接触检查。它相当于警戒距离。4.2.contactDistancecontactDistance0.25距离小于0.25时真正创建一个接触 DetectionOutput所以关系是距离 0.5忽略0.25 距离 0.5进入警戒和精细检测距离 0.25创建接触5.CollisionResponse发现两个物体接触了下一步怎么处理CollisionResponse nameResponse responsePenalityContactForceField/这里讲的是penalty method惩罚法SOFA 组件的历史拼写是 PenalityContactForceField该组件的作用就是用排斥弹簧处理接触。两种碰撞响应Penalty method 惩罚法、Lagrange multiplier constraint 拉格朗日乘子约束法这个教程现在使用DefaultAnimationLoop因此先集中讲惩罚法约束型响应需要另一套约束求解流程。惩罚法怎样产生力如果两个物体发生穿透物体A ─────┐│ 穿透距离 d物体B ─────┘惩罚法根据穿透程度和接触刚度产生排斥力其中接触违反或穿透的程度接触刚度把两个物体推开的接触力。惩罚法通过力来减少穿透但不能严格保证时间步结束时穿透一定等于零。接触刚度太小时物体可能明显穿进去接触刚度太大时又可能导致数值问题。因此它是一种近似处理而不是严格的几何不可穿透约束。惩罚法是DefaultAnimationLoop下当前使用的响应方式.6.碰撞算法可以替换Broad Phase——BruteForceBroadPhaseNarrow Phase——BVHNarrowPhase、DirectSAPNarrowPhaseIntersection method——MinProximityIntersection、LocalMinDistance这些组件可以根据项目需要替换SOFA 用户文档中可以查到每种算法的细节。我们当前使用的是这一组BruteForceBroadPhase/ BVHNarrowPhase/ MinProximityIntersection .../最终流程是碰撞对象对↓包围盒筛选↓BVH局部筛选↓具体图元成对检查↓创建接触7.全局流水线代码放在哪里需要在DefaultAnimationLoop/后面增加五行代码CollisionPipeline/ BruteForceBroadPhase/ BVHNarrowPhase/ MinProximityIntersection nameProximity alarmDistance0.5 contactDistance0.25/ CollisionResponse nameResponse responsePenalityContactForceField/这些组件放在root中因为它们管理的是整个场景中的碰撞流程不是只属于某一个 liver。所以要区分root 下的 CollisionPipeline → 整个场景共用的碰撞算法每个物体中的 Collision 子节点 → 该物体自己的碰撞表示11-collision-model.scn?xml version1.0? !-- Step 2: add a collision representation to Liver -- Node nameroot dt0.01 gravity0 0 0 Node nameplugins RequiredPlugin pluginNameSofa.Component.AnimationLoop/ RequiredPlugin pluginNameSofa.Component.Collision.Detection.Algorithm/ RequiredPlugin pluginNameSofa.Component.Collision.Detection.Intersection/ RequiredPlugin pluginNameSofa.Component.Collision.Geometry/ RequiredPlugin pluginNameSofa.Component.Collision.Response.Contact/ RequiredPlugin pluginNameSofa.Component.Constraint.Projective/ RequiredPlugin pluginNameSofa.Component.IO.Mesh/ RequiredPlugin pluginNameSofa.Component.LinearSolver.Iterative/ RequiredPlugin pluginNameSofa.Component.Mapping.Linear/ RequiredPlugin pluginNameSofa.Component.Mass/ RequiredPlugin pluginNameSofa.Component.ODESolver.Backward/ RequiredPlugin pluginNameSofa.Component.SolidMechanics.FEM.Elastic/ RequiredPlugin pluginNameSofa.Component.StateContainer/ RequiredPlugin pluginNameSofa.Component.Topology.Container.Constant/ RequiredPlugin pluginNameSofa.Component.Topology.Container.Dynamic/ RequiredPlugin pluginNameSofa.Component.Visual/ RequiredPlugin pluginNameSofa.GL.Component.Rendering3D/ /Node DefaultAnimationLoop computeBoundingBoxfalse/ VisualStyle displayFlagsshowVisualModels showBehaviorModels showCollisionModels/ !-- Global collision pipeline -- CollisionPipeline/ BruteForceBroadPhase/ BVHNarrowPhase/ MinProximityIntersection nameProximity alarmDistance0.5 contactDistance0.25/ CollisionResponse nameResponse responsePenalityContactForceField/ !-- Mechanical volumetric mesh -- MeshGmshLoader namemeshLoaderCoarse filenamemesh/liver.msh/ !-- Fine surface mesh, reused by visual and collision representations -- MeshOBJLoader namemeshLoaderFine filenamemesh/liver-smooth.obj/ Node nameLiver EulerImplicitSolver/ CGLinearSolver iterations200 tolerance1e-09 threshold1e-09/ TetrahedronSetTopologyContainer nametopo src../meshLoaderCoarse/ TetrahedronSetGeometryAlgorithms templateVec3d nameGeomAlgo/ MechanicalObject templateVec3d nameMechanicalModel showObject1 showObjectScale3/ TetrahedronFEMForceField nameFEM youngModulus1000 poissonRatio0.4 methodlarge/ MeshMatrixMass massDensity1 topologytopo/ FixedProjectiveConstraint indices1 3 50/ !-- Visual representation -- Node nameVisual OglModel nameVisualModel src../../meshLoaderFine/ BarycentricMapping nameVisualMapping input../MechanicalModel outputVisualModel/ /Node !-- Collision representation -- Node nameCollision MeshTopology nameCollisionTopology src../../meshLoaderFine/ MechanicalObject templateVec3d nameStoringForces/ TriangleCollisionModel nameCollisionModel contactStiffness3/ BarycentricMapping nameCollisionMapping input../MechanicalModel outputStoringForces/ /Node /Node /Node8.给 Liver 增加 Collision 子节点前面为了渲染我们建立过Node nameVisual ... /Node现在按照同样思路再建立Node nameCollision ... /Node场景结构变成Liver│├── MechanicalModel│├── Visual│ └── VisualModel│└── Collision└── CollisionModel这次创建子节点不是为了 rendering而是为了 collision detection。9.Collision 子节点里的四个组件Node nameCollision MeshTopology src../../meshLoaderFine/ MechanicalObject nameStoringForces/ TriangleCollisionModel nameCollisionModel contactStiffness3/ BarycentricMapping nameCollisionMapping input../ outputStoringForces/ /Node9.1.MeshTopologyMeshTopology src../../meshLoaderFine/它定义碰撞表面的点、边、三角形连接关系。这里使用 meshLoaderFine也就是前面红色、较平滑的表面网格。../../是层级寻址向上回溯两级父节点再找到meshLoaderFine这个节点。因此当前例子是Mechanical Model——使用 liver.msh 的四面体体网格Visual Model——使用 liver-smooth.objCollision Model——也使用 liver-smooth.obj并没有要求碰撞网格必须和视觉网格相同只是这个例子选择复用同一个细表面网格。9.2.MechanicalObject nameStoringForcesMechanicalObject nameStoringForces/它保存 Collision 子节点的状态。SOFA 规则 每个力学 / 碰撞计算都需要一个MechanicalObject存顶点坐标、速度、受力。Visual 节点里没有额外的MechanicalObject为什么 Collision 节点里却需要一个我们将在11小节进行解释。9.3.TriangleCollisionModelSOFA 内置碰撞算法基于三角形面片碰撞检测。TriangleCollisionModel nameCollisionModel contactStiffness3/它表示把 MeshTopology 中的三角形 作为碰撞检测图元。读取上面MeshTopology的肝脏三角面场景里其他物体碰到肝脏时计算穿透、挤压contactStiffness3接触刚度数值越大碰撞反弹越硬。 算出的碰撞力会作用在StoringForces这套质点上。在12小节会详细解释。SOFA 还支持 PointCollisionModel、LineCollisionModel、SphereCollisionModel、CubeCollisionModel、TriangleCollisionModel。但我们当前只选择了三角形。官方文档确认CollisionModel 就是由某类碰撞图元组成的列表而contactStiffness主要用于惩罚法接触响应。9.4.BarycentricMapping功能 用重心坐标插值把主肝脏模型每一步的形变位置、位移实时同步复制到碰撞副本StoringForces。BarycentricMapping nameCollisionMapping input../ outputStoringForces/input../表示回到上一级Liver节点找到上层的力学状态。它等价于更明确地写input../MechanicalModel输出outputStoringForces表示映射到 Collision 子节点的MechanicalObject。9.5.完整数据流关系是上层主节点Liver/MechanicalModel肝脏真实形变质点↓ 数据传递靠 BarycentricMapping当前节点Collision/StoringForces碰撞专用副本质点↓ 碰撞力作用在这套质点上TriangleCollisionModel三角碰撞检测器完整数据流分两步正向映射形变同步Liver 主模型形变 → BarycentricMapping 插值 → StoringForces 同步位置 保证碰撞网格和肝脏外形完全一致。反向受力传递碰撞反馈TriangleCollisionModel 算出碰撞接触力 → 先存到 StoringForces 再通过映射反向传回主 Liver/MechanicalModel让肝脏感受到碰撞挤压、产生形变反馈。碰撞模型通常需要通过 Mapping 和父节点的力学表示连接。10.MeshTopology 与 SetTopologyContainer 的区别MeshTopology 和前面学过的TetrahedronSetTopologyContainer/一样都保存拓扑关系。几何坐标每个点(x,y,z)在哪是位置会动拓扑Topology点和点怎么连、拼成什么面 / 体是连接关系。这里强调一个主要区别TetrahedronSetTopologyContainer 属于可更新的拓扑容器配合相应 Modifier可以支持拓扑变化例如切割、撕裂、增加或删除拓扑元素。MeshTopology 在这里被作为静态拓扑使用加载完成后拓扑保持不变。也就是说节点位置可以跟随 Mapping 移动但是点、边、三角形的连接关系不改变不用于切割或者撕裂。所以选择原则是拓扑永远不改变 → 可以使用 MeshTopology需要切割、撕裂或动态更新拓扑 → 使用动态 SetTopologyContainer 和 Modifier它和其他拓扑容器一样可以通过src../../meshLoaderFine从 Loader 读取所有拓扑信息。11.为什么 Collision 里需要 MechanicalObjectNode nameCollision MeshTopology src../../meshLoaderFine/ MechanicalObject nameStoringForces/ TriangleCollisionModel nameCollisionModel contactStiffness3/ BarycentricMapping nameCollisionMapping input../MechanicalModel outputStoringForces/ /NodeVisual 节点里没有额外的MechanicalObject为什么 Collision 节点里却需要一个11.1.Visual Model 是完全被动的视觉模型只负责显示Mechanical Model↓ MappingVisual Model力学模型算出新位置后Mapping 把位置传给视觉模型视觉模型不计算接触力也不需要把任何物理信息返回给力学模型。所以它基本是单向的。11.2. Collision Model 不只是接收位置还要返回力碰撞模型首先也要跟随力学模型运动Mechanical Model↓位置、速度Collision Model但发生碰撞后碰撞模型会得到接触位置、接触法向、两物体之间的距离、穿透距离、惩罚接触力。这些信息最终必须返回给力学模型Collision Model↑接触力Mechanical Model这仍然由 Mapping 完成。向下传播状态向上传播力。碰撞模型的位置由力学模型位置​ 映射得到。而碰撞力返回力学模型时通常按 Mapping 的转置关系传递其中​碰撞模型上计算出的接触力​返回到力学节点上的力Mapping 的雅可比矩阵。11.3.StoringForcesMechanicalObject nameStoringForces/仿真时间步中碰撞检测通常发生在物理求解之前。流程是先检测碰撞↓根据穿透距离创建接触力↓但此时物理方程还没求解↓暂时保存这些力↓随后力学求解器使用这些力因此需要一个 Collision 节点中的机械状态用来承接碰撞模型的位置也承接接触响应产生的力。我们把它命名为 StoringForces 意思是“存储接触力”。但要注意这只是我们给它取的名字不是特殊组件名称它本质上仍然是普通的 MechanicalObject/ 。随后BarycentricMapping input../MechanicalModel outputStoringForces/会自动把 Collision 上的力反向传播给父节点的MechanicalModel。12.contactStiffnessTriangleCollisionModel nameCollisionModel contactStiffness3/contactStiffness 用于前面讲过的 Penalty method 惩罚法两个物体发生了穿透假设球体进入肝脏表面肝脏表面 ─────────────球部分进入表面两个碰撞模型之间存在一个穿透距离惩罚法会在接触位置建立一根虚拟弹簧物体A ←────虚拟弹簧────→ 物体B排斥力近似为 其中穿透距离contactStiffness把两个物体推开的接触力。因此contactStiffness3表示惩罚弹簧的刚度系数是 3。13.碰撞处理完整步骤假设球体和一个三角形之间发生了 1 mm 的穿透。第一步Broad Phase 检查整体包围盒SOFA 为每个碰撞对象计算包围盒。包围盒通常与世界坐标的轴对齐先检查两个大盒子是否相交。如果物体真的已经发生穿透那么它们的包围盒通常也会相交因此进入下一阶段。Broad Phase 的目的只是快速判断这一对物体是否可能碰撞不是判断具体哪个三角形发生接触。第二步Narrow Phase 定位局部区域接下来BVH Narrow Phase 用逐层细分的包围盒定位可能发生接触的小区域。整个物体 ↓ 较大的局部区域 ↓ 更小的局部区域 ↓ 具体球体与三角形第三步Proximity Intersection 确认穿透距离MinProximityIntersection检查具体图元例如Sphere against Triangle 球体 对 三角形它确认球体穿入三角表面 1 mm即第四步Collision Response 创建虚拟弹簧碰撞响应根据 穿透距离 d contactStiffness k 创建惩罚弹簧。这里举的数值是contactStiffness 3 穿透距离 1 mm在国际单位制中因此如果刚度单位是 N/m那么力就是这个力暂时保存在 Collision 节点中再通过 Mapping 传回 Mechanical Model随后由力学求解器使用。第五步惩罚法不是直接移动节点这里要特别纠正了一个容易产生的误解发现穿透 1 mm 后不是直接把球往外移动 1 mm。SOFA 在这一阶段只是给节点施加排斥力随后由质量、材料刚度、时间步长、速度、求解器 共同决定节点下一步实际移动多少。所以流程不是检测到穿透1 mm → 直接修正位置1 mm而是检测到穿透1 mm → 生成接触力 → 求解物理方程 → 物体在接触力作用下运动13.1.惩罚法不能保证完全不穿透因为它只是施加力并不强制满足时间步结束后可能仍有少量穿透。contactStiffness太小排斥力不足 → 物体继续穿入contactStiffness太大排斥力突然非常大 → 仿真抖动求解困难甚至不稳定此外它还受以下因素影响两个物体相撞的速度、时间步长、物体质量、材料刚度、求解器参数。所以contactStiffness对调参非常敏感。

相关新闻