Rep.orchestrator returning all rgba channels=0

5.1.0
Windows 11

Detailed Description

I have had to program in retries for capturing image data and I dont get why. Ex. I’m modifying lighting on the fly to calibrate against a gray card since my lights are randomly placed (i modify the intensity till the lighting is just right). Happens both in headless and not-headless.

    target_average = random.randint(88, 168)
    tolerance = 5
    max_iterations = 100

    print("")
    print(f"Image {i+1}")
    print("    Calibrating gray card")
    for j in range(max_iterations):
        print(f"        Iteration {j}")
        success = False
        attempts = 0
        writer.get_gray = True
        writer.last_avg = None
        writer.last_write_successful = False
        rgb_data = None

        while not writer.last_write_successful and attempts < 1000:
            for _ in range(10):
                world.step(render=True)
            rep.orchestrator.step(rt_subframes=16, delta_time=0.1)#, pause_timeline=False)
            rep.orchestrator.wait_until_complete()
            combined_data = {
                "rgb": writer.rgb_annot.get_data(),
                "semantic_segmentation": writer.seg_annot.get_data(),
                "bounding_box_2d_tight": writer.bbox_annot.get_data()
            }

            # 5. Call your write function manually
            writer.write(combined_data)

            if not writer.last_write_successful:
                attempts += 1
                print(f"            Gray attempts: {attempts}")

        average_value = writer.last_avg

        # Check if we are within the target range
        if abs(average_value - target_average) <= tolerance:
            break

        new_intensity = new_intensity * (target_average / average_value) * (target_average / average_value)

        new_attributes={
            "inputs:intensity": new_intensity, # Intensity of the light
        }
        if choose_light == 1:
            set_light_attributes(rect_light_prim, new_attributes)
        if choose_light == 2:
            set_light_attributes(sphere_light_prim, new_attributes)
        if choose_light == 3:
            set_light_attributes(cylinder_x1_light_prim, new_attributes)
            set_light_attributes(cylinder_x2_light_prim, new_attributes)
        if choose_light == 4:
            set_light_attributes(cylinder_y1_light_prim, new_attributes)
            set_light_attributes(cylinder_y2_light_prim, new_attributes)

Example output:

Image 2
    Calibrating gray card
        Iteration 0
            DEBUG: RGBA layers all 0.
            Gray attempts: 1
            DEBUG: RGBA layers all 0.
            Gray attempts: 2
        Iteration 1
        Iteration 2
        Iteration 3
            DEBUG: RGBA layers all 0.
            Gray attempts: 1


or...


Image 15
    Calibrating gray card
        Iteration 0
        Iteration 1
        Iteration 2
            DEBUG: RGBA layers all 0.
            Gray attempts: 1
        Iteration 3
        Iteration 4
        Iteration 5
        Iteration 6

I have a custom writer that catches the bug (when self.get_gray = True):

lass MultiDataWriterInstanceSeg(rep.Writer):
    def __init__(self, output_dir):
        self._output_dir = output_dir
        self.version = "1.0.0"
        self._rgb_dir = os.path.join(output_dir, "images_raw")
        self._seg_dir = os.path.join(output_dir, "images_raw_seg")
        self._frame_id = 1

        # Tracking state for the main loop
        self.success_count = 0
        self.last_avg = None
        self.get_gray = False
        self.seg_data_only = False
        self.passme = False
        self.last_write_successful = False

        for path in [self._rgb_dir, self._seg_dir]:
            if not os.path.exists(path):
                os.makedirs(path)
        
        ##################################################
        # Initialize annotators
        self.rgb_annot = rep.AnnotatorRegistry.get_annotator("rgb", device="cuda")
        self.seg_annot = rep.AnnotatorRegistry.get_annotator("semantic_segmentation", init_params={"colorize": True}, device="cuda")
        self.bbox_annot = rep.AnnotatorRegistry.get_annotator("bounding_box_2d_tight")

        self.annotators = [
            self.rgb_annot,
            self.seg_annot,
            self.bbox_annot
        ]

    def write(self, data):
        if self.passme == True:
            return

        # 1. Process and Save RGB Data
        # Reset flag at the start of every attempted write
        self.last_write_successful = False
        
        # 1. BLANK CHECK
        rgb_pixels = None
        if not self.seg_data_only:
            rgb_pixels = to_numpy(data.get("rgb"))
            if rgb_pixels is None:
                print("            DEBUG: RGB Image is None.")
                return
            if not np.any(rgb_pixels):
                print("            DEBUG: RGBA layers all 0.")
                return
            if not np.any(rgb_pixels[..., :3]):
                print("            DEBUG: RGB layers all 0. Transparency layer non-zero.")
                return
            if self.get_gray:
                self.last_avg = np.mean(rgb_pixels[..., :3]) # Calculate it while we have the data
                self.last_write_successful = True
                return

How can I get rid of this? It seems to happen randomly (per examples above). Sometimes it doesnt happen at all. sometimes it’ll just sit there till it errors out never capturing data. What am I missing?

To help us debug, could you attach a minimal reproduction—just enough script and USD scene to consistently trigger the all‑zero RGBA frames?

Minimal you say……….

ok look. i know this is dirty code. i know it, so please dont judge me, but its at least easy to follow.

should be able to copy paste this in.

from isaacsim import SimulationApp

# --------------------------
# START SIMULATION
# --------------------------
# Non-headless mode so we can see the stage
simulation_app = SimulationApp({"headless": False, "enable_cameras": True})

from pxr import UsdGeom, Gf, Sdf, UsdShade
import numpy as np
import os
import random
import math
import omni.replicator.core as rep
from isaacsim.core.api.physics_context import PhysicsContext
from pxr import UsdGeom, Gf
from pxr import Sdf
import math
from omni.isaac.core import World
from pxr.PhysxSchema import PhysxSceneAPI
from isaacsim.core.utils.prims import create_prim
import isaacsim.core.utils.prims as prims_utils

bg_x = 1.2
bg_y = 0.9
percent_variance = 0.5

def constrain_multiple_rotations_callback(step_size):
    """
    Leaving this in just in case its causing something im not aware of.
    Looks at every object in the sim and applies hard rotation limits to certain axes.
    """

def general_setup():
    world = World(
        stage_units_in_meters=1.0,
        physics_dt=1.0/120.0,
        rendering_dt=1.0/30.0
    )
    PhysicsContext()
    stage = world.scene.stage

    # Define the physics scene prim (or get if it already exists)
    physics_scene_path = "/physicsScene"#"/World/physicsScene"
    physics_scene_prim = stage.GetPrimAtPath(physics_scene_path)
    PhysxSceneAPI.Apply(physics_scene_prim)

    # Explicitly create the solver attributes with the correct type (int)
    physics_scene_prim.CreateAttribute("physx:numPositionIterations", Sdf.ValueTypeNames.Int).Set(16)
    physics_scene_prim.CreateAttribute("physx:numVelocityIterations", Sdf.ValueTypeNames.Int).Set(4)

    world = World(stage_units_in_meters=1.0)
    world.reset()
    return world, stage

