Commit 799a4f7f authored by nv-mhaselton's avatar nv-mhaselton Committed by Kelly Guo

Adds Headless XR support and Centralize XR-specific Settings (#278)

Adds headless XR support to Isaac Lab and refactors the AppLauncher:
* Fixed headless XR rendering with Kit XR's OpenXR extension
* Automatically enables AR mode when running headless
* Centralized XR-specific settings from code to Kit app configuration
files
* Added new `isaaclab.python.xr.openxr.headless.kit` configuration file
* Introduced `--xr` flag in AppLauncher for explicit XR mode control
(also supports `XR=1` environment variable)
* Device resolution for XR should default to CPU unless overridden
* In a separate commit, the AppLauncher configuration resolution is
broken down to resolve the flake8 C901 complexity violation

<!-- As you go through the list, delete the ones that are not
applicable. -->

- New feature (non-breaking change which adds functionality)

Please attach before and after screenshots of the change if applicable.

<!--
Example:

| Before | After |
| ------ | ----- |
| _gif/png before_ | _gif/png after_ |

To upload images to a PR -- simply drag and drop an image while in edit
mode and it should upload the image directly. You can then paste that
source into the above before/after sections.
-->

- [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with
`./isaaclab.sh --format`
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] I have updated the changelog and the corresponding version in the
extension's `config/extension.toml` file
- [x] I have added my name to the `CONTRIBUTORS.md` or my name already
exists there

<!--
As you go through the checklist above, you can mark something as done by
putting an x character in it

For example,
- [x] I have done this task
- [ ] I have not done this task
-->
parent 1c88446c
##
# Adapted from: apps/isaaclab.python.xr.openxr.kit
##
[package]
title = "Isaac Lab Python OpenXR Headless"
description = "An app for running Isaac Lab with OpenXR in headless mode"
version = "2.0.0"
# That makes it browsable in UI with "experience" filter
keywords = ["experience", "app", "usd", "headless"]
[settings]
# Note: This path was adapted to be respective to the kit-exe file location
app.versionFile = "${exe-path}/VERSION"
app.folder = "${exe-path}/"
app.name = "Isaac-Sim"
app.version = "4.5.0"
[dependencies]
"isaaclab.python.xr.openxr" = {}
[settings]
xr.profile.ar.enabled = true
# Register extension folder from this repo in kit
[settings.app.exts]
folders = [
"${exe-path}/exts", # kit extensions
"${exe-path}/extscore", # kit core extensions
"${exe-path}/../exts", # isaac extensions
"${exe-path}/../extsDeprecated", # deprecated isaac extensions
"${exe-path}/../extscache", # isaac cache extensions
"${exe-path}/../extsPhysics", # isaac physics extensions
"${exe-path}/../isaacsim/exts", # isaac extensions for pip
"${exe-path}/../isaacsim/extsDeprecated", # deprecated isaac extensions
"${exe-path}/../isaacsim/extscache", # isaac cache extensions for pip
"${exe-path}/../isaacsim/extsPhysics", # isaac physics extensions for pip
"${app}", # needed to find other app files
"${app}/../source", # needed to find extensions in Isaac Lab
]
...@@ -24,6 +24,7 @@ app.asyncRenderingLowLatency = true ...@@ -24,6 +24,7 @@ app.asyncRenderingLowLatency = true
# For XR, set this back to default "#define OMNI_MAX_DEVICE_GROUP_DEVICE_COUNT 16" # For XR, set this back to default "#define OMNI_MAX_DEVICE_GROUP_DEVICE_COUNT 16"
renderer.multiGpu.maxGpuCount = 16 renderer.multiGpu.maxGpuCount = 16
renderer.gpuEnumeration.glInterop.enabled = true # Allow Kit XR OpenXR to render headless
[dependencies] [dependencies]
"isaaclab.python.rendering" = {} "isaaclab.python.rendering" = {}
...@@ -34,11 +35,14 @@ renderer.multiGpu.maxGpuCount = 16 ...@@ -34,11 +35,14 @@ renderer.multiGpu.maxGpuCount = 16
"omni.kit.xr.profile.ar" = {} "omni.kit.xr.profile.ar" = {}
[settings] [settings]
app.xr.enabled = true
# xr settings # xr settings
xr.ui.enabled = false xr.ui.enabled = false
xrstage.profile.ar.anchorMode = "active camera" xrstage.profile.ar.anchorMode = "active camera"
xr.depth.aov = "GBufferDepth" xr.depth.aov = "GBufferDepth"
defaults.xr.profile.ar.renderQuality = "off" defaults.xr.profile.ar.renderQuality = "off"
rtx.rendermode = "RaytracedLighting"
# Register extension folder from this repo in kit # Register extension folder from this repo in kit
[settings.app.exts] [settings.app.exts]
......
...@@ -8,15 +8,11 @@ ...@@ -8,15 +8,11 @@
"""Launch Isaac Sim Simulator first.""" """Launch Isaac Sim Simulator first."""
import argparse import argparse
import os
from isaaclab.app import AppLauncher from isaaclab.app import AppLauncher
# add argparse arguments # add argparse arguments
parser = argparse.ArgumentParser(description="Keyboard teleoperation for Isaac Lab environments.") parser = argparse.ArgumentParser(description="Keyboard teleoperation for Isaac Lab environments.")
parser.add_argument(
"--disable_fabric", action="store_true", default=False, help="Disable fabric and use USD I/O operations."
)
parser.add_argument("--num_envs", type=int, default=1, help="Number of environments to simulate.") parser.add_argument("--num_envs", type=int, default=1, help="Number of environments to simulate.")
parser.add_argument("--teleop_device", type=str, default="keyboard", help="Device for interacting with environment") parser.add_argument("--teleop_device", type=str, default="keyboard", help="Device for interacting with environment")
parser.add_argument("--task", type=str, default=None, help="Name of the task.") parser.add_argument("--task", type=str, default=None, help="Name of the task.")
...@@ -28,7 +24,7 @@ args_cli = parser.parse_args() ...@@ -28,7 +24,7 @@ args_cli = parser.parse_args()
app_launcher_args = vars(args_cli) app_launcher_args = vars(args_cli)
if args_cli.teleop_device.lower() == "handtracking": if args_cli.teleop_device.lower() == "handtracking":
app_launcher_args["experience"] = f'{os.environ["ISAACLAB_PATH"]}/apps/isaaclab.python.xr.openxr.kit' app_launcher_args["xr"] = True
# launch omniverse app # launch omniverse app
app_launcher = AppLauncher(app_launcher_args) app_launcher = AppLauncher(app_launcher_args)
simulation_app = app_launcher.app simulation_app = app_launcher.app
...@@ -69,9 +65,7 @@ def pre_process_actions(delta_pose: torch.Tensor, gripper_command: bool) -> torc ...@@ -69,9 +65,7 @@ def pre_process_actions(delta_pose: torch.Tensor, gripper_command: bool) -> torc
def main(): def main():
"""Running keyboard teleoperation with Isaac Lab manipulation environment.""" """Running keyboard teleoperation with Isaac Lab manipulation environment."""
# parse configuration # parse configuration
env_cfg = parse_env_cfg( env_cfg = parse_env_cfg(args_cli.task, device=args_cli.device, num_envs=args_cli.num_envs)
args_cli.task, device=args_cli.device, num_envs=args_cli.num_envs, use_fabric=not args_cli.disable_fabric
)
# modify configuration # modify configuration
env_cfg.terminations.time_out = None env_cfg.terminations.time_out = None
if "Lift" in args_cli.task: if "Lift" in args_cli.task:
......
...@@ -51,11 +51,12 @@ AppLauncher.add_app_launcher_args(parser) ...@@ -51,11 +51,12 @@ AppLauncher.add_app_launcher_args(parser)
# parse the arguments # parse the arguments
args_cli = parser.parse_args() args_cli = parser.parse_args()
app_launcher_args = vars(args_cli)
if args_cli.teleop_device.lower() == "handtracking": if args_cli.teleop_device.lower() == "handtracking":
vars(args_cli)["experience"] = f'{os.environ["ISAACLAB_PATH"]}/apps/isaaclab.python.xr.openxr.kit' app_launcher_args["xr"] = True
# launch the simulator # launch the simulator
app_launcher = AppLauncher(args_cli) app_launcher = AppLauncher(app_launcher_args)
simulation_app = app_launcher.app simulation_app = app_launcher.app
"""Rest everything follows.""" """Rest everything follows."""
......
...@@ -248,10 +248,15 @@ class AppLauncher: ...@@ -248,10 +248,15 @@ class AppLauncher:
default=AppLauncher._APPLAUNCHER_CFG_INFO["enable_cameras"][1], default=AppLauncher._APPLAUNCHER_CFG_INFO["enable_cameras"][1],
help="Enable camera sensors and relevant extension dependencies.", help="Enable camera sensors and relevant extension dependencies.",
) )
arg_group.add_argument(
"--xr",
action="store_true",
default=AppLauncher._APPLAUNCHER_CFG_INFO["xr"][1],
help="Enable XR mode for VR/AR applications.",
)
arg_group.add_argument( arg_group.add_argument(
"--device", "--device",
type=str, type=str,
default=AppLauncher._APPLAUNCHER_CFG_INFO["device"][1],
help='The device to run the simulation on. Can be "cpu", "cuda", "cuda:N", where N is the device ID', help='The device to run the simulation on. Can be "cpu", "cuda", "cuda:N", where N is the device ID',
) )
# Add the deprecated cpu flag to raise an error if it is used # Add the deprecated cpu flag to raise an error if it is used
...@@ -300,6 +305,7 @@ class AppLauncher: ...@@ -300,6 +305,7 @@ class AppLauncher:
"headless": ([bool], False), "headless": ([bool], False),
"livestream": ([int], -1), "livestream": ([int], -1),
"enable_cameras": ([bool], False), "enable_cameras": ([bool], False),
"xr": ([bool], False),
"device": ([str], "cuda:0"), "device": ([str], "cuda:0"),
"experience": ([str], ""), "experience": ([str], ""),
} }
...@@ -396,10 +402,31 @@ class AppLauncher: ...@@ -396,10 +402,31 @@ class AppLauncher:
Args: Args:
launcher_args: A dictionary of all input arguments passed to the class object. launcher_args: A dictionary of all input arguments passed to the class object.
""" """
# Handle all control logic resolution # Handle core settings
livestream_arg, livestream_env = self._resolve_livestream_settings(launcher_args)
self._resolve_headless_settings(launcher_args, livestream_arg, livestream_env)
self._resolve_camera_settings(launcher_args)
self._resolve_xr_settings(launcher_args)
self._resolve_viewport_settings(launcher_args)
# --LIVESTREAM logic-- # Handle device and distributed settings
# self._resolve_device_settings(launcher_args)
# Handle experience file settings
self._resolve_experience_file(launcher_args)
# Handle additional arguments
self._resolve_kit_args(launcher_args)
# Prepare final simulation app config
# Remove all values from input keyword args which are not meant for SimulationApp
# Assign all the passed settings to a dictionary for the simulation app
self._sim_app_config = {
key: launcher_args[key] for key in set(AppLauncher._SIM_APP_CFG_TYPES.keys()) & set(launcher_args.keys())
}
def _resolve_livestream_settings(self, launcher_args: dict) -> tuple[int, int]:
"""Resolve livestream related settings."""
livestream_env = int(os.environ.get("LIVESTREAM", 0)) livestream_env = int(os.environ.get("LIVESTREAM", 0))
livestream_arg = launcher_args.pop("livestream", AppLauncher._APPLAUNCHER_CFG_INFO["livestream"][1]) livestream_arg = launcher_args.pop("livestream", AppLauncher._APPLAUNCHER_CFG_INFO["livestream"][1])
livestream_valid_vals = {0, 1, 2} livestream_valid_vals = {0, 1, 2}
...@@ -426,8 +453,38 @@ class AppLauncher: ...@@ -426,8 +453,38 @@ class AppLauncher:
else: else:
self._livestream = livestream_env self._livestream = livestream_env
# --HEADLESS logic-- # Process livestream here before launching kit because some of the extensions only work when launched with the kit file
# self._livestream_args = []
if self._livestream >= 1:
# Note: Only one livestream extension can be enabled at a time
if self._livestream == 1:
warnings.warn(
"Native Livestream is deprecated. Please use WebRTC Livestream instead with --livestream 2."
)
self._livestream_args += [
'--/app/livestream/proto="ws"',
"--/app/livestream/allowResize=true",
"--enable",
"omni.kit.livestream.core-4.1.2",
"--enable",
"omni.kit.livestream.native-5.0.1",
"--enable",
"omni.kit.streamsdk.plugins-4.1.1",
]
elif self._livestream == 2:
self._livestream_args += [
"--/app/livestream/allowResize=false",
"--enable",
"omni.kit.livestream.webrtc",
]
else:
raise ValueError(f"Invalid value for livestream: {self._livestream}. Expected: 1, 2 .")
sys.argv += self._livestream_args
return livestream_arg, livestream_env
def _resolve_headless_settings(self, launcher_args: dict, livestream_arg: int, livestream_env: int):
"""Resolve headless related settings."""
# Resolve headless execution of simulation app # Resolve headless execution of simulation app
# HEADLESS is initially passed as an int instead of # HEADLESS is initially passed as an int instead of
# the bool of headless_arg to avoid messy string processing, # the bool of headless_arg to avoid messy string processing,
...@@ -463,8 +520,8 @@ class AppLauncher: ...@@ -463,8 +520,8 @@ class AppLauncher:
# Headless needs to be passed to the SimulationApp so we keep it here # Headless needs to be passed to the SimulationApp so we keep it here
launcher_args["headless"] = self._headless launcher_args["headless"] = self._headless
# --enable_cameras logic-- def _resolve_camera_settings(self, launcher_args: dict):
# """Resolve camera related settings."""
enable_cameras_env = int(os.environ.get("ENABLE_CAMERAS", 0)) enable_cameras_env = int(os.environ.get("ENABLE_CAMERAS", 0))
enable_cameras_arg = launcher_args.pop("enable_cameras", AppLauncher._APPLAUNCHER_CFG_INFO["enable_cameras"][1]) enable_cameras_arg = launcher_args.pop("enable_cameras", AppLauncher._APPLAUNCHER_CFG_INFO["enable_cameras"][1])
enable_cameras_valid_vals = {0, 1} enable_cameras_valid_vals = {0, 1}
...@@ -482,6 +539,21 @@ class AppLauncher: ...@@ -482,6 +539,21 @@ class AppLauncher:
if self._enable_cameras and self._headless: if self._enable_cameras and self._headless:
self._offscreen_render = True self._offscreen_render = True
def _resolve_xr_settings(self, launcher_args: dict):
"""Resolve XR related settings."""
xr_env = int(os.environ.get("XR", 0))
xr_arg = launcher_args.pop("xr", AppLauncher._APPLAUNCHER_CFG_INFO["xr"][1])
xr_valid_vals = {0, 1}
if xr_env not in xr_valid_vals:
raise ValueError(f"Invalid value for environment variable `XR`: {xr_env} .Expected: {xr_valid_vals} .")
# We allow xr kwarg to supersede XR envvar
if xr_arg is True:
self._xr = xr_arg
else:
self._xr = bool(xr_env)
def _resolve_viewport_settings(self, launcher_args: dict):
"""Resolve viewport related settings."""
# Check if we can disable the viewport to improve performance # Check if we can disable the viewport to improve performance
# This should only happen if we are running headless and do not require livestreaming or video recording # This should only happen if we are running headless and do not require livestreaming or video recording
# This is different from offscreen_render because this only affects the default viewport and not other renderproducts in the scene # This is different from offscreen_render because this only affects the default viewport and not other renderproducts in the scene
...@@ -497,14 +569,20 @@ class AppLauncher: ...@@ -497,14 +569,20 @@ class AppLauncher:
# avoid creating new stage at startup by default for performance reasons # avoid creating new stage at startup by default for performance reasons
launcher_args["create_new_stage"] = False launcher_args["create_new_stage"] = False
# --simulation GPU device logic -- def _resolve_device_settings(self, launcher_args: dict):
"""Resolve simulation GPU device related settings."""
self.device_id = 0 self.device_id = 0
device = launcher_args.get("device", AppLauncher._APPLAUNCHER_CFG_INFO["device"][1]) device = launcher_args.get("device")
if device is None:
# If no device is specified, default to the GPU device if we are not running in XR
device = "cpu" if self._xr else AppLauncher._APPLAUNCHER_CFG_INFO["device"][1]
if "cuda" not in device and "cpu" not in device: if "cuda" not in device and "cpu" not in device:
raise ValueError( raise ValueError(
f"Invalid value for input keyword argument `device`: {device}." f"Invalid value for input keyword argument `device`: {device}."
" Expected: a string with the format 'cuda', 'cuda:<device_id>', or 'cpu'." " Expected: a string with the format 'cuda', 'cuda:<device_id>', or 'cpu'."
) )
if "cuda:" in device: if "cuda:" in device:
self.device_id = int(device.split(":")[-1]) self.device_id = int(device.split(":")[-1])
...@@ -534,6 +612,10 @@ class AppLauncher: ...@@ -534,6 +612,10 @@ class AppLauncher:
launcher_args["physics_gpu"] = self.device_id launcher_args["physics_gpu"] = self.device_id
launcher_args["active_gpu"] = self.device_id launcher_args["active_gpu"] = self.device_id
print(f"[INFO][AppLauncher]: Using device: {device}")
def _resolve_experience_file(self, launcher_args: dict):
"""Resolve experience file related settings."""
# Check if input keywords contain an 'experience' file setting # Check if input keywords contain an 'experience' file setting
# Note: since experience is taken as a separate argument by Simulation App, we store it separately # Note: since experience is taken as a separate argument by Simulation App, we store it separately
self._sim_experience_file = launcher_args.pop("experience", "") self._sim_experience_file = launcher_args.pop("experience", "")
...@@ -550,6 +632,13 @@ class AppLauncher: ...@@ -550,6 +632,13 @@ class AppLauncher:
) )
else: else:
self._sim_experience_file = os.path.join(isaaclab_app_exp_path, "isaaclab.python.rendering.kit") self._sim_experience_file = os.path.join(isaaclab_app_exp_path, "isaaclab.python.rendering.kit")
elif self._xr:
if self._headless:
self._sim_experience_file = os.path.join(
isaaclab_app_exp_path, "isaaclab.python.xr.openxr.headless.kit"
)
else:
self._sim_experience_file = os.path.join(isaaclab_app_exp_path, "isaaclab.python.xr.openxr.kit")
elif self._headless and not self._livestream: elif self._headless and not self._livestream:
self._sim_experience_file = os.path.join(isaaclab_app_exp_path, "isaaclab.python.headless.kit") self._sim_experience_file = os.path.join(isaaclab_app_exp_path, "isaaclab.python.headless.kit")
else: else:
...@@ -605,22 +694,18 @@ class AppLauncher: ...@@ -605,22 +694,18 @@ class AppLauncher:
else: else:
raise ValueError(f"Invalid value for livestream: {self._livestream}. Expected: 1, 2 .") raise ValueError(f"Invalid value for livestream: {self._livestream}. Expected: 1, 2 .")
sys.argv += self._livestream_args sys.argv += self._livestream_args
# Resolve the absolute path of the experience file
self._sim_experience_file = os.path.abspath(self._sim_experience_file)
print(f"[INFO][AppLauncher]: Loading experience file: {self._sim_experience_file}")
def _resolve_kit_args(self, launcher_args: dict):
"""Resolve additional arguments passed to Kit."""
# Resolve additional arguments passed to Kit # Resolve additional arguments passed to Kit
self._kit_args = [] self._kit_args = []
if "kit_args" in launcher_args: if "kit_args" in launcher_args:
self._kit_args = [arg for arg in launcher_args["kit_args"].split()] self._kit_args = [arg for arg in launcher_args["kit_args"].split()]
sys.argv += self._kit_args sys.argv += self._kit_args
# Resolve the absolute path of the experience file
self._sim_experience_file = os.path.abspath(self._sim_experience_file)
print(f"[INFO][AppLauncher]: Loading experience file: {self._sim_experience_file}")
# Remove all values from input keyword args which are not meant for SimulationApp
# Assign all the passed settings to a dictionary for the simulation app
self._sim_app_config = {
key: launcher_args[key] for key in set(AppLauncher._SIM_APP_CFG_TYPES.keys()) & set(launcher_args.keys())
}
def _create_app(self): def _create_app(self):
"""Launch and create the SimulationApp based on the parsed simulation config.""" """Launch and create the SimulationApp based on the parsed simulation config."""
# Initialize SimulationApp # Initialize SimulationApp
...@@ -659,7 +744,7 @@ class AppLauncher: ...@@ -659,7 +744,7 @@ class AppLauncher:
"""Check if rendering is required by the app.""" """Check if rendering is required by the app."""
# Indicates whether rendering is required by the app. # Indicates whether rendering is required by the app.
# Extensions required for rendering bring startup and simulation costs, so we do not enable them if not required. # Extensions required for rendering bring startup and simulation costs, so we do not enable them if not required.
return not self._headless or self._livestream >= 1 or self._enable_cameras return not self._headless or self._livestream >= 1 or self._enable_cameras or self._xr
def _load_extensions(self): def _load_extensions(self):
"""Load correct extensions based on AppLauncher's resolved config member variables.""" """Load correct extensions based on AppLauncher's resolved config member variables."""
......
...@@ -11,7 +11,6 @@ from scipy.spatial.transform import Rotation, Slerp ...@@ -11,7 +11,6 @@ from scipy.spatial.transform import Rotation, Slerp
from typing import Final from typing import Final
import carb import carb
from omni.kit.viewport.utility import get_active_viewport
from ..device_base import DeviceBase from ..device_base import DeviceBase
...@@ -83,11 +82,6 @@ class Se3HandTracking(DeviceBase): ...@@ -83,11 +82,6 @@ class Se3HandTracking(DeviceBase):
self._alpha_rot = 0.5 self._alpha_rot = 0.5
self._smoothed_delta_pos = np.zeros(3) self._smoothed_delta_pos = np.zeros(3)
self._smoothed_delta_rot = np.zeros(3) self._smoothed_delta_rot = np.zeros(3)
# Set the XR anchormode to active camera
carb.settings.get_settings().set_string("/xrstage/profile/ar/anchorMode", "active camera")
# Select RTX - RealTime for Renderer
viewport_api = get_active_viewport()
viewport_api.set_hd_engine("rtx", "RaytracedLighting")
self._delta_pos_scale_factor = delta_pos_scale_factor self._delta_pos_scale_factor = delta_pos_scale_factor
self._delta_rot_scale_factor = delta_rot_scale_factor self._delta_rot_scale_factor = delta_rot_scale_factor
self._frame_marker_cfg = FRAME_MARKER_CFG.copy() self._frame_marker_cfg = FRAME_MARKER_CFG.copy()
......
...@@ -154,6 +154,8 @@ class SimulationContext(_SimulationContext): ...@@ -154,6 +154,8 @@ class SimulationContext(_SimulationContext):
self._local_gui = carb_settings_iface.get("/app/window/enabled") self._local_gui = carb_settings_iface.get("/app/window/enabled")
# read flag for whether livestreaming GUI is enabled # read flag for whether livestreaming GUI is enabled
self._livestream_gui = carb_settings_iface.get("/app/livestream/enabled") self._livestream_gui = carb_settings_iface.get("/app/livestream/enabled")
# read flag for whether XR GUI is enabled
self._xr_gui = carb_settings_iface.get("/app/xr/enabled")
# read flag for whether the Isaac Lab viewport capture pipeline will be used, # read flag for whether the Isaac Lab viewport capture pipeline will be used,
# casting None to False if the flag doesn't exist # casting None to False if the flag doesn't exist
...@@ -162,7 +164,7 @@ class SimulationContext(_SimulationContext): ...@@ -162,7 +164,7 @@ class SimulationContext(_SimulationContext):
# read flag for whether the default viewport should be enabled # read flag for whether the default viewport should be enabled
self._render_viewport = bool(carb_settings_iface.get("/isaaclab/render/active_viewport")) self._render_viewport = bool(carb_settings_iface.get("/isaaclab/render/active_viewport"))
# flag for whether any GUI will be rendered (local, livestreamed or viewport) # flag for whether any GUI will be rendered (local, livestreamed or viewport)
self._has_gui = self._local_gui or self._livestream_gui self._has_gui = self._local_gui or self._livestream_gui or self._xr_gui
# apply render settings from render config # apply render settings from render config
if self.cfg.render.enable_translucency is not None: if self.cfg.render.enable_translucency is not None:
...@@ -193,6 +195,8 @@ class SimulationContext(_SimulationContext): ...@@ -193,6 +195,8 @@ class SimulationContext(_SimulationContext):
import omni.replicator.core as rep import omni.replicator.core as rep
rep.settings.set_render_rtx_realtime(antialiasing=self.cfg.render.antialiasing_mode) rep.settings.set_render_rtx_realtime(antialiasing=self.cfg.render.antialiasing_mode)
# WAR: The omni.replicator.core extension sets /rtx/renderMode=RayTracedLighting with incorrect casing.
carb_settings_iface.set("/rtx/rendermode", "RaytracedLighting")
except Exception: except Exception:
pass pass
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment