ovrtx

repository·main·Indexed 41 days ago

https://github.com/nvidia-omniverse/ovrtx

A C and Python library for embedding NVIDIA Omniverse RTX sensor simulation and visualization into applications. Optimized for Physical AI workflows, including robotics learning, synthetic data generation, and industrial design. Version 0.5.0 provides physically accurate, real-time simulation for sensors such as Lidar and Radar.

Tokens
149.9K
Snippets
297
Records
676
Agent score
54%

What's inside ovrtx

  1. Overview of NVIDIA ovrtx

    main

    NVIDIA ovrtx is a lightweight C and Python SDK that exposes Omniverse RTX technology. It is designed for real-time, physically accurate sensor simulation and rendering, specifically targeting robotics learning, synthetic data generation, and industrial/design workflows.

    Key Features

    • Physically Accurate Sensor Simulation: Simulates cameras, lidar, radar, and other sensors.
    • Scalable Performance: Supports high-throughput simulation (tens of thousands of frames per second) for reinforcement learning, real-time interactive viewports, and offline predictive rendering.
    • OpenUSD Integration: Uses OpenUSD for scene description, enabling interchange with CAD and simulation tools.
    • Python Ecosystem Integration: Designed for easy use within Python-based simulation and machine learning workflows.
  2. Reference ovrtx Python API components

    main

    The ovrtx Python API provides a high-level interface for rendering. The core components include:

    • Renderer: The primary interface for rendering operations (ovrtx.Renderer).
    • Configuration: Classes for setting up the renderer (ovrtx.RendererConfig) and selection styles (ovrtx.SelectionGroupStyle).
    • Async Operations: Management of asynchronous tasks via ovrtx.Operation, ovrtx.PendingFetch, ovrtx.OperationStatus, and ovrtx.OperationCounter.
    • Render Outputs: Accessing data via ovrtx.RenderProductSetOutputs, ovrtx.ProductOutput, ovrtx.FrameOutput, ovrtx.RenderVarOutput, ovrtx.MappedRenderVar, ovrtx.RenderVarTensor, and ovrtx.RenderVarParam.
    • Attribute Bindings: Managing mappings and metadata via ovrtx.AttributeBinding, ovrtx.AttributeMapping, and ovrtx.AttributeInfo.
    • Enums: Type-safe constants for controlling behavior (e.g., ovrtx.Semantic, ovrtx.PrimMode, ovrtx.Device, ovrtx.BindingFlag, etc.).
  3. Understand the ovrtx Skills Directory structure

    main

    The skills/ directory contains structured SKILL.md files designed for AI coding agents. Each skill provides a self-contained reference for a specific task, including Python and C API usage, prerequisites, and troubleshooting.

    Each skill is organized into its own subdirectory and follows a strict format to ensure accuracy and maintainability.

  4. System requirements for ovrtx runtime validation

    main

    To use the ovrtx runtime, your environment must meet the following requirements:

    • GPU: NVIDIA RTX-capable GPU.
    • Driver: A supported NVIDIA driver (refer to ../driver_requirements for specific versions).
    • Network: Internet access (the minimal example requires downloading scene assets from S3).
    • Environment: Execution must occur outside of sandboxed environments.
  5. Understand the Render Output hierarchy

    main

    When you call step(), the returned RenderProductSetOutputs contains a hierarchical structure of data. Understanding this hierarchy is essential for mapping pixel data from cameras and sensors:

    • RenderProductSetOutputs: The top-level result for a step.
      • .simulation_start_time / .simulation_end_time: The time window [t, t+dt] covered by the step.
      • ProductOutput: One per render product path (e.g., a specific camera).
        • FrameOutput: One per frame produced during the step.
          • .start_time / .end_time: The specific sensor capture time within the step window.
          • RenderVarOutput: One per full RenderVar prim path (e.g., /Render/Camera/LdrColor, /Render/Camera/HdrColor).
    RenderProductSetOutputs
      .simulation_start_time / .simulation_end_time
      -> ProductOutput
        -> FrameOutput
          .start_time / .end_time
          -> RenderVarOutput
  6. Migrate Python USD loading patterns

    main

    In ovrtx 0.3.x, USD loading is determined by your intent for how the content should exist in the stage:

    • Single scene / Root layer: Use open_usd() to set the active root layer.
    • Runtime inline root layer (often with subLayers): Use open_usd_from_string*.
    • Additive removable content: Use add_usd_reference* at a specific prim path. You must keep the returned handle to call remove_usd later.
  7. Manage CUDA includes and file splitting

    main

    When using precompiled CUDA artifacts, you can split a single node across multiple files by compiling them with nvcc and shipping the resulting .ptx, .cubin, or .fatbin.

    Important Note on Includes: A CUDA node is treated as a single translation unit compiled against a single include directory. SPG searches for headers using the directory defined by the CUDA_PATH or CUDA_HOME environment variables, or the headers bundled with the renderer.

    The directory containing your .cu source file is NOT automatically added to the include path. Therefore, #include "MyHelpers.cuh" will fail if MyHelpers.cuh is located in the same folder as your source but not in the official CUDA include paths. To resolve this, compile your helpers into the artifact using your own toolchain before handing the binary to SPG.

  8. Understand lighting behavior in Minimal mode

    main

    Minimal mode uses a simplified lighting model to maintain speed and stability:

    • DistantLight: Only the first DistantLight found in the scene is respected. Shadows from this light are hard shadows.
    • DomeLight: DomeLight is ignored in Minimal mode.
    • Fallback: If no DistantLight is present, the mode falls back to a single camera light.

    To improve visibility without adding scene lights, you can adjust the global ambient lighting attributes or disable shadows using omni:rtx:minimal:castShadows.

  9. Correctly bounding work with the Count channel

    main

    When working with sensor composites like Lidar, point channels are often allocated for the worst-case capacity (the maximum possible returns).

    The Stride Problem

    For a channel like Coordinates, the shape is typically [3, Nmax]. The data is stored with a stride where all X values come first, then all Y, then all Z. The step between elements is the allocated capacity, not the number of valid points.

    The Solution: Use the Counts channel

    To avoid processing invalid data or reading out of bounds, you must bound your GPU work using the Counts channel:

    1. Access the Counts tensor via pc.tensors["Counts"].
    2. Pass the Counts tensor to the GPU.
    3. Apply the bound (the valid count) within your kernel.

    Note: The .status field is unreliable for determining if data exists for the current frame; always rely on the value in the Counts channel.

  10. Understand Non-Visual Sensors in ovrtx

    main

    Non-visual sensors in ovrtx (such as Lidar and Radar) are designed to produce structured sensor data instead of standard camera images.

    Key characteristics include:

    • Structured Data: They typically expose composite PointCloud RenderVars.
    • Named Tensors: These RenderVars contain specific named tensors for data like coordinates, counts, intensity, RCS (Radar Cross Section), radial velocity, and time offsets.
    • Material Modeling: You can use non-visual material labels to model how these sensors interact with surfaces (return behavior) independently of the visual shading used for cameras.
  11. How SPG Separable Blur handles radius changes

    main

    In this implementation, the blur radius is a USD attribute. Because inputs:radius is connected to nothing, writing a new value to the radius attribute on the Shader prim takes effect on the next render step without requiring a reset.

    To ensure exactness, the system verifies that at radius 0, the weight table is {1.0} (the identity), meaning the published AOV must match the LdrColor input byte-for-byte.

    # Example of writing a new radius to the Shader prim
    # (Snippet context from main.py)
    # [snippet:blur-write-radius]
  12. Configure attribute semantics and data types

    main

    When writing attributes, you must specify the correct AttributeSemantic to ensure the data is interpreted correctly by the USD schema.

    Common Semantics

    • Generic Data: AttributeSemantic.NONE / OVSTAGE_SEMANTIC_NONE / OVRTX_SEMANTIC_NONE.
    • Matrices: AttributeSemantic.MATRIX / OVSTAGE_SEMANTIC_MATRIX / OVRTX_SEMANTIC_XFORM_MAT4x4.
    • Tokens: AttributeSemantic.TOKEN_ID / OVSTAGE_SEMANTIC_TOKEN_ID / OVRTX_SEMANTIC_TOKEN_ID (use for interned token IDs).
    • Relationships: AttributeSemantic.RELATIONSHIP_PATH_ID / OVSTAGE_SEMANTIC_RELATIONSHIP_PATH_ID (write with is_array=true).
    • Strings: AttributeSemantic.STRING / OVSTAGE_SEMANTIC_STRING (UTF-8 bytes; write with is_array=true and dtype {kDLUInt, 8, 1}).
    • Assets: AttributeSemantic.ASSET_PATH_ID / OVSTAGE_SEMANTIC_ASSET_PATH_ID (interned (authored, resolved) pairs; write with is_array=false and dtype {kDLUInt, 64, 2}).

    Important Constraints

    • Array Authority: The .is_array flag in the write payload is the sole authority for fixed vs. array storage; it does not auto-derive from the DLTensor's shape.
    • Dtype Matching: Array attribute dtypes must exactly match the USD schema (e.g., do not use float64 for a float3[] attribute).
    • Quaternion Order: Use the ovrtx runtime lane order (i, j, k, real) for writes. This differs from USDA's authored (real, i, j, k) order.