# --------------------------
# GRAY CARD
# --------------------------

def create_gray_card():
    """
    Creates a rectangular mesh representing an 18% grey card with a standard USD Preview Surface material.

    Args:
        stage: The USD stage to add the gray card to.
    """
    gray_card_path = "/World/GrayCardMesh"
    
    # Create the mesh primitive using the core utils
    gray_card_prim = create_prim(
        gray_card_path, "Mesh",
        position=Gf.Vec3d(0, 0, 0),
        scale=Gf.Vec3f(1.0, 1.0, 1.0)
    )
    
    # Define the mesh geometry
    mesh_geom = UsdGeom.Mesh(gray_card_prim)
    mesh_geom.GetPointsAttr().Set(
        [
            Gf.Vec3f(-bg_x/2, -bg_y/2, 0.0),
            Gf.Vec3f(bg_x/2, -bg_y/2, 0.0),
            Gf.Vec3f(bg_x/2, bg_y/2, 0.0),
            Gf.Vec3f(-bg_x/2, bg_y/2, 0.0),
        ]
    )
    mesh_geom.GetFaceVertexCountsAttr().Set([4])
    mesh_geom.GetFaceVertexIndicesAttr().Set([0, 1, 2, 3])

    # Create and configure a USD Preview Surface material
    material_path = Sdf.Path("/World/Looks/GrayCardMaterial")
    material_prim = UsdShade.Material.Define(stage, material_path)
    shader_path = material_path.AppendPath("Shader")
    shader_prim = UsdShade.Shader.Define(stage, shader_path)

    # Use the USD Preview Surface shader ID
    shader_prim.CreateIdAttr("UsdPreviewSurface")

    # Set the diffuse color to 18% grey
    shader_prim.CreateInput("diffuseColor", Sdf.ValueTypeNames.Color3f).Set(Gf.Vec3f(0.18, 0.18, 0.18))
    # Set the roughness to 1.0 for a fully matte surface
    shader_prim.CreateInput("roughness", Sdf.ValueTypeNames.Float).Set(1.0)
    # Set metallic to 0.0 for a non-metallic surface
    shader_prim.CreateInput("metallic", Sdf.ValueTypeNames.Float).Set(0.0)

    shader_prim.CreateInput("specular", Sdf.ValueTypeNames.Float).Set(1.0)

    shader_prim.CreateInput("ior", Sdf.ValueTypeNames.Float).Set(1.0)

    # Connect the shader to the material's surface output
    material_prim.CreateSurfaceOutput().ConnectToSource(shader_prim.ConnectableAPI(), "surface")

    # Bind the material to the mesh
    UsdShade.MaterialBindingAPI(gray_card_prim).Bind(material_prim, UsdShade.Tokens.strongerThanDescendants)

    xformable = UsdGeom.Xformable(gray_card_prim)
    xformable.ClearXformOpOrder() 

    return gray_card_prim

def move_prim(path, x, y, z):
    prim = stage.GetPrimAtPath(path)
    prim.GetAttribute("xformOp:translate").Set((x, y, z))



# --------------------------
# ADD CAMERA
# --------------------------
camera_path = "/World/TopCamera"
def get_camera_params():
    aperture_w = 6.4  # mm, default horizontal aperture for 4:3
    aperture_h = 4.8  # mm, default vertical aperture for 4:3
    focal_len = 12.0

    # Compute FOV from lens
    h_fov = 2 * math.atan((aperture_w / 2) / focal_len)
    v_fov = 2 * math.atan((aperture_h / 2) / focal_len)

    # Required height to see entire plane
    required_height_w = (bg_x / 2.0) / math.tan(h_fov / 2.0)
    required_height_h = (bg_y / 2.0) / math.tan(v_fov / 2.0)
    max_height = max(required_height_w, required_height_h)

    return aperture_w, aperture_h, focal_len, max_height

def setup_camera(aperture_w, aperture_h, focal_len, max_height, camera_path):
    # Create or fetch camera
    if not stage.GetPrimAtPath(camera_path):
        cam = UsdGeom.Camera.Define(stage, camera_path)
    else:
        cam = UsdGeom.Camera(stage.GetPrimAtPath(camera_path))

    # Set camera parameters
    # Aperture
    cam.GetHorizontalApertureAttr().Set(aperture_w)
    cam.GetVerticalApertureAttr().Set(aperture_h)
    # Focal Length
    cam.GetFocalLengthAttr().Set(focal_len)

    cam.GetClippingRangeAttr().Set(Gf.Vec2f(0.001, 1000000.0))

    # Set transform: camera above plane along +Z, looking downward (-Z)
    xform = UsdGeom.Xformable(cam)
    xform.AddTranslateOp().Set(Gf.Vec3d(0, 0, max_height))
    xform.AddRotateXOp().Set(0.0)  # no rotation needed; default looks down -Z in Z-up


def set_camera_height(camera_height, camera_path):
    cam = stage.GetPrimAtPath(camera_path)
    xform = UsdGeom.Xformable(cam)
    xform.GetTranslateOp().Set(Gf.Vec3d(0, 0, camera_height))


# --------------------------
# ADD LIGHTS
# --------------------------
RECT_LIGHT_PATH = "/World/RectLight"
SPHERE_LIGHT_PATH = "/World/SphereLight"
CYLINDER_X1_LIGHT_PATH = "/World/CylinderLightX1"
CYLINDER_X2_LIGHT_PATH = "/World/CylinderLightX2"
CYLINDER_Y1_LIGHT_PATH = "/World/CylinderLightY1"
CYLINDER_Y2_LIGHT_PATH = "/World/CylinderLightY2"

def create_rect_light(max_height):
    """Creates a RectLight and returns the prim object."""
    rect_light_prim = prims_utils.create_prim(
        prim_path=RECT_LIGHT_PATH,
        prim_type="RectLight",
        position=np.array([0.0, 0.0, max_height]),
    )
    return rect_light_prim

def create_sphere_light(max_height, radius=0.05):
    """Creates a SphereLight and returns the prim object."""
    sphere_light_prim = prims_utils.create_prim(
        prim_path=SPHERE_LIGHT_PATH,
        prim_type="SphereLight",
        position=np.array([0.0, 0.0, max_height]),
        attributes={"inputs:radius": radius},
    )
    return sphere_light_prim

