OvPhysX 后端#
警告
OvPhysX 仍处于 高度实验性 阶段,目前不建议普遍使用。后端正在积极开发,公共接口变化较快。在 Isaac Lab 3.0 各测试版本之间,功能支持和测试命令可能变化。
警告
不要将 OvPhysX 与 Kit 可视化器组合使用。physics=ovphysx --visualizer kit 等命令不受支持:ovphysx 从自身软件包加载依赖 USD 的 PhysX 插件,而 Kit 在同一进程内管理另一套独立的 USD 和插件。请使用 --visualizer newton_gl、--visualizer rerun 或 --visualizer viser;也可以不传 --visualizer,以无界面方式运行。
OvPhysX 是不依赖 Kit 的 PhysX 后端变体。它直接驱动 PhysX,无需 Omniverse Kit 运行时,并从 USD 的 PhysicsScene prim 读取场景级求解器参数,而不是从 Python 配置读取。Python 配置 OvPhysxCfg 只暴露少数 USD 模式中没有对应表示的 GPU 缓冲区大小。
通过 OvPhysxCfg 选择 OvPhysX:
from isaaclab.sim import SimulationCfg
from isaaclab_ov.physics import OvPhysxCfg
sim_cfg = SimulationCfg(physics=OvPhysxCfg())
为什么使用 OvPhysX?#
不依赖 Kit 的运行。 OvPhysX 无需 Omniverse Kit,适合探索无界面部署,以及不需要 Kit 运行环境的后端。
以 USD 为权威依据。 求解器参数来自
PhysicsSceneUSD prim,已有 USD 场景管理能力的创作工具无需再维护一份 Python 配置。
当前可用功能#
资源与传感器接口沿用 PhysX 的设计,但本文编写时仅实现并验证了其中一部分。以下组件已在 develop 中可用:
RigidObject:通过 PR #5426 合并。
Articulation:通过 PR #5459 合并。
RigidObjectCollection:通过 PR #5570 合并。
接触传感器:通过 PR #5422 合并。
SceneDataProvider:通过 PR #5589 合并。
FrameView:通过 PR #5678 合并。
DeformableObject:在 CUDA 仿真设备上实验性支持体积和表面可变形体。对于原生张量布局相同的异构刚体与关节体几何变体,支持快速克隆。
其他 OvPhysX 功能仍在开发中。IMU、坐标系变换器、关节力与力矩传感器、PVA、射线投射器和渲染功能,在其实现进入 develop 并通过后端基本运行测试之前,本页不将其列为受支持功能。
异构克隆#
异构运行时克隆要求 OvPhysX 0.6.3。张量绑定按环境的数字顺序排列,保证索引式重置、动作和观测对应正确变体。变体的几何可以不同,但刚体、关节和肌腱布局必须一致。Isaac Lab 检查原型旋转轴和肌腱布局;OVPhysX 在绑定关节体时检查刚体与关节元数据。
克隆上下文只编译一次计划中的原型和仿真世界分配。物理管理器挂接一个导出的 USD 舞台,重放原生副本,并在资源和传感器绑定之前预热运行时。硬重置复用相同声明,不另设一次性消费队列。绑定路径来自计划的世界布局和环境模板,而不是原生克隆顺序。
所有写入 USD 的源对象均获得原生环境 ID 零。因此,包含源对象或仅通过 USD 定义物理的每个仿真世界,都会将其声明的全部资源作为原始对象导入。其他世界从组成相同、完整的原始世界克隆资源,每个目标世界使用一个原生环境 ID。这样,机器人、桌子和物体可以相互接触,无需目标占位对象。只复制声明的资源子树,其他写入 USD 的资源保持不变。
保持 filter_collisions 启用,以通过 USD 碰撞组隔离原始世界。GPU 副本还使用原生环境 ID 过滤。OvPhysX 0.6.3 的 CPU 模式没有原生环境 ID 过滤,会导入全部声明的 USD 副本,并使用碰撞组。大量重叠的原始布局仍可能耗尽粗检测碰撞对容量,因此应将环境在空间上分开。
可变形体限制#
目前 OvPhysX 要求同一个 DeformableObject 匹配到的所有物体具有相同数量的仿真节点。节点数量不同时,初始化会报错,而不会暴露填充后的状态,以免产生错误的归约结果。
可变形体场景还要求将整个 USD 舞台实例化展开,因此启动开销会随已定义环境数量增加。这条路径适合小规模验证场景,目前不支持数千个环境的训练规模工作负载。异构快速克隆器不支持可变形体。
安装#
ovphysx 扩展依赖要求 OvPhysX 0.6.4.72118723。在仓库根目录执行以下命令安装:
uv sync --inexact --extra ovphysx
--inexact 会保留通过其他扩展依赖安装的软件包。使用 --extra ov 可同时安装公开发行的 OvPhysX 和 OVRTX 运行时。这组扩展依赖将 OVRTX 0.5.1.385782 与 OVStage 0.2.1 配套使用;OVRTX 0.4.1 与该组合不兼容。旧版 Isaac Lab 安装器也支持 ./isaaclab.sh -i 'ov[ovphysx]' 和 ./isaaclab.sh -i 'ov[all]'。
测试安装#
先检查 Python 软件包和运行时 wheel 能否正常导入:
uv run --extra ovphysx --extra test python -c "import ovphysx.types; from isaaclab_ov.physics import OvPhysxCfg; print('OvPhysX runtime OK')"
./isaaclab.sh -p -c "import ovphysx.types; from isaaclab_ov.physics import OvPhysxCfg; print('OvPhysX runtime OK')"
然后运行一个小规模后端基本运行测试:
uv run --extra ovphysx --extra test python -m pytest source/isaaclab_ov/test/assets/test_rigid_object.py::test_initialization -k cpu
./isaaclab.sh -p -m pytest source/isaaclab_ov/test/assets/test_rigid_object.py::test_initialization -k cpu
要运行声明了 OvPhysX 物理预设的任务,使用与其他后端相同的预设 CLI 语法:
uv run --extra ovphysx isaaclab zero_agent --task Isaac-Cartpole-Direct \
--num_envs 128 --max_steps 64 --viz none physics=ovphysx
./isaaclab.sh -p scripts/environments/zero_agent.py --task Isaac-Cartpole-Direct \
--num_envs 128 --max_steps 64 --viz none physics=ovphysx
此命令以无界面方式运行 64 步零动作轨迹,然后退出。
受支持的足式运动环境#
以下足式运动训练环境声明了 ovphysx 物理预设。支持时,通过 uv run isaaclab play 运行策略也使用相同后端。
Isaac-Ant-DirectIsaac-Humanoid-DirectIsaacContrib-Velocity-Rough-AnymalBIsaacContrib-Velocity-Rough-AnymalCIsaac-Velocity-Flat-AnymalDIsaac-Velocity-Rough-AnymalDIsaacContrib-Velocity-Rough-UnitreeA1IsaacContrib-Velocity-Rough-UnitreeGo1Isaac-Velocity-Rough-UnitreeGo2Isaac-Velocity-Rough-CassieIsaac-Velocity-Rough-G1Isaac-Velocity-Rough-H1
当前状态与后续工作#
OvPhysX 仍处于实验阶段,因此上方功能列表有意采用保守表述。更广泛的功能支持和文档完善工作记录在 issue #5634 中。
架构背景见 后端架构 。
访问原生接口#
基本概念#
OvPhysX 暴露通用的 TensorBinding 对象。一个绑定将 prim 选择与已安装的一种 TensorType 结合,并不是某个资源专用的原生存储对象。调用方通过 read() 显式将值读入自己的缓冲区,再通过 write() 将缓冲区写回。Isaac Lab 可以选择使用 OvPhysxView 包装这些绑定,提供以字符串为键、带检查的便捷接口。
生命周期前提#
仅在 OvPhysX 仿真完成初始化和重置、原生运行时已就绪后创建绑定。重新加载 USD 舞台、重建舞台或运行时的重置流程,以及管理器清理,都会使所有已有绑定和视图失效,之后需要重新获取。
满足生命周期前提后,从管理器获取当前 OvPhysX 句柄:
from isaaclab_ov.physics import OvPhysxManager
physx = OvPhysxManager.get_physx_instance()
if physx is None:
raise RuntimeError("OvPhysX has not been constructed; initialize and reset the simulation first.")
句柄非 None 只说明管理器已构建 OvPhysX 实例,并不表示当前仿真上下文已经就绪。管理器清理时会释放实例并清空句柄。访问前先初始化并重置当前上下文,创建新绑定或视图前始终重新获取句柄。
复用 Isaac Lab 持有的访问对象#
如果选择符合需要,复用 Isaac Lab 资源已经持有的便捷视图:
object_view = scene["object"].root_view
poses = object_view.get_attribute("rigid_body_pose")
创建底层访问#
所需选择尚未由 Isaac Lab 资源持有时,创建原始绑定。以下示例位姿绑定使用 float32 和仿真设备,并不是适用于所有张量类型的通用分配器:
import warp as wp
from isaaclab.physics import PhysicsManager
from ovphysx.types import TensorType
binding = physx.create_tensor_binding(
pattern="/World/envs/env_*/Object",
tensor_type=TensorType.RIGID_BODY_POSE,
)
try:
poses = wp.empty(
tuple(binding.shape),
dtype=wp.float32,
device=PhysicsManager.get_device(),
)
binding.read(poses)
binding.write(poses)
finally:
binding.destroy()
分配缓冲区前,检查 binding.shape 、 binding.dtype 、绑定数量和路径元数据。必须精确匹配绑定形状与 DLPack 标量元数据,并遵守原生设备和访问模式要求。 RIGID_BODY_POSE 使用上方的 float32 布局,但其他张量类型的数据类型、形状、原生设备或写入权限可能不同。
对于新选择,使用原生运行时和 Tensor API 模式构建 OvPhysxView :
from isaaclab.physics import PhysicsManager
from isaaclab_ov.sim.views import OvPhysxView
view = OvPhysxView(
physx,
pattern="/World/envs/env_*/Object",
device=PhysicsManager.get_device(),
)
try:
if view.try_binding_for("rigid_body_pose") is not None:
poses = view.get_attribute("rigid_body_pose")
view.set_attribute("rigid_body_pose", poses)
view.read_into("rigid_body_pose", poses)
finally:
view.close()
try_binding_for 尝试为该选择创建绑定,没有有效类型时返回 None 。 binding_for 返回原始绑定,会绕过视图的设备、数据类型、形状和只读检查。
读写语义#
原始 binding.read(buffer) 将值读入调用方持有的缓冲区, binding.write(buffer) 则将值写入仿真。仅修改本地缓冲区不会改变仿真。带检查的 get_attribute() 、 read_into() 和 set_attribute() 具有相同的读取与写回边界,同时验证绑定形状、标量数据类型、原生设备和写入权限。
所有权、同步与失效#
在绑定要求的设备上分配缓冲区,并匹配其形状与 DLPack 标量元数据。状态张量通常使用仿真设备,部分属性张量则仅支持 CPU。 OvPhysxView 验证这些要求,并可将受支持的平坦标量布局重新解释为结构化 Warp 值,但不会在 CPU 与 GPU 之间移动数据。
如果某个张量类型可能不适用于选定 prim,请使用 try_binding_for 。重置流程重建舞台或运行时之后,以及清理之后,应重新获取原始绑定和便捷视图。不再需要时,应销毁原始绑定并关闭自定义视图。管理器清理会先关闭已跟踪的 OvPhysxView 实例,再释放运行时;显式清理可以避免在长时间运行的仿真中一直保留这些绑定。