场景数据提供器#
SceneDataProvider 向渲染器和可视化器提供刚体变换及可视几何。它从当前物理后端读取数据,按需转换 Warp 数组或调整其顺序。开发渲染器、可视化器或其他场景变换与几何数据使用者时,可使用此接口;任务代码通常通过资产和传感器 API 读取状态。
概述#
物理管理器通过 SceneDataBackend 暴露原生数据。从仿真上下文获取提供器:
from isaaclab.sim import SimulationContext
# The SimulationContext owns the active provider; consumers fetch it instead of
# constructing one directly.
provider = SimulationContext.instance().get_scene_data_provider()
架构#
数据流#
系统有三层:
SceneDataBackend:各物理管理器实现的小型接口。它将后端变换数组直接作为SceneDataFormat中的一种 Warp 结构提供,同时给出每个变换的 prim 路径和总数。原生状态写入或缓冲区交换后,数据生产者递增transforms_timestamp。SDP 在读取时间戳前调用get_transforms(output_format),因为解析指针本身可能检测到交换。默认实现返回已有的transforms属性。这是逻辑发布时间戳,不是经过的时间,在后端生命周期内不会重置,因此独立读取器不会相互掩盖变化。SceneDataBackend.transforms:Warp 结构形式的原生数据(SceneDataFormat.Vec3_Quat、SceneDataFormat.Transform、SceneDataFormat.Matrix44或SceneDataFormat.Vec3_Matrix33)。SceneDataBackend.transforms_timestamp:原生变换的逻辑更新时间戳。SceneDataBackend.transform_count:变换数量。SceneDataBackend.transform_paths:USD prim 路径列表,每个变换对应一个路径。SceneDataBackend.native_transform_formats:无需转换即可提供的格式。PhysX 提供打包位姿或 Fabric 矩阵,只刷新请求的表示形式。SceneDataBackend.get_geometry_batches():原生点数组或插值输入,配对后端构建时编译得到的精确可视 prim 路径和范围。请求的原生表示可用时直接返回,否则返回主要表示,由 SDP 转换。返回类型始终为批次列表,包括原生 Fabric 情况。SceneDataBackend.geometry_timestamp:逻辑更新时间戳,同一步内的写入和原生指针交换都会推进它。与资产数据缓冲区一样,缓存输出记录其所包含数据的时间戳。这不是已过的仿真时间,也不是由某个读取器清除的共享脏标志。SceneDataBackend.native_geometry_formats:无需转换即可获得的几何格式。
SceneDataProvider:包装后端,提供格式转换和索引重新映射。SceneDataProvider.get_transforms():格式与顺序匹配时绑定原生数组,否则绑定 SDP 管理的缓冲区;对每个生产者时间戳和目标布局只转换一次。这些共享数组只读,即使它们替换了预分配的输出字段。传入allow_passthrough=False,则直接写入调用方管理的数组。SceneDataProvider.create_mapping():构建从后端 prim 路径到使用者期望顺序的重映射数组。当渲染器或可视化器希望按自己的刚体列表、而非物理视图顺序索引变换时使用。SceneDataProvider.get_geometry_points():按精确可视 prim 路径索引的只读世界空间点视图。原生点范围直接引用生产者数据;插值与目标重排融合为一次缓存转换。使用固定原生存储的使用者,将该数组或FabricPoints作为output,将可视路径偏移作为offsets传入。调用返回所提供的目标。目标缓存保留索引元数据,不保留使用者缓冲区,并随目标释放而失效。SceneDataProvider.get_camera_transforms():从 USD 舞台发现各相机、各环境的世界变换。SceneDataProvider.num_envs:从/World/envs/env_<id>prim 推断的环境数量。
后端实现:
PhysxSceneDataBackend(位于isaaclab_physx.physics内部)包装 PhysX 的RigidBodyView,以SceneDataFormat.Transform提供变换。存在可变形物体时,还通过SceneDataFormat.Points提供展平的仿真节点位置。OvPhysxSceneDataBackend(位于isaaclab_ov.physics内部)对刚体变换和 OVPhysX 可变形节点张量采用与 PhysX 相同的约定。NewtonSceneDataBackend(位于isaaclab_newton.physics内部)包装 Newton 模型的body_q,以SceneDataFormat.Transform提供。
PhysX 后端#
使用 PhysX 物理后端时,提供器直接从 PhysX 的 RigidBodyView 读取变换,这是一个经通配符展开、覆盖所有环境中全部刚体的张量视图。变换以 SceneDataFormat.Transform (Warp transformf 数组)返回,因此需要这种格式的使用者可零拷贝获取数据。
Newton 可视化器、Rerun、Viser 和 Newton Warp 渲染器还需要 Newton Model/State,由各自的克隆上下文在初始化前构建。其中刚体的 body_q 直接绑定到 SDP 的 Transform 数组,无需中间拷贝。OVRTX 直接请求 TransposedMatrix44d,并在同一次转换中处理顺序和缩放。
对于仿真网格与可视网格分离的可变形体,数据生产者只计算一次重心插值索引与权重。SDP 直接将插值结果写入 Newton 表示的 particle_q 对应位置,并借用带填充的 PhysX 节点数组,无需重新打包;使用者也不需要中间缓冲区或重映射。
OVRTX 通过 SDP 接收同样的精确可视路径数据。它不导入 Newton 管理器,也不请求 Newton 模型。网格、粒子云和线缆曲线使用统一的点绑定路径。
PhysX 通过 SDP 直接发布原生 Fabric 矩阵,无需获取打包后的位姿。isaaclab_physx.renderers.fabric.FabricBackend 持有舞台和层级句柄,以舞台及设备为键。物理初始化后,Kit、Isaac RTX 和显式 Fabric 同步通过 sim.get_or_create_backend(FabricBackendCfg(stage=sim.stage, device=sim.device)) 共用该资源。
使用者向 update_transforms(provider) 传入仿真的 SDP。对于其他物理后端,该方法将位姿转换为 Fabric 局部矩阵,并更新 GPU 层级。变换绑定归此资源所有,RenderContext 不持有绑定。由于物理后端提供绝对位姿,刚体目标使用仅存在于 Fabric 中的变换栈重置根节点;可视子节点仍继承所属刚体的变换,USD 不变。
源索引和世界缩放仅绑定一次。Fabric 报告结构变化时,资源会刷新数组视图,而不重复路径匹配或缩放捕获;否则直接复用层级。请求未变化时不会获取可写 Fabric 数组。无论物理后端为何,渲染器均使用这条数据通路。
update_geometries(provider, frame) 处理几何。PhysX 直接发布原生 FabricPoints,其他后端则将插值后的网格顶点写入 GPU Fabric 存储。Kit Hydra 要求 Points 和 BasisCurves 的目标位于 CPU,因此 SDP 会在更新间隔到达时传输这些数据,而不写入 USD。世界坐标中的点会重置变换栈,避免重复应用刚体或环境位姿。FabricMatrix44 和 FabricPoints 仅保存数组,不持有绑定或引擎句柄。
Newton 后端#
使用 Newton 物理后端时,后端直接包装 Newton 模型的 body_q 。无需影子模型或逐帧同步:Newton 已管理权威模型和状态,提供器将该状态以 SceneDataFormat.Transform 暴露。
原生读取会统一处理待生效的状态写入,只执行一次。新的物理数据发布本身不要求执行正向运动学。Kit/RTX 在渲染前通过 SDP 请求当前 Fabric 变换,无需额外调用物理 forward() 。无界面视口采集按需请求这些变换,而非每个可视化器步都请求。
外部回放的 CUDA 图不会调用 Python 写入钩子。写入被捕获后,Newton 会在读取时保守地重新发布变换,避免未通知的回放使渲染数据过时。这类读取无法利用未变化数据的发布缓存。
几何数据发布#
Newton 可变形物体和 MPM 的位置是原生 particle_q 范围的直接视图。线缆数据借用原生刚体位姿和胶囊体参数,SDP 对每个更新时间戳只计算一次曲线端点。相机渲染器和查看器使用同一缓存结果。
ClonePlan 始终是通用的复制与分发描述。资产构造时编写原型几何,原生导入将这些原型与计划组合,并记录原生范围。使用者绑定到这些已完成的资源,不会再次遍历已完成的舞台进行发现。
# Default: read-only native or converted views, cached by producer timestamp.
points_by_path = provider.get_geometry_points()
# A consumer with fixed native storage receives the conversion directly.
provider.get_geometry_points(output=state.particle_q, offsets=visual_path_offsets)
# A Fabric consumer supplies native storage and its exact visual-path row indices.
provider.get_geometry_points(output=fabric_points, offsets=visual_path_rows)
内部的展平节点查询和由物理管理的几何同步方法已移除。渲染使用者改用 get_geometry_points ;物理管理器不再从 pre_render 运行几何写入器。
变换转换缓存使用 TimestampedBuffer ,与资产数据使用相同的数据/时间戳容器。仅在需要转换时分配存储,转换成功后才确认数据已更新。匹配的原生格式仍直接传递,不分配存储。即使物理状态未变,更换 Fabric 目标也会使缓存绑定失效。
与关节体和刚体物体数据一样,当前时间戳与缓存缓冲区时间戳用途不同:一个标识当前状态,另一个标识缓冲区中的状态。资产数据随时间推进 _sim_timestamp ,并在同一步内写入时使依赖缓冲区失效。SDP 则在这些写入时推进 geometry_timestamp ,使独立更新的使用者都能看到变化。输出缓存负责自身的新鲜度检查;下游上传或 BVH 可能需要自己的失效机制,但不应重复管理转换缓存的状态。
惰性读取约定#
使用 TimestampedBuffer 将缓存数据与最近一次成功更新的时间戳配对。存储由数据所有者分配,容器本身不分配或转换数据。同一步内的写入通过 reset_timestamps 使受影响的资产缓存失效,并推进 SDP 的发布时间戳。请求数据后,各使用者比较自己的时间戳,因为解析原生指针本身也可能发现变化。只跟踪上传操作的使用者只需时间戳,无需再保存一份 SDP 数据引用。
SDP 读取器采用与资产数据相同的时间戳检查机制,缓存缓冲区和映射数据,不使用绑定工厂或存储的更新回调。匹配的原生数组绕过转换。调用方管理的目标仅通过弱引用保存,因此调用方释放目标后,其缓存映射也会失效。
待执行工作由其执行者管理。Newton 的 forward() 和 PhysX/OVPhysX 的 update_kinematics() 在内部检查 kinematics_dirty ,成功后清除;读取器直接调用操作,无需检查该标志。重排后的关节体视图仍会刷新自身的派生数组。传感器和 Newton 共享 BVH 同样使用脏标志,设备掩码选择需要处理的环境。应保留即时接触读取,以检测接触消失。
采样周期和有限差分使用仿真时间 [s];Fabric 几何更新周期使用渲染帧数。两者都不是发布计数器。CUDA 图回放时不会执行 Python 条件检查,因此捕获的工作必须保留在图中,或使用设备端失效机制。Newton 保留选择性重置掩码,并在外部回放写入后采用保守读取。
数据需求#
可视化器和渲染器声明自己需要的场景数据。在构造使用者时、共享克隆计划构建前,就会确定这些需求:
组件 |
需要 Newton 模型 |
需要 USD 舞台 |
|---|---|---|
Kit 可视化器 |
No |
Yes |
Newton 可视化工具 |
Yes |
No |
Rerun 可视化器 |
Yes |
No |
Viser 可视化器 |
Yes |
No |
Isaac RTX 渲染器 |
No |
Yes |
Newton Warp 渲染器 |
Yes |
No |
OVRTX 渲染器 |
No |
Yes |