def create_cylinder_x1_light(max_height, length=1.0, radius=0.05):
    """Creates a CylinderLight and returns the prim object."""
    cylinder_x1_light_prim = prims_utils.create_prim(
        prim_path=CYLINDER_X1_LIGHT_PATH,
        prim_type="CylinderLight",
        position=np.array([0.0, 0.0, max_height]),
        attributes={
            "inputs:length": length,
            "inputs:radius": radius,
        },
    )
    return cylinder_x1_light_prim

def create_cylinder_x2_light(max_height, length=1.0, radius=0.05):
    """Creates a CylinderLight and returns the prim object."""
    cylinder_x2_light_prim = prims_utils.create_prim(
        prim_path=CYLINDER_X2_LIGHT_PATH,
        prim_type="CylinderLight",
        position=np.array([0.0, 0.0, max_height]),
        attributes={
            "inputs:length": length,
            "inputs:radius": radius,
        },
    )
    return cylinder_x2_light_prim

def create_cylinder_y1_light(max_height, length=1.0, radius=0.05):
    """Creates a CylinderLight and returns the prim object."""
    cylinder_y1_light_prim = prims_utils.create_prim(
        prim_path=CYLINDER_Y1_LIGHT_PATH,
        prim_type="CylinderLight",
        position=np.array([0.0, 0.0, max_height]),
        attributes={
            "inputs:length": length,
            "inputs:radius": radius,
        },
    )
    # Apply a 90-degree rotation around the Y-axis to make it vertical
    xformable = UsdGeom.Xformable(cylinder_y1_light_prim)
    xformable.AddRotateZOp().Set(90.0)

    return cylinder_y1_light_prim

def create_cylinder_y2_light(max_height, length=1.0, radius=0.05):
    """Creates a CylinderLight and returns the prim object."""
    cylinder_y2_light_prim = prims_utils.create_prim(
        prim_path=CYLINDER_Y2_LIGHT_PATH,
        prim_type="CylinderLight",
        position=np.array([0.0, 0.0, max_height]),
        attributes={
            "inputs:length": length,
            "inputs:radius": radius,
        },
    )
    # Apply a 90-degree rotation around the Y-axis to make it vertical
    xformable = UsdGeom.Xformable(cylinder_y2_light_prim)
    xformable.AddRotateZOp().Set(90.0)
    return cylinder_y2_light_prim

def set_light_params(prim, new_position, new_attributes):
    # Set the new position
    xformable = UsdGeom.Xformable(prim)
    translate_op = xformable.GetTranslateOp()
    translate_op.Set(Gf.Vec3d(*new_position))
    
    # Set the new attributes
    # The attributes dictionary can contain `inputs:radius`, `inputs:intensity`, etc.
    for attr_name, attr_value in new_attributes.items():
        attr = prim.GetAttribute(attr_name)
        if attr.IsValid():
            attr.Set(attr_value)
        else:
            print(f"Warning: Attribute '{attr_name}' not found")

def set_light_attributes(prim, new_attributes):
    # Set the new attributes
    # The attributes dictionary can contain `inputs:radius`, `inputs:intensity`, etc.
    for attr_name, attr_value in new_attributes.items():
        attr = prim.GetAttribute(attr_name)
        if attr.IsValid():
            attr.Set(attr_value)
        else:
            print(f"Warning: Attribute '{attr_name}' not found")

# --------------------------
# TAKE A PICTURE
# --------------------------
def to_numpy(data):
    if data is None:
        return None
    
    # 1. Check for Warp Array (wp.array) - Specific to Isaac Sim 5.1+
    if hasattr(data, "numpy") and callable(data.numpy):
        return data.numpy()
    
    # 2. Check for PyTorch Tensor
    if hasattr(data, "cpu"):
        return data.cpu().numpy()
    
    # 3. Check for CuPy Array
    if hasattr(data, "get"):
        return data.get()
    
    # 4. Fallback for standard lists/already NumPy
    try:
        return np.array(data)
    except Exception:
        return data



#Leaving in all the annotators I used in case this matters
class MultiDataWriterInstanceSeg(rep.Writer):
    def __init__(self, output_dir):
        self._output_dir = output_dir
        self.version = "1.0.0"
        self._rgb_dir = os.path.join(output_dir, "images_raw")
        self._seg_dir = os.path.join(output_dir, "images_raw_seg")
        self._frame_id = 1

        self.success_count = 0
        self.last_avg = None
        self.get_gray = False
        self.last_write_successful = False

        for path in [self._rgb_dir, self._seg_dir]:
            if not os.path.exists(path):
                os.makedirs(path)
        
        self.rgb_annot = rep.AnnotatorRegistry.get_annotator("rgb", device="cuda")
        self.seg_annot = rep.AnnotatorRegistry.get_annotator("semantic_segmentation", init_params={"colorize": True}, device="cuda")
        self.bbox_annot = rep.AnnotatorRegistry.get_annotator("bounding_box_2d_tight")
        self.bbox3d_annot = rep.AnnotatorRegistry.get_annotator("bounding_box_3d")
        self.camera_annot = rep.AnnotatorRegistry.get_annotator("camera_params")

        self.annotators = [
            self.rgb_annot,
            self.seg_annot,
            self.bbox_annot,
            self.bbox3d_annot,
            self.camera_annot
        ]

    def write(self, data):

        self.last_write_successful = False
        
        # 1. Process RGB Data
        rgb_pixels = None
        
        rgb_pixels = to_numpy(data.get("rgb"))
        if rgb_pixels is None:
            print("            DEBUG: RGB Image is None.")
            return 4
        if not np.any(rgb_pixels):
            print("            DEBUG: RGBA layers all 0.")
            return 3
        if not np.any(rgb_pixels[..., :3]):
            print("            DEBUG: RGB layers all 0. Transparency layer non-zero.")
            return 2
        
        self.last_avg = np.mean(rgb_pixels[..., :3])
        self.last_write_successful = True
        return 1


    def write_metadata(self, *args, **kwargs):
        pass

def setup_picture_saver(camera_path):

    render_product = rep.create.render_product(camera_path, (1920, 1440))
    simulation_app.update()
    writer = MultiDataWriterInstanceSeg("output")

    writer.rgb_annot.attach(render_product)
    writer.seg_annot.attach(render_product)
    writer.bbox_annot.attach(render_product)
    writer.bbox3d_annot.attach(render_product)
    writer.camera_annot.attach(render_product)

    rep.orchestrator.set_capture_on_play(False)
    
    return writer, render_product


# --------------------------
# RUN SIMULATION AND SHOW STAGE
# ------------------------

world, stage = general_setup()
create_gray_card()

aperture_w, aperture_h, focal_len, max_height = get_camera_params()
setup_camera(aperture_w, aperture_h, focal_len, max_height, camera_path)

