7-SOFA_Mapping 与多网格表示 📅 2026/7/13 21:46:18 7-mapping.scn?xml version1.0? !-- Connecting representations: the mapping -- Node nameroot dt0.01 gravity0 0 0 Node nameplugins RequiredPlugin nameSofa.Component.IO.Mesh/ !-- Needed to use components [MeshGmshLoader] -- RequiredPlugin nameSofa.Component.LinearSolver.Iterative/ !-- Needed to use components [CGLinearSolver] -- RequiredPlugin nameSofa.Component.Mass/ !-- Needed to use components [MeshMatrixMass] -- RequiredPlugin nameSofa.Component.MechanicalLoad/ !-- Needed to use components [ConstantForceField] -- RequiredPlugin nameSofa.Component.StateContainer/ !-- Needed to use components [MechanicalObject] -- RequiredPlugin nameSofa.Component.ODESolver.Backward/ !-- Needed to use components [EulerImplicitSolver] -- RequiredPlugin nameSofa.Component.SolidMechanics.FEM.Elastic/ !-- Needed to use components [TetrahedronFEMForceField] -- RequiredPlugin nameSofa.Component.Topology.Container.Dynamic/ !-- Needed to use components [TetrahedronSetGeometryAlgorithms, TetrahedronSetTopologyContainer] -- RequiredPlugin nameSofa.Component.Visual/ !-- Needed to use components [VisualStyle] -- RequiredPlugin nameSofa.GL.Component.Rendering3D/ !-- Needed to use components [OglModel] -- RequiredPlugin nameSofa.Component.Mapping.Linear/ !-- Needed to use components [IdentityMapping] -- /Node DefaultAnimationLoop computeBoundingBoxfalse/ VisualStyle displayFlagsshowForceFields / MeshGmshLoader namemeshLoaderCoarse filenamemesh/liver.msh / 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 / ConstantForceField totalForce1 0 0 / Node nameVisual OglModel nameVisualModel src../../meshLoaderCoarse / IdentityMapping nameMapping input../MechanicalModel outputVisualModel / /Node /Node /Node1. 为什么需要 Mapping1.1.Mapping每个 time step 都需要重新加载/更新 node positionmapping能自动做这个。Mapping 会在mechanical model和rendering model之间创建对应关系。它的作用是MechanicalObject 算出新的位置/速度↓Mapping 自动传播这些信息↓OglModel 更新显示所以 mapping 不是装饰品它是 SOFA 多表示结构里的连接器。1.2.为什么把 Visual 做成 Liver 里面的子节点通常我们创建 visual model 这种子表示时会把它放在对象内部的一个子节点里。因为在 SOFA 的层级关系里mechanics 是主表示rendering 只是跟随 mechanics。所以代码从 6-visual-model.scn 的这种Node nameLiver ... OglModel nameVisualModel src../meshLoaderCoarse / /Node变成 7 号的这种Node nameLiver ... MechanicalObject nameMechanicalModel ... / Node nameVisual OglModel nameVisualModel src../../meshLoaderCoarse / IdentityMapping nameMapping input../MechanicalModel outputVisualModel / /Node /Node意思是Liver 是主对象。MechanicalObject 是力学主表示。Visual 是 Liver 里面的视觉子表示。VisualModel 通过 Mapping 跟随 MechanicalModel。1.3.路径变化../../meshLoaderCoarse在6-visual-model.scn里OglModel和MechanicalObject都在Liver这一层所以引用 root 下的 loader 时写src../meshLoaderCoarse但在7-mapping.scn里OglModel被放进了Visual子节点root ├── meshLoaderCoarse └── Liver └── Visual └── OglModel所以从Visual里面要回到 root需要往上走两层Visual → Liver → root因此写src../../meshLoaderCoarse因为现在低了两个节点所以要用../..往上走两层。1.4.视觉模型开始跟随力学模型点击 Animate 后mesh 会跟随运动如果拖动力学模型rendering model渲染模型 也会跟着因为新位置在每个 time step 都通过 mapping 更新。这段对应的是IdentityMapping nameMapping input../MechanicalModel outputVisualModel /把 MechanicalModel 的位置和速度传给 VisualModel。MechanicalObject负责计算真实力学状态。OglModel负责显示外观。Mapping负责把力学状态传给显示模型。没有 mapping 时力学模型和视觉模型是两套表示视觉模型不一定知道力学模型怎么动。有 mapping 后力学模型每一步算出的新位置/速度会自动传播给视觉模型。Liver ├── MechanicalObject 力学表示负责计算 ├── FEMForceField 材料内部力 ├── Mass 质量 └── Visual ├── OglModel 视觉表示负责显示 └── IdentityMapping 连接力学和视觉2.7-mapping.scn同一网格的映射2.1.IdentityMappingNode nameVisual OglModel nameVisualModel src../../meshLoaderCoarse / IdentityMapping nameMapping input../MechanicalModel outputVisualModel / /Node这时候mechanical model力学模型和visual model视觉模型用的是同一个 mesh也就是同一套节点、同一套拓扑。老师说这种 mapping 就像一个identity mapping恒等映射。因为它不是从一个空间转换到另一个不同空间而是从“同一个网格”传到“同一个网格”。所以它本质上就是视觉模型的位置 力学模型的位置如果两个对象节点数量一样、网格也一样那么从力学空间到渲染空间的变换就是identity matrix单位矩阵所以叫IdentityMapping。IdentityMapping 两边网格一样直接一一复制位置/速度。2.2.查看mesh、rendering model1meshmesh 就是网格。如果想看更明显的网格线打开 Windows → Display Flags勾 Show Wire Frame。或者左侧点 VisualStyle1 右边找displayFlags勾上showVisual showBehavior showForceFields showWireFrame这样就能看到表面的三角形线框。2rendering modelrendering model 是渲染模型。左边展开 Liver再展开里面的 Visual找 VisualModel点它右边Selection details会显示它的属性。画面里各部分对应灰色大块视觉模型也就是 rendering model / OglModel。白色小点力学模型的节点也就是 MechanicalObject 里的点。3.7-mapping-fine-visual.scn不同网格的映射7-mapping-fine-visual.scn?xml version1.0? !-- Mapping with two different topologies -- Node nameroot dt0.01 gravity0 0 0 Node nameplugins RequiredPlugin nameSofa.Component.IO.Mesh/ RequiredPlugin nameSofa.Component.LinearSolver.Iterative/ RequiredPlugin nameSofa.Component.Mass/ RequiredPlugin nameSofa.Component.MechanicalLoad/ RequiredPlugin nameSofa.Component.StateContainer/ RequiredPlugin nameSofa.Component.ODESolver.Backward/ RequiredPlugin nameSofa.Component.SolidMechanics.FEM.Elastic/ RequiredPlugin nameSofa.Component.Topology.Container.Dynamic/ RequiredPlugin nameSofa.Component.Visual/ RequiredPlugin nameSofa.GL.Component.Rendering3D/ RequiredPlugin nameSofa.Component.Mapping.NonLinear/ /Node DefaultAnimationLoop computeBoundingBoxfalse/ VisualStyle displayFlagsshowVisual showBehavior showForceFields showWireFrame/ 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 / ConstantForceField totalForce1 0 0 / Node nameFineVisualModel OglModel nameVisualModel src../../meshLoaderFine / BarycentricMapping nameMapping input../MechanicalModel outputVisualModel / /Node /Node /Node3.1.fine visual 场景演示打开 7-mapping-fine-visual.scn 可以看到一个更细的红色 mesh。选中 wireframe并关闭 force field只看 rendering mesh。会发现这个红色网格只是一个表面它不是体积网格。它只是 triangulated surface只有三角面表面不包含内部四面体。然后再打开 force field能看到蓝色/力学相关的体网格。这个体网格才是用来做力学计算的 3D volumetric mesh。运行仿真并拖动物体红色视觉网格虽然不是力学网格但它会跟着变形。原因就是力学模型的运动→ 通过 BarycentricMapping 插值→ 传给红色视觉表面网格红色 mesh 使用的不是 mechanics 的 mesh但力学运动会通过 barycentric mapping 插值到红色 mesh 上。3.2.SOFA 里力学表示和视觉表示可以分离现在仿真分成两部分。第一部分是 mechanics负责真正计算EulerImplicitSolverCGLinearSolverTetrahedronSetTopologyContainerMechanicalObjectTetrahedronFEMForceFieldMeshMatrixMassConstantForceField这些都工作在 3D volumetric mesh 上也就是蓝色体网格。第二部分是 rendering只负责显示是一个更光滑的 surface mesh。它不自己计算力学而是通过 mapping 依附在力学表示上。we mapped a rendering representation onto a mechanical representation。这样之后不需要手动定义视觉模型怎么动SOFA 会自动通过 mapping 更新。3.3.力学网格和视觉网格不一样的情况因为力学网格太细会让计算变慢但视觉网格可以细一点让显示更好看。这时需要两个 loaderMeshGmshLoader namemeshLoaderCoarse filenamemesh/liver.msh / MeshOBJLoader namemeshLoaderFine filenamemesh/liver-smooth.obj /第一个用来加载粗的体积网格给力学模型用。第二个用来加载细的表面网格给视觉模型用。.msh这种 Gmsh 格式可以支持 volumetric object也就是体积网格而.obj通常只用于 surface mesh也就是表面网格。力学计算需要 3D 体网格因为 FEM 要在体积内部积分但渲染只需要外表面不需要把内部的四面体都画出来。所以这里的设计是力学模型用 liver.msh粗的 3D 体网格视觉模型用 liver-smooth.obj更光滑的表面网格3.4.不同网格不能用 IdentityMapping要用 BarycentricMapping现在两个网格不一样了MechanicalModel 使用 coarse volumetric meshVisualModel 使用 fine surface mesh它们节点数量不一样拓扑也不一样所以不能再直接一一复制。这时需要一种interpolation插值。SOFA 里用的是BarycentricMapping nameMapping input../MechanicalModel outputVisualModel /BarycentricMapping中文可以叫重心映射 / 重心坐标映射它会计算视觉网格上的每个点位于力学体网格的哪个四面体/单元附近并用力学网格节点的运动来插值出视觉点的位置。老师说这个 mapping 会根据 mechanics 的信息对 rendering model 的运动进行插值。BarycentricMapping 用力学网格的变形结果插值驱动另一个不同的视觉网格。4.7-mapping-extract-surface.scn从体网格提取视觉表面7-mapping-extract-surface.scn?xml version1.0? !-- Extract surface from volumetric mesh and map it to the mechanical model -- Node nameroot dt0.01 gravity0 0 0 Node nameplugins RequiredPlugin nameSofa.Component.IO.Mesh/ RequiredPlugin nameSofa.Component.LinearSolver.Iterative/ RequiredPlugin nameSofa.Component.Mass/ RequiredPlugin nameSofa.Component.MechanicalLoad/ RequiredPlugin nameSofa.Component.StateContainer/ RequiredPlugin nameSofa.Component.ODESolver.Backward/ RequiredPlugin nameSofa.Component.SolidMechanics.FEM.Elastic/ RequiredPlugin nameSofa.Component.Topology.Container.Dynamic/ RequiredPlugin nameSofa.Component.Topology.Mapping/ RequiredPlugin nameSofa.Component.Visual/ RequiredPlugin nameSofa.GL.Component.Rendering3D/ RequiredPlugin nameSofa.Component.Mapping.Linear/ /Node DefaultAnimationLoop computeBoundingBoxfalse/ VisualStyle displayFlagsshowVisual showBehavior showForceFields showWireFrame/ MeshGmshLoader namemeshLoaderCoarse filenamemesh/liver.msh / 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 / ConstantForceField totalForce1 0 0 / Node nameExtractSurface TriangleSetTopologyContainer nameContainer / TriangleSetTopologyModifier nameModifier / Tetra2TriangleTopologicalMapping input../topo outputContainer / Node nameVisual OglModel nameVisualModel colorgreen / IdentityMapping nameMapping input.. outputVisualModel / /Node /Node /Node /Node4.1 为什么要提取表面Extract Surface这个例子不是重新加载一个liver-smooth.obj而是从原来的体网格里直接提取表面。也就是说力学模型还是用liver.msh这个体网格但视觉模型不用单独准备一个新的表面文件而是从这个体网格中抽取外表面三角形作为视觉模型。这样可以避免重新划分网格也不需要单独创建一个 dedicated mesh。方法 A单独加载一个 fine surface mesh例如 liver-smooth.obj方法 B从 mechanical volumetric mesh 里 extract surface直接提取表面这两个都可以。真实项目中如果你有好看的外观模型可以用方法 A如果没有就可以从体网格里提取表面。4.2.关键组件Tetra2TriangleTopologicalMappingTetra2TriangleTopologicalMapping input../topo outputContainer /Tetratetrahedron 四面体。也就是四面体网格Triangle三角形。因为表面由三角形组成。TopologicalMapping拓扑映射。所以 Tetra2TriangleTopologicalMapping 完整意思把四面体拓扑转换成三角形表面拓扑。输入input../topo这里的 topo 是什么前面TetrahedronSetTopologyContainer nametopo src../meshLoaderCoarse/所以 topo 是四面体拓扑。里面是tetra 1 tetra 2 tetra 3 ...输出outputContainerContainerTriangleSetTopologyContainer nameContainer/也就是生成三角形表面。所以流程是liver.msh -- TetrahedronSetTopologyContainer -- Tetra2TriangleTopologicalMapping -- TriangleSetTopologyContainer -- OglModel显示对比组件作用BarycentricMapping不同网格同步运动IdentityMapping相同网格同步运动Tetra2TriangleTopologicalMapping从四面体生成三角表面