Scene Partitions#
Scene partitions let cameras render separate environments from one stage, while sharing unpartitioned geometry and lighting. Use them to simulate independent robot environments without loading a separate stage for each one. Partitioning is enabled by default in ovrtx. Named partition selection is supported by Camera prims, including camera-based sensor models. Non-camera sensors cannot select a named partition.
Three cameras at the same viewpoint render the orange cube, the blue torus, or both. All three views share the ground and studio lighting.#
Each Camera prim selects one partition. That selection applies to every RenderProduct using the camera, including its tile in a product that renders several cameras.
Creating scene partitions#
Select a camera’s partition with omni:scenePartition. Assign geometry with
the primvars:omni:scenePartition token primvar. Primvars are inherited, so
you can assign an entire environment on its top-level Xform. A partition is
identified by its name: a camera and the geometry it should see carry the same
token.
USD declaration |
Description |
|---|---|
|
Author on a Camera to select the named partition that it renders. |
|
Author on geometry or an ancestor Xform to assign that content to a named partition. |
Neither attribute has a schema-generated accessor. Author them using the exact names and token types shown above.
With the default visibility settings:
A camera sees geometry assigned to its selected partition.
A camera does not see geometry assigned to another partition unless
showAllPartitionsByDefaultis enabled; see Viewing all partitions.Unpartitioned geometry remains visible to every camera.
A camera with a missing or empty selector sees only unpartitioned geometry.
Viewing all partitions changes these rules.
This excerpt from the example assigns the two objects to separate partitions and selects them with the left and right cameras. The third camera has no partition selector.
Both tabs author the same scene objects. Asset paths are relative to the
example directory; the Python snippet assumes an existing USD stage.
#usda 1.0
def Xform "World"
{
def Xform "Left" (
prepend references = @../../../tests/docs/data/cube.usd@
)
{
token primvars:omni:scenePartition = "left" (interpolation = "constant")
double3 xformOp:translate = (-115, 0, 0)
uniform token[] xformOpOrder = ["xformOp:translate"]
over "Cube"
{
color3f[] primvars:displayColor = [(0.9, 0.12, 0.025)]
}
}
def Xform "Right" (
prepend references = @../../../tests/docs/data/torus.usd@
)
{
token primvars:omni:scenePartition = "right" (interpolation = "constant")
double3 xformOp:translate = (115, 75, 0)
float3 xformOp:rotateXYZ = (90, 0, 0)
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"]
over "Torus"
{
color3f[] primvars:displayColor = [(0.025, 0.3, 0.85)]
}
}
def Xform "Ground" (
prepend references = @../../../tests/docs/data/ground.usd@
)
{
double3 xformOp:scale = (20, 1, 20)
uniform token[] xformOpOrder = ["xformOp:scale"]
}
def DomeLight "Environment"
{
float inputs:intensity = 1000
asset inputs:texture:file = @../../../tests/docs/data/studio.exr@
token inputs:texture:format = "latlong"
}
def Camera "LeftCamera"
{
custom token omni:scenePartition = "left"
float focalLength = 38
float2 clippingRange = (1, 100000)
double3 xformOp:translate = (0, 230, 850)
float3 xformOp:rotateXYZ = (-12, 0, 0)
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"]
}
def Camera "RightCamera"
{
custom token omni:scenePartition = "right"
float focalLength = 38
float2 clippingRange = (1, 100000)
double3 xformOp:translate = (0, 230, 850)
float3 xformOp:rotateXYZ = (-12, 0, 0)
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"]
}
def Camera "BothCamera"
{
float focalLength = 38
float2 clippingRange = (1, 100000)
double3 xformOp:translate = (0, 230, 850)
float3 xformOp:rotateXYZ = (-12, 0, 0)
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ"]
}
}
from pxr import Gf, Sdf, UsdGeom, UsdLux
UsdGeom.Xform.Define(stage, "/World")
left = UsdGeom.Xform.Define(stage, "/World/Left")
left.GetPrim().GetReferences().AddReference("../../../tests/docs/data/cube.usd")
UsdGeom.PrimvarsAPI(left).CreatePrimvar(
"omni:scenePartition", Sdf.ValueTypeNames.Token, UsdGeom.Tokens.constant
).Set("left")
left.AddTranslateOp().Set(Gf.Vec3d(-115, 0, 0))
UsdGeom.Mesh(stage.GetPrimAtPath("/World/Left/Cube")).CreateDisplayColorAttr(
[(0.9, 0.12, 0.025)]
)
right = UsdGeom.Xform.Define(stage, "/World/Right")
right.GetPrim().GetReferences().AddReference("../../../tests/docs/data/torus.usd")
UsdGeom.PrimvarsAPI(right).CreatePrimvar(
"omni:scenePartition", Sdf.ValueTypeNames.Token, UsdGeom.Tokens.constant
).Set("right")
right.AddTranslateOp().Set(Gf.Vec3d(115, 75, 0))
right.AddRotateXYZOp().Set(Gf.Vec3f(90, 0, 0))
UsdGeom.Mesh(stage.GetPrimAtPath("/World/Right/Torus")).CreateDisplayColorAttr(
[(0.025, 0.3, 0.85)]
)
ground = UsdGeom.Xform.Define(stage, "/World/Ground")
ground.GetPrim().GetReferences().AddReference("../../../tests/docs/data/ground.usd")
ground.AddScaleOp(UsdGeom.XformOp.PrecisionDouble).Set(Gf.Vec3d(20, 1, 20))
environment = UsdLux.DomeLight.Define(stage, "/World/Environment")
environment.CreateIntensityAttr(1000)
environment.CreateTextureFileAttr("../../../tests/docs/data/studio.exr")
environment.CreateTextureFormatAttr("latlong")
for name, partition in (("Left", "left"), ("Right", "right"), ("Both", None)):
camera = UsdGeom.Camera.Define(stage, f"/World/{name}Camera")
if partition is not None:
camera.GetPrim().CreateAttribute(
"omni:scenePartition", Sdf.ValueTypeNames.Token, custom=True
).Set(partition)
camera.CreateFocalLengthAttr(38)
camera.CreateClippingRangeAttr(Gf.Vec2f(1, 100000))
camera.AddTranslateOp().Set(Gf.Vec3d(0, 230, 850))
camera.AddRotateXYZOp().Set(Gf.Vec3f(-12, 0, 0))
Viewing all partitions#
A camera without a partition selector can render all partitions, for example
to provide an overview of several environments. Enable this with the following
scene-wide setting on the RenderSettings prim. The example uses
/Render/OmniverseGlobalRenderSettings; see global render settings for how that prim is
selected.
USD declaration |
Description |
|---|---|
|
Allow cameras without a partition selector to render partitioned geometry as well as unpartitioned geometry. |
OmniRtxSettingsGlobalCommonAPI_1 declares this setting. It also works as a
plain attribute without applying the schema, as in the example.
Warning
This scene-wide setting also affects cameras with a partition selector:
geometry from overlapping environments can appear in each other’s camera
views. Separate partition names do not preserve isolation when it is enabled.
Leave it false when cameras must remain isolated. Cameras without a
partition selector then see only unpartitioned geometry. Neural-reconstruction
volumes are an exception: partition assignments do not isolate them with
either value; see Supported object types.
Separating the environments’ geometry in world space does not guarantee isolation with this option enabled. The region a partition’s camera can see is sized using the largest partition extent along each axis, so geometry from another environment can remain visible even when the environments do not overlap. Large background meshes assigned to a partition can increase the separation needed.
The example enables this setting so that the third camera sees both objects.
Lighting#
Assign lights with primvars:omni:scenePartition on the light or an ancestor
Xform, just as for geometry. Partitioned lights illuminate their own
partition; unpartitioned lights provide shared lighting.
Dome lights use the following default policy:
A partition with its own dome lights uses those domes.
A partition without its own dome lights inherits the unpartitioned domes.
An unpartitioned camera uses the unpartitioned domes.
The example’s studio dome is unpartitioned, and neither object partition has its own dome. Both therefore inherit the studio lighting without needing a dome-light override. See Dome Light for dome properties.
Supported object types#
Meshes, curves, points, OpenVDB volumes, and ParticleFields support
scene partitioning through primvars:omni:scenePartition. Geometry instances
also carry their own partition assignment.
Partition bounds follow updated geometry bounds, including skinning and displacement.
Neural-reconstruction volumes are not isolated by scene partitions. Assigning a partition does not filter them from other cameras; their ordinary visibility rules still apply. See Limitations.
Non-camera sensors#
OmniLidar, OmniRadar and OmniAcoustic prims do not use
omni:scenePartition to select a partition. Authoring the attribute on one
of these prims does not isolate its measurements to the named environment.
Their rays use the rules for an unassigned partition:
|
Geometry available to the sensor’s rays |
|---|---|
|
Unpartitioned geometry only. Partitioned geometry is excluded. |
|
Unpartitioned geometry and all partitions at their world-space positions, without isolation between environments. |
The setting is scene-wide and also affects cameras. Enabling it does not provide independent lidar, radar or acoustic environments within one stage.