# Min height
min_height = max_height * percent_variance
# Random height between min and max
camera_height = random.uniform(min_height, max_height)
set_camera_height(max_height, camera_path)


rect_light_prim = create_rect_light(max_height)
sphere_light_prim = create_sphere_light(max_height)
cylinder_x1_light_prim = create_cylinder_x1_light(max_height)
cylinder_x2_light_prim = create_cylinder_x2_light(max_height)
cylinder_y1_light_prim = create_cylinder_y1_light(max_height)
cylinder_y2_light_prim = create_cylinder_y2_light(max_height)

writer, render_product = setup_picture_saver(camera_path)

print("Adding physics callback")
world.add_physics_callback("multiple_rotation_constrainer", constrain_multiple_rotations_callback)

print("Starting sim loop")
for i in range(10):
    if not simulation_app.is_running():
        break
    world.stop()
    # Min height (80% of plane visible)
    min_height = max_height * percent_variance
    # Random height between min and max
    camera_height = random.uniform(min_height, max_height)
    set_camera_height(camera_height, camera_path)
    new_color = Gf.Vec3f(1.0, 1.0, 1.0)
    new_intensity = 5000
    new_attributes={
        "inputs:intensity": 0 # Intensity of the light
    }
    set_light_attributes(rect_light_prim, new_attributes)
    set_light_attributes(sphere_light_prim, new_attributes)
    set_light_attributes(cylinder_x1_light_prim, new_attributes)
    set_light_attributes(cylinder_x2_light_prim, new_attributes)
    set_light_attributes(cylinder_y1_light_prim, new_attributes)
    set_light_attributes(cylinder_y2_light_prim, new_attributes)

    choose_light = random.randint(1, 4)

    x_bounds = bg_x
    y_bounds = bg_y

    height_var = random.uniform(0.5, 1)

    if choose_light == 1: #Rect
        new_position = np.array([random.uniform(-x_bounds*2, x_bounds*2), random.uniform(-y_bounds*2, y_bounds*2), max_height*height_var])
        new_attributes={
            "inputs:width": bg_x * random.uniform(0.3, 2), # Width of the rectangular light
            "inputs:height": bg_y * random.uniform(0.3, 2), # Height of the rectangular light
            "inputs:intensity": new_intensity, # Intensity of the light
            "inputs:color": new_color, # Color of the light (RGB)
            "inputs:enableColorTemperature": False, # Disable color temperature for direct color setting
        }
        set_light_params(rect_light_prim, new_position, new_attributes)

    if choose_light == 2: #Sphere
        new_position = np.array([random.uniform(-x_bounds*2, x_bounds*2), random.uniform(-y_bounds*2, y_bounds*2), max_height*height_var])
        new_attributes={
            "inputs:radius": max(bg_x,bg_y) * random.uniform(0.3,1)/2, # Radius of the spherical light
            "inputs:intensity": new_intensity, # Intensity of the light
            "inputs:color": new_color, # Color of the light (RGB)
            "inputs:enableColorTemperature": False, # Disable color temperature for direct color setting
        }
        set_light_params(sphere_light_prim, new_position, new_attributes)

    if choose_light == 3: #CylinderX
        length = bg_x * random.uniform(0.25, 2)
        radius = random.uniform(0.005,0.03)
        x_pos = random.uniform(-(bg_x - length)/2, (bg_x - length)/2)
        y1_pos = random.uniform(0.25*bg_y/2, 1*bg_y/2)
        y2_pos = -y1_pos
        new_position = np.array([x_pos, y1_pos, max_height*height_var])
        new_attributes={
            "inputs:radius": radius, # Radius of the cylindrical light
            "inputs:length": length, # Radius of the cylindrical light
            "inputs:intensity": new_intensity, # Intensity of the light
            "inputs:color": new_color, # Color of the light (RGB)
            "inputs:enableColorTemperature": False, # Disable color temperature for direct color setting
        }
        set_light_params(cylinder_x1_light_prim, new_position, new_attributes)
        new_position = np.array([x_pos, y2_pos, max_height*height_var])
        set_light_params(cylinder_x2_light_prim, new_position, new_attributes)

    if choose_light == 4: #CylinderY
        length = bg_y * random.uniform(0.25, 2)
        radius = random.uniform(0.005,0.03)
        y_pos = random.uniform(-(bg_y - length)/2, (bg_y - length)/2)
        x1_pos = random.uniform(0.25*bg_x/2, 1*bg_x/2)
        x2_pos = -x1_pos
        new_position = np.array([x1_pos, y_pos, max_height*height_var])
        new_attributes={
            "inputs:radius": radius, # Radius of the cylindrical light
            "inputs:length": length, # Radius of the cylindrical light
            "inputs:intensity": new_intensity, # Intensity of the light
            "inputs:color": new_color, # Color of the light (RGB)
            "inputs:enableColorTemperature": False, # Disable color temperature for direct color setting
        }
        set_light_params(cylinder_y1_light_prim, new_position, new_attributes)
        new_position = np.array([x2_pos, y_pos, max_height*height_var])
        set_light_params(cylinder_y2_light_prim, new_position, new_attributes)
    
    for _ in range(10):
        world.step(render=True)
    
    # Calibrate exposure/intensity
    graycard_path = "/World/GrayCardMesh"
    move_prim(graycard_path, 0, 0, 0)

    target_average = random.randint(88, 168)
    tolerance = 5
    max_iterations = 100

    print("")
    print(f"Image {i+1}")
    print("    Calibrating gray card")
    for j in range(max_iterations):
        print(f"        Iteration {j+1}")
        success = False
        attempts = 0
        writer.get_gray = True
        writer.last_avg = None
        writer.last_write_successful = False
        rgb_data = None

        while not writer.last_write_successful and attempts < 1000:
            for _ in range(10):
                world.step(render=True)
            rep.orchestrator.step(rt_subframes=16, delta_time=0.1)#, pause_timeline=False)
            rep.orchestrator.wait_until_complete()
            combined_data = {
                "rgb": writer.rgb_annot.get_data(),
                "semantic_segmentation": writer.seg_annot.get_data(),
                "bounding_box_2d_tight": writer.bbox_annot.get_data(),
                "bounding_box_3d": writer.bbox3d_annot.get_data(),
                "camera_params": writer.camera_annot.get_data()
            }

            # 5. Call your write function manually
            result = writer.write(combined_data)

            if not writer.last_write_successful:
                attempts += 1
                if result == 2:
                    new_intensity = new_intensity + 1000
                    new_attributes={
                        "inputs:intensity": new_intensity # Intensity of the light
                    }
                    if choose_light == 1:
                        set_light_attributes(rect_light_prim, new_attributes)

                    if choose_light == 2:
                        set_light_attributes(sphere_light_prim, new_attributes)

                    if choose_light == 3:
                        set_light_attributes(cylinder_x1_light_prim, new_attributes)
                        set_light_attributes(cylinder_x2_light_prim, new_attributes)

                    if choose_light == 4:
                        set_light_attributes(cylinder_y1_light_prim, new_attributes)
                        set_light_attributes(cylinder_y2_light_prim, new_attributes)
                print(f"            Gray attempts: {attempts}")
        
        average_value = writer.last_avg

        # Check if we are within the target range
        if abs(average_value - target_average) <= tolerance:
            break

        new_intensity = new_intensity * (target_average / average_value) * (target_average / average_value)

        new_attributes={
            "inputs:intensity": new_intensity, # Intensity of the light
        }
        if choose_light == 1:
            set_light_attributes(rect_light_prim, new_attributes)
        if choose_light == 2:
            set_light_attributes(sphere_light_prim, new_attributes)
        if choose_light == 3:
            set_light_attributes(cylinder_x1_light_prim, new_attributes)
            set_light_attributes(cylinder_x2_light_prim, new_attributes)
        if choose_light == 4:
            set_light_attributes(cylinder_y1_light_prim, new_attributes)
            set_light_attributes(cylinder_y2_light_prim, new_attributes)

    writer.get_gray = False

    graycard_path = "/World/GrayCardMesh"
    move_prim(graycard_path, 0, 0, -0.1)


