5-SOFA可变形的3D物体 5-elasticity.scn

接下来从 rigid case 进入 deformable case(从刚体情况进入可变形情况)

rigid frames → deformable object

一个或多个刚体点/刚体 frame 整体移动→一个 3D 物体可以发生形变

Adding a material law for deformation 现在要给物体加入"材料定律",让它能按照材料属性发生变形。

5-elasticity.scn

XML 复制代码
<?xml version="1.0"?>

<!-- Adding a material law for deformation -->
<Node name="root" dt="0.01" gravity="0 0 0">

    <!-- Needed to use UniformMass / MeshMatrixMass -->
    <RequiredPlugin name="Sofa.Component.Mass"/>

    <!-- Needed to use ConstantForceField -->
    <RequiredPlugin name="Sofa.Component.MechanicalLoad"/>

    <!-- Needed to use MechanicalObject -->
    <RequiredPlugin name="Sofa.Component.StateContainer"/>

    <!-- Needed to use CGLinearSolver -->
    <RequiredPlugin name="Sofa.Component.LinearSolver.Iterative"/>

    <!-- Needed to use EulerImplicitSolver -->
    <RequiredPlugin name="Sofa.Component.ODESolver.Backward"/>

    <!-- Needed to use MeshGmshLoader -->
    <RequiredPlugin name="Sofa.Component.IO.Mesh"/>

    <!-- Needed to use TetrahedronSetTopologyContainer / TetrahedronSetGeometryAlgorithms -->
    <RequiredPlugin name="Sofa.Component.Topology.Container.Dynamic"/>

    <!-- Needed to use TetrahedronFEMForceField -->
    <RequiredPlugin name="Sofa.Component.SolidMechanics.FEM.Elastic"/>

    <DefaultAnimationLoop computeBoundingBox="false"/>

    <MeshGmshLoader name="meshLoaderCoarse" filename="mesh/liver.msh" />

    <!-- Optional: transform the loaded mesh position -->
    <!--
    <TransformEngine name="transformer"
                     input_position="@meshLoaderCoarse.position"
                     translation="0 2 0"
                     rotation="0 0 0" />
    -->

    <Node name="Liver">

        <EulerImplicitSolver />
        <CGLinearSolver iterations="200" tolerance="1e-09" threshold="1e-09"/>

        <TetrahedronSetTopologyContainer name="topo" src="@../meshLoaderCoarse" />

        <TetrahedronSetGeometryAlgorithms template="Vec3d" name="GeomAlgo" />

        <MechanicalObject template="Vec3d"
                          name="MechanicalModel"
                          showObject="1" />

        <TetrahedronFEMForceField name="FEM"
                                  youngModulus="1000"
                                  poissonRatio="0.4" />

        <MeshMatrixMass massDensity="1" />

        <ConstantForceField totalForce="1 0 0" />

    </Node>

</Node>

学习简化版代码:

XML 复制代码
<Node name="root" dt="0.01" gravity="0 0 0">

    <MeshGmshLoader name="meshLoaderCoarse" filename="mesh/liver.msh" />

    <Node name="Liver">

        <EulerImplicitSolver />
        <CGLinearSolver iterations="200" tolerance="1e-09" threshold="1e-09"/>

        <TetrahedronSetTopologyContainer name="topo" src="@../meshLoaderCoarse" />
        <TetrahedronSetGeometryAlgorithms template="Vec3d" name="GeomAlgo" />

        <MechanicalObject template="Vec3d" name="MechanicalModel" showObject="1"/>

        <TetrahedronFEMForceField name="FEM" youngModulus="1000" poissonRatio="0.4" />
        <MeshMatrixMass massDensity="1" />
        <ConstantForceField totalForce="1 0 0" />

    </Node>

</Node>

1.deformable object 可形变物体

在前面 SOFA 场景里,什么东西决定了对象的类型、决定了自由度的性质?

答案是:MechanicalObject 的 template

XML 复制代码
<MechanicalObject template="Rigid3d" ... />

它表示对象是 3D 刚体,状态包含:位置 x y z + 姿态 orientation / quaternion

现在进入可变形物体后,最关键变化是:

XML 复制代码
<MechanicalObject template="Vec3d" name="MechanicalModel" showObject="1"/>

Rigid3d 改成 Vec3d,这是从刚体到可变形物体时主要改变的东西之一。

区别是:

