While migrating to Isaac2023, I noticed that the cloning offsets are not working.
For example, running the clone_ants.py example with a z offset of 5m does not work and the ants are spawned at the ground level anyway.
An easy fix for me was to revert the grid_cloner.py script to the one of Isaac2022 and adding back the new copy_from_source input. This indeed solves the issue.
Didn’t have the time to go through the code though, so I don’t know where exactly the problem is with the new GridCloner.
As a reference, here’s the code I am using for the grid_cloner.py:
# Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. # # NVIDIA CORPORATION and its licensors retain all intellectual property # and proprietary rights in and to this software, related documentation # and any modifications thereto. Any use, reproduction, disclosure or # distribution of this software and related documentation without an express # license agreement from NVIDIA CORPORATION is strictly prohibited. # from typing import List, Union import numpy as np import omni.usd import torch from omni.isaac.cloner import Cloner from pxr import Gf, UsdGeom class GridCloner(Cloner): """ This is a specialized Cloner class that will automatically generate clones in a grid fashion. """ def __init__(self, spacing: float, num_per_row: int = -1): """ Args: spacing (float): Spacing between clones. num_per_row (int): Number of clones to place in a row. Defaults to sqrt(num_clones). """ self._spacing = spacing self._num_per_row = num_per_row Cloner.__init__(self) def clone( self, source_prim_path: str, prim_paths: List[str], position_offsets: np.ndarray = None, orientation_offsets: np.ndarray = None, replicate_physics: bool = False, base_env_path: str = None, root_path: str = None, copy_from_source: bool = False ): """ Creates clones in a grid fashion. Positions of clones are computed automatically. Args: source_prim_path (str): Path of source object. prim_paths (List[str]): List of destination paths. position_offsets (np.ndarray): Positions to be applied as local translations on top of computed clone position. Defaults to None, no offset will be applied. orientation_offsets (np.ndarray): Orientations to be applied as local rotations for each clone. Defaults to None, no offset will be applied. replicate_physics (bool): Uses omni.physics replication. This will replicate physics properties directly for paths beginning with root_path and skip physics parsing for anything under the base_env_path. base_env_path (str): Path to namespace for all environments. Required if replicate_physics=True and define_base_env() not called. root_path (str): Prefix path for each environment. Required if replicate_physics=True and generate_paths() not called. copy_from_source: (bool): Setting this to False will inherit all clones from the source prim; any changes made to the source prim will be reflected in the clones. Setting this to True will make copies of the source prim when creating new clones; changes to the source prim will not be reflected in clones. Defaults to False. Note that setting this to True will take longer to execute. Returns: positions (List): Computed positions of all clones. """ num_clones = len(prim_paths) self._num_per_row = int(np.sqrt(num_clones)) if self._num_per_row == -1 else self._num_per_row num_rows = np.ceil(num_clones / self._num_per_row) num_cols = np.ceil(num_clones / num_rows) row_offset = 0.5 * self._spacing * (num_rows - 1) col_offset = 0.5 * self._spacing * (num_cols - 1) stage = omni.usd.get_context().get_stage() positions =  orientations =  for i in range(num_clones): # compute transform row = i // num_cols col = i % num_cols x = row_offset - row * self._spacing y = col * self._spacing - col_offset up_axis = UsdGeom.GetStageUpAxis(stage) position = [x, y, 0] if up_axis == UsdGeom.Tokens.z else [x, 0, y] orientation = Gf.Quatd.GetIdentity() if position_offsets is not None: translation = position_offsets[i] + position else: translation = position if orientation_offsets is not None: orientation = ( Gf.Quatd(orientation_offsets[i].item(), Gf.Vec3d(orientation_offsets[i][1:].tolist())) * orientation ) else: orientation = [ orientation.GetReal(), orientation.GetImaginary(), orientation.GetImaginary(), orientation.GetImaginary(), ] positions.append(translation) orientations.append(orientation) super().clone( source_prim_path=source_prim_path, prim_paths=prim_paths, positions=positions, orientations=orientations, replicate_physics=replicate_physics, base_env_path=base_env_path, root_path=root_path, copy_from_source=copy_from_source, ) return positions