simulation_app.close()

And here’s an example output I get:

Adding physics callback
Starting sim loop
2026-02-26T02:23:33Z [25,346ms] [Warning] [omni.syntheticdata.plugin] SdPostRenderVarToHost : invalid input resource for renderVar SemanticBoundingBox2DExtentTightSD
2026-02-26T02:23:33Z [25,498ms] [Warning] [omni.replicator.core.plugin] OgnSemanticOcclusionReduction: no semantics in the scene.
Module omni.replicator.core.ogn.python.impl.nodes.OgnSemanticSegmentation ae958f7 load on device 'cuda:0' took 2.35 ms  (cached)

Image 1
    Calibrating gray card
        Iteration 1
        Iteration 2
        Iteration 3
        Iteration 4

Image 2
    Calibrating gray card
        Iteration 1
        Iteration 2
        Iteration 3
        Iteration 4
        Iteration 5
        Iteration 6

Image 3
    Calibrating gray card
        Iteration 1
        Iteration 2
        Iteration 3
        Iteration 4
            DEBUG: RGBA layers all 0.
            Gray attempts: 1
        Iteration 5

Image 4
    Calibrating gray card
        Iteration 1
        Iteration 2
        Iteration 3

Image 5
    Calibrating gray card
        Iteration 1
        Iteration 2
        Iteration 3
        Iteration 4
            DEBUG: RGBA layers all 0.
            Gray attempts: 1
        Iteration 5
        Iteration 6

Image 6
    Calibrating gray card
        Iteration 1
        Iteration 2
        Iteration 3
            DEBUG: RGBA layers all 0.
            Gray attempts: 1
        Iteration 4

Image 7
    Calibrating gray card
        Iteration 1
        Iteration 2
        Iteration 3

Image 8
    Calibrating gray card
        Iteration 1
        Iteration 2

Image 9
    Calibrating gray card
        Iteration 1
        Iteration 2
        Iteration 3
        Iteration 4
        Iteration 5

Image 10
    Calibrating gray card
        Iteration 1
        Iteration 2
        Iteration 3
        Iteration 4
        Iteration 5
        Iteration 6
        Iteration 7
[109.099s] Simulation App Shutting Down

Could you try reproducing this with Isaac Sim 6.0 OSS and let us know if the issue still occurs?

I’m not entirely sure i understand the installation process since it looks like i need to build the whole thing from github. Is there a zip i can download?

Are you getting the same errors when you run the reproducible code?


I got 6.0.0 installed from “https://github.com/isaac-sim/IsaacSim/tree/develop” following the instructions. With many complications :(

had to install with “build.bat --skip-compiler-version-check” to avoid this error

[03/10/26 00:17:00] WARNING  Retrieving repo_build version via VERSION file.                             version.py:312
                    ERROR    BuildError exception stack trace dumped to logfile                              log.py:182
                             C:/IS600/isaacsim/_repo/repo.log. Stacks dumped to console via `--verbose` or
                             `--tracebacks`.
                             BuildError: Compiler version check failed:  desired versions : {'vs_version':
                             '2022', 'msvc_version': 'v143', 'msbuild_version': '17', 'vs_edition': '',
                             'winsdk_version': '10.0.22621.0'}, found versions: {'17.14.37012.4':
                             {'Community': {'vs_root': 'C:\\Program Files\\Microsoft Visual
                             Studio\\2022\\Community', 'msbuild': 'C:\\Program Files\\Microsoft Visual
                             Studio\\2022\\Community\\MSBuild/Current/Bin/MSBuild.exe', 'year': '2022',
                             'edition': 'Community'}}}
[03/10/26 00:17:00] ERROR    error running: _repo\python\python.exe                                        utils.py:264
                             C:\IS600\isaacsim\tools\repoman\repoman.py build, code: 1, message: ""

C:\IS600\isaacsim>build.bat --skip-compiler-version-check

There were still some fatal warnings like this

Generating version header file: main aa503a9 5.1.0-rc.19 Thu Nov 20 17:21:27 2025 -0600 https://github.com/isaac-sim/IsaacSim.git
** Warning: the flags value FatalCompileWarnings has been deprecated and will be removed.
   Use `fatalwarnings { "All" }` instead.
   @C function

** Warning: the flags value FatalCompileWarnings has been deprecated and will be removed.
   Use `fatalwarnings { "All" }` instead.
   @c:\IS600\isaacsim\source\extensions\isaacsim.asset.gen.conveyor\premake5.lua(47)

** Warning: the flags value FatalCompileWarnings has been deprecated and will be removed.
   Use `fatalwarnings { "All" }` instead.
   @c:\IS600\isaacsim\_build\windows-x86_64\release\kit\dev\ogn\ogn_helpers.lua(433)

** Warning: the flags value FatalCompileWarnings has been deprecated and will be removed.
   Use `fatalwarnings { "All" }` instead.
   @c:\IS600\isaacsim\_build\windows-x86_64\release\kit\dev\ogn\ogn_helpers.lua(406)

** Warning: the flags value FatalCompileWarnings has been deprecated and will be removed.
   Use `fatalwarnings { "All" }` instead.
   @c:\IS600\isaacsim\source\extensions\isaacsim.asset.importer.mjcf\premake5.lua(28)