(1)Rigid3d:

每个自由度 = 位置 xyz + 姿态 quaternion

适合刚体 frame。

(2)Vec3d:

每个自由度 = 位置 xyz

适合可变形体的网格节点。

对于可变形物体,每个节点只是空间中的一个点,它可以移动,但没有自己的刚体姿态。

所以现在的未知量是:每个 mesh node 的 x、y、z 位置

2.TetrahedronSetTopologyContainer(四面体拓扑容器)

如果我们要做一个普通的 3D 可变形物体,就需要一个真正的 3D 有体积的网格

前面 liver.msh 文件不只包含点,还包含:points / nodes、edges、triangles、tetrahedra

其中 tetrahedra 是四面体单元,是 3D 体积元素。要在 3D 空间里求解力学平衡方程,需要这些 3D 元素作为空间支撑。

可变形仿真不是让一堆独立点乱飞,而是让一个由四面体连接起来的体积物体发生形变。

之前只关心点,所以用:

XML 复制代码
<PointSetTopologyContainer name="topo" src="@../meshLoaderCoarse" />

现在要做 3D 可变形体,需要完整的四面体拓扑,所以换成:

XML 复制代码
<TetrahedronSetTopologyContainer name="topo" src="@../meshLoaderCoarse" />

它同样从 meshLoaderCoarse 里读取数据,但这次不再只读取点,而是读取完整的拓扑层级:tetrahedra、triangles、edges、points。

这些信息先由 MeshGmshLoader 加载,然后由 TetrahedronSetTopologyContainer 存储。

3.MechanicalObject 仍然不用手写 position

和之前一样,现在也不需要在 MechanicalObject 里手写:position="..."

XML 复制代码
<TetrahedronSetTopologyContainer name="topo" src="@../meshLoaderCoarse" />
<MechanicalObject template="Vec3d" name="MechanicalModel" showObject="1"/>

MechanicalObject 会在同一个 Liver 节点里找到 topology container,然后自动用里面的节点位置初始化自己的 position。

MeshGmshLoader 读 mesh

→ TetrahedronSetTopologyContainer 保存四面体拓扑和点位置

→ MechanicalObject 自动拿这些点位置作为初始状态

4.TetrahedronSetGeometryAlgorithms 工具包

XML 复制代码
<TetrahedronSetGeometryAlgorithms template="Vec3d" name="GeomAlgo" />

它不是主要的物理组件,而是一个 toolkit,工具包

它提供几何计算能力,比如:某个四面体的体积是多少、某个三角形的面积是多少、两个点之间的距离是多少。这些几何信息会被后面的物理组件使用。

5.负责物理的组件

后面这两个组件会用到上面的几何算法:

XML 复制代码
<TetrahedronFEMForceField name="FEM" youngModulus="1000" poissonRatio="0.4" />
<MeshMatrixMass massDensity="1" />
(1)MeshMatrixMass(网格质量矩阵组件)
XML 复制代码
<MeshMatrixMass massDensity="1" />

这个组件根据体网格和质量密度,进行空间积分,构建质量矩阵。给它一个 mass density,它就能在整个 3D 域上积分,得到 mass matrix。

UniformMass:

前面那种简单平均分配总质量。

MeshMatrixMass:

根据 3D 网格体积和质量密度,计算更合理的质量分布。

(2)TetrahedronFEMForceField
XML 复制代码
<TetrahedronFEMForceField name="FEM" youngModulus="1000" poissonRatio="0.4" />

TetrahedronFEMForceField 组件 实现的是可变形体的 材料模型 / 本构力学模型

它定义了:物体如何变形、物体变形后产生什么内部力,这些内部力就是材料本身抵抗变形的力。

  • 刚体以前只有:质量 + 外力 → 整体运动
  • 可变形体现在多了:材料模型 → 产生内部弹性力 → 发生形变但又抵抗形变

这个 constitutive mechanical model(材料本构模型) 是 linear elasticity 线弹性 模型。

线弹性可以理解成,形变不太大时,力和位移/应变近似成线性关系。类似弹簧里的胡克定律:F = kx

力学里还有很多材料模型,比如一些 hyperelastic model,超弹性模型 ,包括 Mooney-Rivlin、Ogden 等,它们属于非线性材料模型。但这里这个不是那些复杂非线性模型,而是 linear elasticity,线弹性模型

