Exercise: Authoring Point Instancing#

Introduction#

In this exercise, you will learn how to create a PointInstancer from a JSON file that emulates exported data from a simulation application. Point instancing is a powerful technique for efficiently representing large numbers of similar objects. You’ll read scatter data of boxes and pallets and create a PointInstancer prim. This technique is essential for handling massive datasets in production workflows.

Exploring the Point Instancer Script#

  1. Open instancing/ex_pt_author/author_point_instancer.py in VSCode to inspect the code.

author_point_instancer.py#
16import json
17from pathlib import Path
18
19from pxr import Usd, UsdGeom, Gf, Sdf
20
21exercise_dir = Path(__file__).parent
22
23with open(str(exercise_dir / "points_export.json")) as f:
24    export_data = json.load(f)
25
26stage = Usd.Stage.Open(str(exercise_dir / "Scenario.usd"))
27stage_path = Path(stage.GetRootLayer().identifier)
28
29# Create PointInstancer
30pi = UsdGeom.PointInstancer.Define(stage, "/World/Scatter")
31# Create prototypes container
32prototypes_prim = UsdGeom.Scope.Define(stage, pi.GetPath().AppendChild("Prototypes"))
33# Reference the CubeBox_A04_26cm asset to use as a prototype
34box = stage.DefinePrim(prototypes_prim.GetPath().AppendChild("CubeBox_A04_26cm"))
35box_asset_path = stage_path.parent.parent / "src_assets" / "Assets" / "Components" / "CubeBox_A04_26cm" / "CubeBox_A04_26cm.usd"
36box.GetReferences().AddReference(str(box_asset_path))
37# Reference the BlockPallet_A07 asset to use as a prototype
38pallet = stage.DefinePrim(prototypes_prim.GetPath().AppendChild("BlockPallet_A07"))
39pallet_asset_path = stage_path.parent.parent / "src_assets" / "Assets" / "Components" / "BlockPallet_A07" / "BlockPallet_A07.usd"
40pallet.GetReferences().AddReference(str(pallet_asset_path))
41
42# Fill in PointInstancer with exported data.
43# Required properties: prototypes, protoIndices, positions 
44proto_rel = pi.CreatePrototypesRel()
45proto_rel.SetTargets([
46    box.GetPath(),
47    pallet.GetPath()
48])
49pi.CreatePositionsAttr(export_data['positions'])
50pi.CreateProtoIndicesAttr(export_data['proto_ids'])
51pi.CreateOrientationsAttr([Gf.Quath(*vector) for vector in export_data['orientations']])
52
53prototypes_prim.GetPrim().SetSpecifier(Sdf.SpecifierOver)
54
55stage.Save()

The script reads position, orientation, and prototype data from a JSON file, then creates a PointInstancer with two prototypes (a box and a pallet) and populates it with thousands of instances. This demonstrates how to efficiently create thousands of instances of individual assets using a PointInstancer.

Running the Point Instancer Script#

  1. Run in the terminal:

Windows:

python .\instancing\ex_pt_author\author_point_instancer.py

Linux:

python ./instancing/ex_pt_author/author_point_instancer.py

You shouldn’t notice any additional output in the terminal or file system. We will open up Scenario.usd in usdview to see what the script did.

Viewing the Point Instancer Results#

  1. Run in the terminal:

Windows:

.\scripts\usdview.bat .\instancing\ex_pt_author\Scenario.usd --camera ExCam_01

Linux:

./scripts/usdview.sh ./instancing/ex_pt_author/Scenario.usd --camera ExCam_01

Notice how the scattered boxes and pallets are now represented as a single PointInstancer prim, dramatically reducing the scene complexity while maintaining the same visual appearance as if we had used scenegraph instancing.

  1. Close usdview.

Conclusion#

You’ve successfully learned how to create PointInstancers from exported data, a crucial technique for handling large-scale scenes efficiently. PointInstancer can represent 100,000s of objects with minimal memory overhead while maintaining full visual fidelity, making this approach essential for production workflows with massive datasets.