** Warning: the flags value FatalCompileWarnings has been deprecated and will be removed.
   Use `fatalwarnings { "All" }` instead.
   @c:\IS600\isaacsim\source\extensions\isaacsim.asset.importer.mjcf\premake5.lua(29)

** Warning: the flags value FatalCompileWarnings has been deprecated and will be removed.
   Use `fatalwarnings { "All" }` instead.
   @c:\IS600\isaacsim\source\extensions\isaacsim.asset.importer.urdf\premake5.lua(27)

** Warning: the flags value FatalCompileWarnings has been deprecated and will be removed.
   Use `fatalwarnings { "All" }` instead.
   @c:\IS600\isaacsim\source\extensions\isaacsim.asset.importer.urdf\premake5.lua(28)

But I let it finish and looks like it opens up and runs fine. Window heading still says 5.1.0 though :/


But now I need your help. With the standalone version i have with 5.1.0, i open visual studio code right in that folder, ex: “C:\IsaacSim\isaac-sim-standalone-5.1.0-windows-x86_64”

how can I accomplish the same with my 6.0.0 install in order to run my code?

Opening it in here: C:\IS600\isaacsim_build\windows-x86_64\release

results in many errors as it tries to start up, for example:

2026-03-10T05:27:38Z [15,853ms] [Error] [omni.ext._impl.custom_importer] Failed to import python module omni.volume. Error: No module named 'omni.volume'. Traceback:
Traceback (most recent call last):
  File "C:\IS600\isaacsim\_build\windows-x86_64\release/kit/kernel/py\omni\ext\_impl\custom_importer.py", line 85, in import_module
    return importlib.import_module(name)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\IS600\isaacsim\_build\windows-x86_64\release\kit\python\Lib\importlib\__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1140, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'omni.volume'

2026-03-10T05:27:38Z [15,853ms] [Error] [carb.scripting-python.plugin] Exception: Extension python module: 'omni.volume' in 'c:\is600\isaacsim\_build\windows-x86_64\release\extscache\omni.volume-0.5.2+69cbf6ad.wx64.r.cp311' failed to load.

At:
  C:\IS600\isaacsim\_build\windows-x86_64\release/kit/kernel/py\omni\ext\_impl\_internal.py(222): startup
  C:\IS600\isaacsim\_build\windows-x86_64\release/kit/kernel/py\omni\ext\_impl\_internal.py(337): startup_extension
  PythonExtension.cpp::startup()(2): <module>
  C:\IS600\isaacsim\_build\windows-x86_64\release\exts\isaacsim.simulation_app\isaacsim\simulation_app\simulation_app.py(534): _start_app
  C:\IS600\isaacsim\_build\windows-x86_64\release\exts\isaacsim.simulation_app\isaacsim\simulation_app\simulation_app.py(270): __init__
  C:\Users\us.er\Python\AI_Vision\v01\ISAAC_gray_minimal.py(7): <module>
  c:\Users\us.er\.vscode\extensions\ms-python.debugpy-2025.18.0-win32-x64\bundled\libs\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py(118): _run_code
  c:\Users\us.er\.vscode\extensions\ms-python.debugpy-2025.18.0-win32-x64\bundled\libs\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py(127): _run_module_code        
  c:\Users\us.er\.vscode\extensions\ms-python.debugpy-2025.18.0-win32-x64\bundled\libs\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_runpy.py(310): run_path
  c:\Users\us.er\.vscode\extensions\ms-python.debugpy-2025.18.0-win32-x64\bundled\libs\debugpy\launcher/../..\debugpy/..\debugpy\server\cli.py(358): run_file
  c:\Users\us.er\.vscode\extensions\ms-python.debugpy-2025.18.0-win32-x64\bundled\libs\debugpy\launcher/../..\debugpy/..\debugpy\server\cli.py(508): main
  c:\Users\us.er\.vscode\extensions\ms-python.debugpy-2025.18.0-win32-x64\bundled\libs\debugpy\launcher/../..\debugpy\__main__.py(71): <module>
  c:\IS600\isaacsim\_build\windows-x86_64\release\kit\python\Lib\runpy.py(88): _run_code
  c:\IS600\isaacsim\_build\windows-x86_64\release\kit\python\Lib\runpy.py(198): _run_module_as_main

2026-03-10T05:27:38Z [15,854ms] [Error] [omni.ext.plugin] [ext: omni.volume-0.5.2] Failed to startup python extension.

Also getting this from VSC

Default interpreter path '${workspaceFolder}/kit/python/python.exe' could not be resolved: Could not resolve interpreter path '${workspaceFolder}/kit/python/python.exe'

Any help on this front?

If you guys have 5.1.0, can you please test the code that you asked me to prepare?

This is very time consuming


Ah hah! Got it… had to run VSC as administrator!

And alas, I the same problem persists. Example output:

Image 1
    Calibrating gray card
        Iteration 1
            DEBUG: RGBA layers all 0.
            Gray attempts: 1
        Iteration 2
        Iteration 3
            DEBUG: RGBA layers all 0.
            Gray attempts: 1
        Iteration 4
        Iteration 5

Image 2
    Calibrating gray card
        Iteration 1
        Iteration 2
        Iteration 3
        Iteration 4

Image 3
    Calibrating gray card
        Iteration 1
            DEBUG: RGBA layers all 0.
            Gray attempts: 1
        Iteration 2
        Iteration 3
            DEBUG: RGBA layers all 0.
            Gray attempts: 1
        Iteration 4
        Iteration 5
        Iteration 6

I was able to reproduce this issue with your code using Isaac Sim 5.1.0 previously, but I can no longer reproduce it now. One change since then is that I ran Isaac Sim once with the --reset-user flag, which may have cleared whatever was causing the problem on my side.

Could you try launching Isaac Sim with --reset-user as well and see if the issue still occurs afterward?

Tried it stand alone by running isaac-sim.bat —reset-user from cmd, and tried adding to simulation_app = SimulationApp({“reset_user”: True… }) in my script

Both still resulted the same, randomly blank images returned

Can you please provide some debug ideas I can try?

Edit: i see now my last response was not directly in response to your comment, but I did try what you previously suggested (see post above this one)

Hello? Is been 19 days since your response and i did both things you mentioned including installing 6.0.0 and using reset-user

I’m putting in a lot more than what I’m getting back from you guys and I’d hope that this is telling of my desire to resolve this issue. I’d appreciate if you’re going to ask me to spend a bunch of time on something that you’d continue to help or at least tell me that you’re not willing to help figure this out.

Hi @kristinandtom2016,

Apologies for the delay — I want to make sure we give you something actionable rather than another suggestion that doesn’t pan out.

