# 🌊 超越刚体 Genesis 统一了多个物理求解器,支持超越刚体动力学的仿真。`solver`(求解器)本质上是处理特定材料集的一组物理仿真算法。在本教程中,我们将介绍 3 个流行的求解器,并使用它们来仿真具有不同物理属性的实体: - [光滑粒子流体动力学(SPH)求解器](#sph) - [物质点法(MPM)求解器](#mpm) - [基于位置的动力学(PBD)求解器](#pbd) ## 使用 SPH 求解器进行液体仿真 首先,让我们看看如何仿真一个水立方。让我们像往常一样创建一个空场景并添加一个平面: ```python import genesis as gs ########################## init ########################## gs.init() ########################## create a scene ########################## scene = gs.Scene( sim_options=gs.options.SimOptions( dt = 4e-3, substeps = 10, ), sph_options=gs.options.SPHOptions( lower_bound = (-0.5, -0.5, 0.0), upper_bound = (0.5, 0.5, 1), particle_size = 0.01, ), vis_options=gs.options.VisOptions( visualize_sph_boundary = True, ), show_viewer = True, ) ########################## entities ########################## plane = scene.add_entity( morph=gs.morphs.Plane(), ) ``` 这里我们应该注意几点: - 配置 `sim_options` 时,现在我们使用相对较小的 `dt` 并设置 `substeps=10`。这意味着在仿真器内部,对于每个 `step`,它将仿真 10 个 `substep`,每个 `substep_dt = 4e-3 / 10`。当我们之前处理刚体时,我们不需要设置这个,只是使用了默认设置(`substeps=1`),每个步骤只运行 1 个子步骤。 接下来,让我们添加水。添加 - 正如我们之前讨论的,我们使用 `options` 来配置每个不同的求解器。由于我们使用 `SPHSolver`,我们需要通过 `sph_options` 配置其属性。在这个示例中,我们设置求解器的边界,并将粒子大小指定为 0.01m。SPHSolver 是一个拉格朗日求解器,意味着它使用粒子来表示对象。 - 在 `vis_options` 中,我们指定希望在渲染视图中看到 SPH 求解器的边界。 接下来,让我们添加一个水块实体并开始仿真! 当我们添加块时,将它从刚体块变成水块所需的唯一区别是设置 `material`。事实上,当我们之前只处理刚体时,这在内部默认设置为 `gs.materials.Rigid()`。由于我们现在使用 SPH 求解器进行液体仿真,我们在 `SPH` 类别下选择 `Liquid` 材料: ```python liquid = scene.add_entity( material=gs.materials.SPH.Liquid( sampler='pbs', ), morph=gs.morphs.Box( pos = (0.0, 0.0, 0.65), size = (0.4, 0.4, 0.4), ), surface=gs.surfaces.Default( color = (0.4, 0.8, 1.0), vis_mode = 'particle', ), ) ########################## build ########################## scene.build() horizon = 1000 for i in range(horizon): scene.step() ``` 创建 `Liquid` 材料时,我们设置 `sampler='pbs'`。这配置了我们希望如何根据 `Box` morph 对粒子进行采样。`pbs` 代表'基于物理的采样',它运行一些额外的仿真步骤以确保粒子以物理自然的方式排列。你也可以使用 `'regular'` 采样器简单地使用网格晶格模式对粒子进行采样。如果你使用其他求解器,如 MPM,你也可以使用 `'random'` 采样器。 你可能还注意到我们传入了一个额外的属性——`surface`。此属性用于定义实体的所有视觉属性。这里,我们将水的颜色设置为偏蓝色,并通过设置 `vis_mod='particle'` 选择将其可视化为粒子。 一旦你成功运行此示例,你会看到水落下并在平面上扩散,但限制在求解器边界内: 你可以通过以下方式获取实时粒子位置: ``` particles = liquid.get_particles_pos() ``` **更改液体属性:** 你也可以调整液体的物理属性。例如,你可以增加其粘度(`mu`)和表面张力(`gamma`): ```python material=gs.materials.SPH.Liquid(mu=0.02, gamma=0.02), ``` 并观察行为将如何不同。尽情享受吧! 完整脚本: ```python import genesis as gs ########################## init ########################## gs.init() ########################## create a scene ########################## scene = gs.Scene( sim_options=gs.options.SimOptions( dt = 4e-3, substeps = 10, ), sph_options=gs.options.SPHOptions( lower_bound = (-0.5, -0.5, 0.0), upper_bound = (0.5, 0.5, 1), particle_size = 0.01, ), vis_options=gs.options.VisOptions( visualize_sph_boundary = True, ), show_viewer = True, ) ########################## entities ########################## plane = scene.add_entity( morph=gs.morphs.Plane(), ) liquid = scene.add_entity( # 粘性液体 # material=gs.materials.SPH.Liquid(mu=0.02, gamma=0.02), material=gs.materials.SPH.Liquid(), morph=gs.morphs.Box( pos = (0.0, 0.0, 0.65), size = (0.4, 0.4, 0.4), ), surface=gs.surfaces.Default( color = (0.4, 0.8, 1.0), vis_mode = 'particle', ), ) ########################## build ########################## scene.build() horizon = 1000 for i in range(horizon): scene.step() # 获取粒子位置 particles = liquid.get_particles_pos() ``` ## 使用 MPM 求解器进行可变形物体仿真 MPM 求解器是一个非常强大的物理求解器,支持更广泛的材料。MPM 代表物质点法,使用混合拉格朗日-欧拉表示,即粒子和网格,来表示对象。 在本示例中,让我们创建三个对象: - 一个弹性立方体,可视化为 `'particles'` - 一个液体立方体,可视化为 `'particles'` - 一个弹塑性球体,可视化为原始球体网格,但基于内部粒子状态变形(`vis_mode='visual'`)。将内部粒子状态映射到变形视觉网格的过程在计算机图形学中称为 *蒙皮*。 完整代码脚本: ```python import genesis as gs ########################## init ########################## gs.init() ########################## create a scene ########################## scene = gs.Scene( sim_options=gs.options.SimOptions( dt = 4e-3, substeps = 10, ), mpm_options=gs.options.MPMOptions( lower_bound = (-0.5, -1.0, 0.0), upper_bound = (0.5, 1.0, 1), ), vis_options=gs.options.VisOptions( visualize_mpm_boundary = True, ), viewer_options=gs.options.ViewerOptions( camera_fov=30, ), show_viewer = True, ) ########################## entities ########################## plane = scene.add_entity( morph=gs.morphs.Plane(), ) obj_elastic = scene.add_entity( material=gs.materials.MPM.Elastic(), morph=gs.morphs.Box( pos = (0.0, -0.5, 0.25), size = (0.2, 0.2, 0.2), ), surface=gs.surfaces.Default( color = (1.0, 0.4, 0.4), vis_mode = 'visual', ), ) obj_sand = scene.add_entity( material=gs.materials.MPM.Liquid(), morph=gs.morphs.Box( pos = (0.0, 0.0, 0.25), size = (0.3, 0.3, 0.3), ), surface=gs.surfaces.Default( color = (0.3, 0.3, 1.0), vis_mode = 'particle', ), ) obj_plastic = scene.add_entity( material=gs.materials.MPM.ElastoPlastic(), morph=gs.morphs.Sphere( pos = (0.0, 0.5, 0.35), radius = 0.1, ), surface=gs.surfaces.Default( color = (0.4, 1.0, 0.4), vis_mode = 'particle', ), ) ########################## build ########################## scene.build() horizon = 1000 for i in range(horizon): scene.step() ``` 注意,要更改底层物理材料,你所要做的就是更改 `material` 属性。随意尝试其他材料类型(如 `MPM.Sand()` 和 `MPM.Snow()`),以及每种材料类型中的属性值。 预期的渲染结果: ## 使用 PBD 求解器进行布料仿真 PBD 代表基于位置的动力学。这也是一个拉格朗日求解器,使用粒子和边来表示实体,并通过求解一组基于位置的约束来仿真它们的状态。它可以用于仿真保持其拓扑结构的 1D/2D/3D 实体。在本示例中,我们将看到如何使用 PBD 求解器仿真布料。 在本示例中,我们将添加两个方形布料实体:一个固定 4 个角,另一个只固定 1 个角并落到第一块布上。此外,我们将使用不同的 `vis_mode` 渲染它们。 创建场景并构建: ```python import genesis as gs ########################## init ########################## gs.init() ########################## create a scene ########################## scene = gs.Scene( sim_options=gs.options.SimOptions( dt = 4e-3, substeps = 10, ), viewer_options=gs.options.ViewerOptions( camera_fov = 30, res = (1280, 720), max_FPS = 60, ), show_viewer = True, ) ########################## entities ########################## plane = scene.add_entity( morph=gs.morphs.Plane(), ) cloth_1 = scene.add_entity( material=gs.materials.PBD.Cloth(), morph=gs.morphs.Mesh( file='meshes/cloth.obj', scale=2.0, pos=(0, 0, 0.5), euler=(0.0, 0, 0.0), ), surface=gs.surfaces.Default( color=(0.2, 0.4, 0.8, 1.0), vis_mode='visual', ) ) cloth_2 = scene.add_entity( material=gs.materials.PBD.Cloth(), morph=gs.morphs.Mesh( file='meshes/cloth.obj', scale=2.0, pos=(0, 0, 1.0), euler=(0.0, 0, 0.0), ), surface=gs.surfaces.Default( color=(0.8, 0.4, 0.2, 1.0), vis_mode='particle', ) ) ########################## build ########################## scene.build() ``` 然后,让我们固定我们想要的角(粒子)。为此,我们提供了一个方便的工具,使用笛卡尔空间中的位置来定位粒子: ```python cloth_1.fix_particles(cloth_1.find_closest_particle((-1, -1, 1.0))) cloth_1.fix_particles(cloth_1.find_closest_particle((1, 1, 1.0))) cloth_1.fix_particles(cloth_1.find_closest_particle((-1, 1, 1.0))) cloth_1.fix_particles(cloth_1.find_closest_particle((1, -1, 1.0))) cloth_2.fix_particles(cloth_2.find_closest_particle((-1, -1, 1.0))) horizon = 1000 for i in range(horizon): scene.step() ``` 预期的渲染结果: :::{warning} **2D 网格的蒙皮** 我们注意到在使用 2D 平面布料网格并设置 `vis_mode='visual'` 时存在一些问题,这是由于计算质心权重时退化的伪逆矩阵计算导致的。如果你在上述示例中添加非零的欧拉角并使用 `vis_mode='visual'`,你可能会注意到奇怪的可视化结果。我们将很快修复这个问题。 ::: ***关于求解器耦合的更多教程即将推出!***