(a).youngModulus 杨氏模量

youngModulus="1000" 这是 杨氏模量。它代表材料有多硬,单位和压力一样,通常是 Pascal/ Pa。

  • Young's modulus 大:材料更硬,不容易变形
  • Young's modulus 小:材料更软,更容易变形
(b).poissonRatio 泊松比

poissonRatio="0.4" 这是 泊松比。它和材料的横向变形/可压缩性有关。比如你压缩一个方向,另一个方向会膨胀多少。

poissonRatio 控制材料被拉伸/压缩时,横向会怎么变。

6.刚体和可变形体的对比

前面刚体:

XML 复制代码
<MechanicalObject template="Rigid3d" .../>
<UniformMass totalMass="1"/>
<ConstantForceField totalForce="1 0 0 0 0 0"/>

它只有一个刚体 frame。受到力以后不会变形,只会整体运动。

现在可变形体:

XML 复制代码
<TetrahedronSetTopologyContainer .../>
<MechanicalObject template="Vec3d" .../>
<TetrahedronFEMForceField .../>
<MeshMatrixMass .../>
<ConstantForceField totalForce="1 0 0"/>

它是一个 3D mesh。这个网格作为空间积分域,用来计算质量、材料内部力和外力。

ConstantForceField 现在只有 3 个数

  • 前面刚体 Rigid3d 时外力是 totalForce="1 0 0 0 0 0",因为刚体有 3 个平移力 + 3 个力矩
  • 现在 Vec3d 时外力变成 totalForce="1 0 0",因为每个节点只有 x y z 三个平移自由度

没有刚体姿态,也没有力矩自由度。现在没有 frame / orientation 的概念,只有空间中的点,所以 force 自身也只有 X、Y、Z 三个分量。

刚体阶段 可变形体阶段
Rigid3d Vec3d
一个刚体 frame,有位置和姿态 mesh 节点,只有 x/y/z 位置
PointSetTopologyContainer TetrahedronSetTopologyContainer
只用点 用四面体体网格
UniformMass MeshMatrixMass
简单质量 根据质量密度和体积积分质量矩阵
没有材料模型 TetrahedronFEMForceField 定义材料变形规律
totalForce="1 0 0 0 0 0" totalForce="1 0 0"

7.SOFA 不管单位,单位一致性要自己负责

SOFA 不会自动知道你用的是米、毫米、千克还是克,SOFA 只拿数值去计算,所以必须保证所有输入单位是一致的。

比如用国际单位制:

长度:m;质量:kg;时间:s;力:N;杨氏模量:Pa;密度:kg/m³;重力加速度:m/s²

但如果mesh 是毫米单位,又把 Young modulus 当成 Pa 来填,仿真结果就会错。网格单位、杨氏模量、质量密度、重力加速度这些都必须在同一套单位体系里。

所以很多错误都来自 mesh。

因为 mesh 可能来自扫描、MRI、3D scan 或别的软件,里面的尺寸单位有时并不清楚。它可能是毫米,也可能是米,也可能只是某种缩放后的无单位坐标。

所以以后拿到一个 .msh.obj.vtk 文件,不要只问"能不能加载",还要问:

这个 mesh 的坐标单位到底是什么?

它的大小是真实尺寸吗?

这会直接影响材料参数、质量、重力和仿真稳定性。

相关推荐
2501_915909062 小时前
iOS应用性能优化:十大策略提升用户体验与开发效率
android·ios·小程序·https·uni-app·iphone·webview
sun0077003 小时前
打通android全链路,网卡驱动, 内核 , 到上层hal, framework
android
awu的Android笔记3 小时前
Android VpnService:如何把所有流量导入用户态
android
plainGeekDev3 小时前
AlertDialog → DialogFragment
android·java·kotlin
流星白龙3 小时前
【MySQL高阶】13.其他存储引擎
android·数据库·mysql
Lyyaoo.3 小时前
【MySQL】SQL优化
android·sql·mysql
ImTryCatchException4 小时前
Android 性能优化实战手册:从理论到落地的完整方法论
android·性能优化
sun0077004 小时前
qnx网络相关模块,全链路,硬件网卡 → 用户态驱动 (.so) → io‑pkt/io‑sock(用户态 TCP/IP + 转发 + 控制)
android
赏金术士4 小时前
Android app 项目:模块打包 AAR 教程
android·热修复·tinker·aar打包