I was able to reproduce the intermittent all-zero RGBA frames with your script on 5.1.0 previously, and I believe this is a render product synchronization timing issue — get_data() can occasionally read the
annotator buffer before the GPU has finished writing the rendered frame into it. The wait_until_complete() call ensures the OmniGraph evaluation is done, but there’s a gap before the GPU render results are fully
flushed.

Workaround to try: After the orchestrator step completes, force an additional app update before reading annotator data. This should ensure the GPU render has been flushed:

  rep.orchestrator.step(rt_subframes=16, delta_time=0.1)                                                                                                                                                            
  rep.orchestrator.wait_until_comp lete()                                                                                                                                                                           
                                                                                                                                                                                                                    
  # Force an additional render/update cycle to flush GPU results                                                                                                                                                    
  import omni.kit.app                                                                                                                                                                                               
  omni.kit.app.get_app().update()                                                                                                                                                                                   
                                                                                                                                                                                                                    
  # Now read annotator data                                                                                                                                                                                         
  combined_data = {                                                                                                                                                                                                 
      "rgb": writer.rgb_annot.get_data(),                                                                                                                                                                           
      "semantic_segmentation": writer.seg_annot.get_data(),                                                                                                                                                         
      "bounding_box_2d_tight": writer.bbox_annot.get_data()                                                                                                                                                         
  }                                                                                                                                                                                                                 

If one update() call isn’t enough, try two back-to-back — the render pipeline is double-buffered, so a second cycle ensures the frame has fully propagated.

Regarding 6.0.0: I understand the build-from-source process was painful. The 6.0.0 Early Developer Release 2 (dev2, March 16) includes annotator improvements (“fast annotator variants”) that may improve this. If
you’d like to test it, the latest instructions are at: GitHub - isaac-sim/IsaacSim at v6.0.0-dev2 · GitHub.

