Files
mindbot/create_liquid.py

130 lines
4.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import omni.isaac.core.utils.prims as prim_utils
from omni.isaac.core.simulation_context import SimulationContext
from omni.isaac.core.utils.stage import get_current_stage
from pxr import UsdGeom, UsdPhysics, PhysxSchema, Gf, Sdf
# 引入 PhysX 粒子工具 (Omniverse 内置库)
import omni.physx.scripts.utils as physxUtils
import omni.physx.scripts.particleUtils as particleUtils
def create_fluid_scene():
stage = get_current_stage()
# 1. 初始化仿真环境
sim = SimulationContext()
# 确保物理频率适合流体 (流体通常需要更小的步长或更多的子步)
sim.set_simulation_dt(physics_dt=1.0 / 60.0, rendering_dt=1.0 / 60.0)
# 2. 创建粒子系统 (Particle System)
# 这是管理所有流体粒子的容器
particle_system_path = "/World/FluidSystem"
particleUtils.add_physx_particle_system(
stage=stage,
particle_system_path=particle_system_path,
simulation_owner=None,
radius=0.02, # 粒子半径(决定流体分辨率)
contact_offset=0.03,
solid_rest_offset=0.02,
fluid_rest_offset=0.02,
mode="fluid" # 设置为流体模式
)
# 3. 创建流体材质 (定义粘度)
# 对于像蜂蜜或洗发水这样的"带流性"液体,需要高粘度
material_path = "/World/FluidMaterial"
particleUtils.add_pbd_particle_material(
stage=stage,
path=material_path,
cohesion=0.02, # 内聚力 (让液体聚在一起)
viscosity=0.5, # 粘度 (关键参数:数值越大越粘稠,如蜂蜜)
surface_tension=0.01, # 表面张力
friction=0.1, # 粒子间摩擦
damping=0.1 # 阻尼
)
# 4. 创建流体几何体 (在试管初始位置生成一堆粒子)
# 假设我们在 (0, 0, 0.5) 的位置生成一团液体
fluid_path = "/World/Liquid"
# 使用网格采样创建粒子点集
particleUtils.add_physx_particleset_pointinstancer(
stage=stage,
path=fluid_path,
particle_system_path=particle_system_path,
self_collision=True,
fluid=True,
particle_group=0,
particle_mass=0.001,
density=1000.0 # 水的密度
)
# 这里的关键是将材质绑定到几何体
physxUtils.add_physics_material_to_prim(stage, stage.GetPrimAtPath(fluid_path), material_path)
# 这里的逻辑通常需要编写一个简单的生成器,在空间中填满粒子
# 为了演示简单,我们假设通过 create_grid_particles 生成位置
# 在实际 Isaac Lab 中,你通常会加载一个预先保存好的带粒子的 USD或者使用 SamplingAPI
points = []
for x in range(5):
for y in range(5):
for z in range(10):
points.append(Gf.Vec3f(x*0.04, y*0.04, 0.5 + z*0.04))
# 将坐标赋予粒子系统
points_attr = stage.GetPrimAtPath(fluid_path).GetAttribute("positions")
points_attr.Set(points)
# 5. 创建容器 (烧杯和试管)
# 这里使用简单的圆柱管演示,实际应用需加载 .usd 模型
# 烧杯 (底部接收)
beaker_path = "/World/Beaker"
prim_utils.create_cyl(
prim_path=beaker_path,
radius=0.15,
height=0.2,
position=Gf.Vec3d(0, 0, 0.1)
)
# 注意PrimUtils创建的是实心凸包流体进不去。
# 关键步骤:必须将容器碰撞改为 Mesh (SDF) 或手动用多个面拼成空心杯子。
# 在代码中通常加载自定义 USD 资产,这里仅做说明:
# setup_concave_collision(beaker_path)
# 试管 (上方倒水)
tube_path = "/World/TestTube"
tube = prim_utils.create_cyl(
prim_path=tube_path,
radius=0.05,
height=0.2,
position=Gf.Vec3d(0.2, 0, 0.6) # 位于烧杯上方侧面
)
# 为试管添加刚体属性以便旋转
physxUtils.set_rigid_body_properties(stage, tube_path)
return sim, tube_path
def run_simulation(sim, tube_path):
# 6. 开始循环并执行“倒水”动作
sim.initialize_physics()
sim.play()
stage = get_current_stage()
tube_prim = stage.GetPrimAtPath(tube_path)
xform = UsdGeom.Xformable(tube_prim)
# 模拟 500 帧
for i in range(500):
# 简单的运动学控制:慢慢旋转试管
if i < 200:
# 旋转以倒出液体 (欧拉角或四元数)
rotation = Gf.Rotation(Gf.Vec3d(0, 1, 0), i * 0.5) # 绕Y轴旋转
# 注意:实际代码需处理完整的 Transform 设置
current_xform = xform.GetLocalTransformation()
# 这里简化处理,直接更新姿态逻辑需根据具体场景编写
sim.step()
# 执行
if __name__ == "__main__":
sim, tube = create_fluid_scene()
run_simulation(sim, tube)