11. Visualizing Live Data

11.1. Learning Objectives

This tutorial shares the best practices for visualizing large amounts of geometry that is frequently updating — like from sensor data. After this tutorial, you will know the different methods for efficiently updating geometry, and in whcich scenarios to use them.

5-10 Minute Tutorial

11.2. Getting Started

There are three primary APIs you should use when making frequent updates to large amounts of geometry: UsdGeom.Points, UsdGeom.PointInstancer, and DebugDraw. The different advantages and limitations of each of these methods are explained below, and can help guide you on which method to use.

11.3. UsdGeom.Points

Use the UsdGeom.Points API when the geometry needs to interact with the renderer. The UsdGeom.Points API is the most efficient method to render large amounts of point geometry.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import random
import omni.usd
from pxr import UsdGeom

def create(self):
    # Create Point List
    N = 500
    self.point_list = [(random.uniform(-100, 100), 0, random.uniform(-50, 50)) for _ in range(N)]
    self.sizes = [5 for _ in range(N)]

    points_path = "/World/Points"
    stage = omni.usd.get_context().get_stage()
    self.points = UsdGeom.Points.Define(stage, points_path)
    self.points.CreatePointsAttr().Set(self.point_list)
    self.points.CreateWidthsAttr().Set(self.sizes)
    self.points.CreateDisplayColorPrimvar("constant").Set([(1, 0, 1)])

def update(self):
    # modify the point list
    for i in range(len(self.point_list)):
        self.point_list[i][1] = random.uniform(-5,5)
    # update the points
    self.points.GetPointsAttr().Set(self.point_list)

11.4. UsdGeom.PointInstancer

Use the UsdGeom.PointInstancer API when the geometry needs to interact with the physics scene. The UsdGeom.PointInstancer API lets you efficiently replicate an instance of a prim — with all of its USD properties — and update all instances with a list of positions, colors, and sizes.

Below are code snippets for how to create and update geometry with UsdGeom.PointInstancer:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import random
import omni.usd
from pxr import UsdGeom

def create(self):
    # Create Point List
    N = 500
    self.point_list = [(random.uniform(-100, 100), 0, random.uniform(-50, 50)) for _ in range(N)]
    self.colors = [(1, 1, 1, 1) for _ in range(N)]
    self.sizes = [5 for _ in range(N)]

    # Set up Geometry to be Instanced
    cube_path = "/World/Cube"
    cube = UsdGeom.Cube(stage.DefinePrim(cube_path, "Cube"))
    cube.AddScaleOp().Set(Gf.Vec3d(1, 1, 1) * scalar)
    cube.CreateDisplayColorPrimvar().Set([(0, 1, 1)])
    # Set up Point Instancer
    stage = omni.usd.get_context().get_stage()
    instance_path = "/World/PointInstancer"
    self.point_instancer = UsdGeom.PointInstancer(stage.DefinePrim(instance_path, "PointInstancer"))
    # Create & Set the Positions Attribute
    self.positions_attr = self.point_instancer.CreatePositionsAttr()
    self.positions_attr.Set(self.point_list)
    # Set the Instanced Geometry
    self.point_instancer.CreatePrototypesRel().SetTargets([cube.GetPath()])
    self.proto_indices_attr = self.point_instancer.CreateProtoIndicesAttr()
    self.proto_indices_attr.Set([0] * len(self.point_list))

def update(self):
    # modify the point list
    for i in range(len(self.point_list)):
        self.point_list[i][1] = random.uniform(-5,5)
    # update the points
    self.positions_attr.Set(self.point_list)

11.5. DebugDraw

The Debug Drawing Helper API is useful for purely visualizing geometry in the Viewport. Geometry drawn with the debug_draw_interface cannot be rendered and does not interact with the physics scene. However, it is the most performance-efficient method of visualizing geometry.

Below are code snippets for how to create and update geometry visualed with DebugDraw:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import random
from omni.isaac.debug_draw import _debug_draw

def create(self):
    self.draw = _debug_draw.acquire_debug_draw_interface()
    N = 500
    self.point_list = [(random.uniform(-100, 100), 0, random.uniform(-50, 50)) for _ in range(N)]
    self.colors = [(1, 1, 1, 1) for _ in range(N)]
    self.sizes = [5 for _ in range(N)]

def update(self):
    # modify the point list
    for i in range(len(self.point_list)):
        self.point_list[i][1] = random.uniform(-5,5)

    # draw the points
    self.draw.clear_points()
    self.draw.draw_points(self.point_list, self.color_list, self.size_list)

See the API Documentation for complete usage information.

11.6. Summary

This tutorial covered three different ways to visualize frequently updating geometry in Omniverse Isaac Sim:

  1. Use the UsdGeom.Points API when the geometry need to be rendered.

  2. Use the UsdGeom.PointInstancer API when the geometry need to interact with the physics scene.

  3. Use the DebugDraw API when the geometry is for visualization purposes only.

11.7. Further Learning

See the PointInstancer Tutorial for more hands-on learning with the PointInstancer API.