This issue is also being tracked alongside a related report (GitHub #507 ) about annotators returning empty data on random frames. I’m escalating both to the
Replicator team.

I’ll follow up here once I have more from the team. Sorry again for the gap.

Thank you - I’m going to be MIA till mid April. I’ll attempt again at that point and update as soon as i can

Have a great time, and I look forward to hearing from you then.

Hi @kristinandtom2016,

Welcome back! Quick update — I ran a reproduction test on Isaac Sim 6.0 and the all-zero RGBA issue appears to be fixed:

  • 150 frames captured across three test scenarios (no workaround, with extra app.update(), and with dynamic light changes per frame)
  • 0 zero frames in all cases

In 6.0, the orchestrator now enforces step_async instead of synchronous step inside Kit, which eliminates the GPU flush race condition that caused the intermittent blank frames in 5.x. Note that your existing rep.orchestrator.step() calls will need to change to await rep.orchestrator.step_async() in 6.0 — synchronous orchestrator calls are no longer allowed
inside Kit.

If you’re still on 5.x, the app.update() workaround from my earlier post should help reduce the issue. But if you’re able to move to 6.0, this should be fully resolved.

Let me know how it goes on your end.

Thank you for the update. Would you be able to in turn provide the code that you used with 6.0.0 to eliminate this issue? Specifically, I’ve actually had no success in implementing the await/step_async() command.

PS: I tried 5.1.0 doing this with 2 updates as suggested and it was unsuccessful

  import omni.kit.app                                                                                                                                                                                               
  omni.kit.app.get_app().update()
  omni.kit.app.get_app().update()

PSS: @VickNV , i did drop in the minimal reproducible code i provided into 6.0.0 and still had the same issue. So if you can show me that async method, i think that may be the trick to cross this off the list.

Hi @kristinandtom2016,

I verified this on 6.0 — here’s what I found:

The zero-frame issue does not reproduce on 6.0. I ran your minimal repro (adapted for 6.0 imports) with 20 frames of dynamic light changes and got 0 zero frames — both with and without extra app.update() calls.

The reason your code didn’t work when dropped into 6.0 is likely an import error. In 6.0, the module paths changed:

  # 5.x (old)                                                                                                                                                                                                                                      
  from omni.isaac.core import World                                                                                                                                                                                                                
                                                                                                                                                                                                                                                   
  # 6.0 (new)                                                                                                                                                                                                                                      
  from isaacsim.core.api import World                                                                                                                                                                                                              

If that import fails, the script crashes silently before reaching your capture loop. Here’s a working 6.0 capture pattern:

  from isaacsim import SimulationApp                                                                                                                                                                                                               
  simulation_app = SimulationApp({"headless": True, "enable_cameras": True})                                                                                                                                                                       
                                                                                                                                                                                                                                                   
  import numpy as np                                                                                                                                                                                                                               
  import omni.replicator.core as rep                                                                                                                                                                                                               
  from isaacsim.core.api import World                                                                                                                                                                                                              
                                                                                                                                                                                                                                                   
  # ... scene setup ...                                                                                                                                                                                                                            
                                                                                                                                                                                                                                                   
  # Create render product + annotator                                                                                                                                                                                                              
  render_product = rep.create.render_product("/World/TopCamera", (640, 480))                                                                                                                                                                       
  rgb_annot = rep.AnnotatorRegistry.get_annota tor("rgb")                                                                                                                                                                                          
  rgb_annot.attach([render_product ])                                                                                                                                                                                                              
                                                                                                                                                                                                                                                   
  world = World(stage_units_in_meters=1.0)                                                                                                                                                                                                         
  world.reset()                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                   
  # Warm up (important!)                                                                                                                                                                                                                           
  for _ in range(10):                                                                                                                                                                                                                              
      world.step(render=True)                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                   
  # Capture loop with dynamic light changes                                                                                                                                                                                                        
  for i in range(num_frames):                                                                                                                                                                                                                      
      # Modify scene (e.g., change light intensity)                                                                                                                                                                                                
      light_prim.GetAttribute("inputs: intensity").Set(new_intensity)                                                                                                                                                                              
                                                                                                                                                                                                                                                   
      # Step simulation                                                                                                                                                                                                                            
      for _ in range(5):                                                                                                                                                                                                                           
          world.step(render=True)                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                   
      # Capture — synchronous step works fine in 6.0 standalone scripts                                                                                                                                                                            
      rep.orchestrator.step(rt_subframes=16, delta_time=0.1)                                                                                                                                                                                       
      rep.orchestrator.wait_until_comp lete()                                                                                                                                                                                                      
                                                                                                                                                                                                                                                   
      # Read data                                                                                                                                                                                                                                  
      rgb_data = rgb_annot.get_data()                                                                                                                                                                                                              
      # rgb_data will be valid (no zero frames)                                                                                                                                                                                                    

Key points:

  • rep.orchestrator.step() (synchronous) works in standalone scripts on 6.0 — you don’t need step_async unless you’re inside the Script Editor
  • No extra app.update() workaround needed on 6.0
  • Make sure all imports use the new isaacsim.* paths (not omni.isaac.*)

If you’re still seeing issues after fixing the imports, please share the exact error output from 6.0.

I don’t think I’m following. I updated the import path as you suggested in 6.0.0 to

from isaacsim.core.api import World

If that’s the only change to make to the minimally reproducible code i provided above, then I’m still getting the issue persisting. Is this not the case on your end?

I don’t understand what to do with the other code snippet you provided though. It looks like a generic snippet

Hi @kristinandtom2016,

I’ve done a deep reproduction of this issue on Isaac Sim 5.1.0 and I believe I’ve found the root cause. It’s not a render pipeline race condition – the annotator is correctly returning what was rendered. The problem is that your SphereLight and CylinderLight configurations produce insufficient illumination at the radii and intensities you’re using.

The Evidence

I ran your exact capture pattern with two setups:

  1. Your multi-light pattern (SphereLight + RectLight, random selection): 72.9% zero-frame rate
  2. Same pattern but RectLight only: 0% zero-frame rate over 113 captures

Then I tested SphereLight illumination directly:

SphereLight radius=0.05, intensity=5000:    RGB mean = 0.00 (completely dark!)
SphereLight radius=0.05, intensity=10000:   RGB mean = 0.08
SphereLight radius=0.05, intensity=500000:  RGB mean = 46.45
RectLight   intensity=5000:                 RGB mean = 53.53

A SphereLight with radius=0.05 and intensity=5000 produces literally zero RGB values in the rendered frame. The alpha channel is non-zero (correct – it indicates valid rendered pixels), but the scene is so dark that RGB quantizes to 0.

Why This Happens

In USD/RTX, intensity is power per steradian. A SphereLight emits from its surface area – a tiny sphere (r=5cm) at distance produces orders of magnitude less total flux on your gray card compared to a RectLight at the same intensity. The same applies to CylinderLight at your radii of 0.005-0.03m.

Your detection code checks np.any(rgb_pixels[..., :3]) – this correctly identifies that all RGB values are zero, but it’s a legitimately dark frame, not a render error.

The Fix

Option A: Scale intensity by light type (recommended)

Different light types need vastly different intensity values to produce equivalent illumination:

if choose_light == 1:  # RectLight
    new_intensity = 5000
elif choose_light == 2:  # SphereLight
    new_intensity = 500000  # ~100x more for small sphere
elif choose_light in [3, 4]:  # CylinderLight
    new_intensity = 200000  # scale based on radius

Option B: Use a minimum brightness threshold instead of exact zero

# Instead of:
if not np.any(rgb_pixels[..., :3]):
    print("DEBUG: RGB layers all 0.")
    return

# Use:
if np.mean(rgb_pixels[..., :3]) < 1.0:  # below quantization threshold
    print("DEBUG: Scene too dark, adjusting light.")
    # Increase intensity and retry

Option C: Use normalize=True on your lights

USD lights support a normalize attribute that adjusts intensity to account for the light’s surface area:

light_prim.GetAttribute("inputs:normalize").Set(True)

This makes a SphereLight with radius=0.05 produce comparable illumination to a larger light at the same intensity value. However, the behavior may not be exactly what you want for calibration.

Thank you for continuing to try and figure this out. Your explanation doesn’t jive with the debug print outs I’ve added though.

The fault is that RGBA are all zero. If it was that it was literally all black because it was a really really dark scene, then RGB would be zero and A would be all at 255. I have a separate debug readout for that exact scenario in order to highlight exactly what you’ve mentioned. But the printout I’m getting is:

            DEBUG: RGBA layers all 0.

Note the different debug printouts in class MultiDataWriterInstanceSeg(rep.Writer):

        if rgb_pixels is None:
            print("            DEBUG: RGB Image is None.")
            return 4
        if not np.any(rgb_pixels):
            print("            DEBUG: RGBA layers all 0.")
            return 3
        if not np.any(rgb_pixels[..., :3]):
            print("            DEBUG: RGB layers all 0. Transparency layer non-zero.")
            return 2

You’ll also notice for every time it spits out “Gray attempts: {attempts}” it doesn’t modify the intensity or change the scene at all, it just steps a few times and retries. Associated code block to look at:

        while not writer.last_write_successful and attempts < 1000:
            for _ in range(10):
                world.step(render=True)
            rep.orchestrator.step(rt_subframes=16, delta_time=0.1)#, pause_timeline=False)                                                                                                                                    
            rep.orchestrator.wait_until_complete()  

            import omni.kit.app                                                                                                                                                                                               
            omni.kit.app.get_app().update()
            omni.kit.app.get_app().update() 

            combined_data = {
                "rgb": writer.rgb_annot.get_data(),
                "semantic_segmentation": writer.seg_annot.get_data(),
                "bounding_box_2d_tight": writer.bbox_annot.get_data(),
                "bounding_box_3d": writer.bbox3d_annot.get_data(),
                "camera_params": writer.camera_annot.get_data()
            }

            # 5. Call your write function manually
            result = writer.write(combined_data)

            if not writer.last_write_successful:
                attempts += 1
                old_intensity = new_intensity
                if result == 2:
                    new_intensity = new_intensity + 1000
                    new_attributes={
                        "inputs:intensity": new_intensity # Intensity of the light
                    }
                    if choose_light == 1:
                        set_light_attributes(rect_light_prim, new_attributes)

                    if choose_light == 2:
                        set_light_attributes(sphere_light_prim, new_attributes)

                    if choose_light == 3:
                        set_light_attributes(cylinder_x1_light_prim, new_attributes)
                        set_light_attributes(cylinder_x2_light_prim, new_attributes)

                    if choose_light == 4:
                        set_light_attributes(cylinder_y1_light_prim, new_attributes)
                        set_light_attributes(cylinder_y2_light_prim, new_attributes)
                print(f"            Gray attempts: {attempts}")

Adding the light type and intensity value to the iteration printout (in my minimally reproduceable code originally provided), an example output is:

Image 3
    Calibrating gray card
        Iteration 1, CylinderX, Intensity: 5000.0
        Iteration 2, CylinderX, Intensity: 99630.6
            DEBUG: RGBA layers all 0.
            Gray attempts: 1
            DEBUG: RGBA layers all 0.
            Gray attempts: 2
            DEBUG: RGBA layers all 0.
            Gray attempts: 3
        Iteration 3, CylinderX, Intensity: 25019.5
        Iteration 4, CylinderX, Intensity: 29247.1

Even in this specific output, the image capture worked in Iteration 1 with an intensity of 5000. Then on iteration 2 with a higher intensity, I was getting the RGBA=0 fault.

So unfortunately @VickNV I dont think the intensity as you described is the root cause. Am I wrong in any of these points/conclusions?