录制模拟动画

录制模拟动画#

Omniverse包括工具来记录物理模拟的动画。 Stage Recorder 扩展监听USD阶段中的所有运动和USD属性变化,并将它们记录到USD文件中。该文件包含更改的时间样本,可以回放以渲染动画。

timeSampled USD文件只包含阶段的更改。它使用录制时原始阶段相同的层次结构。这允许将动画添加到原始阶段,或者添加到具有相同层次结构的不同阶段。timeSampled文件可以直接添加为原始阶段的子层,以回放动画。

备注

Omniverse只支持同时在USD基元上播放动画或播放物理。如果要回放USD基元的动画,需要在该基元上禁用物理模拟。

在Isaac Lab中,我们直接使用 Stage Recorder 扩展来记录物理模拟的动画。这作为 BaseEnvWindow 类的一个功能可用。但是,要记录模拟的动画,需要禁用 Fabric 以允许读取和写入所有更改(如运动和USD属性)到USD阶段。

Stage Recorder设置#

Isaac Lab集成了 Stage Recorder 扩展,假设了某些默认设置。如果要更改设置,可以直接在Omniverse Create应用程序中使用 Stage Recorder 扩展。

在base_env_window.py中使用的设置
 1    def _toggle_recording_animation_fn(self, value: bool):
 2        """Toggles the animation recording."""
 3        if value:
 4            # log directory to save the recording
 5            if not hasattr(self, "animation_log_dir"):
 6                # create a new log directory
 7                log_dir = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
 8                self.animation_log_dir = os.path.join(os.getcwd(), "recordings", log_dir)
 9            # start the recording
10            _ = omni.kit.commands.execute(
11                "StartRecording",
12                target_paths=[("/World", True)],
13                live_mode=True,
14                use_frame_range=False,
15                start_frame=0,
16                end_frame=0,
17                use_preroll=False,
18                preroll_frame=0,
19                record_to="FILE",
20                fps=0,
21                apply_root_anim=False,
22                increment_name=True,
23                record_folder=self.animation_log_dir,
24                take_name="TimeSample",
25            )
26        else:
27            # stop the recording
28            _ = omni.kit.commands.execute("StopRecording")
29            # save the current stage
30            stage = omni.usd.get_context().get_stage()
31            source_layer = stage.GetRootLayer()
32            # output the stage to a file
33            stage_usd_path = os.path.join(self.animation_log_dir, "Stage.usd")
34            source_prim_path = "/"
35            # creates empty anon layer
36            temp_layer = Sdf.Find(stage_usd_path)
37            if temp_layer is None:
38                temp_layer = Sdf.Layer.CreateNew(stage_usd_path)
39            temp_stage = Usd.Stage.Open(temp_layer)
40            # update stage data
41            UsdGeom.SetStageUpAxis(temp_stage, UsdGeom.GetStageUpAxis(stage))
42            UsdGeom.SetStageMetersPerUnit(temp_stage, UsdGeom.GetStageMetersPerUnit(stage))
43            # copy the prim
44            Sdf.CreatePrimInLayer(temp_layer, source_prim_path)
45            Sdf.CopySpec(source_layer, source_prim_path, temp_layer, source_prim_path)
46            # set the default prim
47            temp_layer.defaultPrim = Sdf.Path(source_prim_path).name
48            # remove all physics from the stage
49            for prim in temp_stage.TraverseAll():
50                # skip if the prim is an instance
51                if prim.IsInstanceable():
52                    continue
53                # if prim has articulation then disable it
54                if prim.HasAPI(UsdPhysics.ArticulationRootAPI):
55                    prim.RemoveAPI(UsdPhysics.ArticulationRootAPI)
56                    prim.RemoveAPI(PhysxSchema.PhysxArticulationAPI)
57                # if prim has rigid body then disable it
58                if prim.HasAPI(UsdPhysics.RigidBodyAPI):
59                    prim.RemoveAPI(UsdPhysics.RigidBodyAPI)
60                    prim.RemoveAPI(PhysxSchema.PhysxRigidBodyAPI)
61                # if prim is a joint type then disable it
62                if prim.IsA(UsdPhysics.Joint):
63                    prim.GetAttribute("physics:jointEnabled").Set(False)
64            # resolve all paths relative to layer path
65            omni.usd.resolve_paths(source_layer.identifier, temp_layer.identifier)
66            # save the stage
67            temp_layer.Save()
68            # print the path to the saved stage
69            print("Recording completed.")
70            print(f"\tSaved recorded stage to    : {stage_usd_path}")
71            print(f"\tSaved recorded animation to: {os.path.join(self.animation_log_dir, 'TimeSample_tk001.usd')}")
72            print("\nTo play the animation, check the instructions in the following link:")
73            print(
74                "\thttps://docs.omniverse.nvidia.com/extensions/latest/ext_animation_stage-recorder.html#using-the-captured-timesamples"
75            )
76            print("\n")
77            # reset the log directory
78            self.animation_log_dir = None

示例用法#

在所有环境独立脚本中,可以通过将 --disable_fabric 标志传递给脚本来禁用Fabric。在这里,我们运行状态机示例并记录模拟的动画。

./isaaclab.sh -p source/standalone/environments/state_machine/lift_cube_sm.py --num_envs 8 --device cpu --disable_fabric

运行脚本时,Isaac Lab UI窗口将打开,并在工具栏中显示”Record Animation”按钮。单击此按钮将开始记录模拟的动画。再次单击按钮,录制停止。记录的动画和原始阶段(所有物理均已禁用)将保存在当前工作目录的 recordings 文件夹中。文件以 usd 格式存储:

  • Stage.usd :所有物理已禁用的原始阶段

  • TimeSample_tk001.usd :包含记录的动画的timeSampled文件

您可以打开Omniverse Isaac Sim应用程序来回放动画。有许多启动应用程序的方法(比如从终端或 Omniverse Launcher )。在这里,我们使用终端来打开应用程序并播放动画。

./isaaclab.sh -s  # Opens Isaac Sim application through _isaac_sim/isaac-sim.sh

在新阶段上,将 Stage.usd 添加为子层,然后将 TimeSample_tk001.usd 添加为子层。您可以通过将文件从文件资源管理器拖放到场景中来执行此操作。有关更多详细信息,请查阅 Omniverse中的分层教程

然后您可以通过按下播放按钮来播放动画。