Switch Stored Patterns#
Change geometry, ray counts and receiver groups without replacing their stored arrays.
Before you start. Create the base sensor and output in Set Up a Sensor. The USD Python tab below adds the alternative patterns to that stage.
Stored pattern alternatives#
Store alternatives when different captures should use different geometry, ray counts or receiver connections. A stored transmitter pattern may contain several transmitter elements; selecting it activates that complete pattern, not one element within it. Receiver patterns are selected independently.
Each transmitter pattern also assigns its ray bundle and receiver-mapping rule.
Changing the transmitter selector also selects that pattern’s bundle and mapping
rule. When using map, a mapping-page change selects another page of receiver
groups. Refer to
patterns and selection
for the role-local indices and packed family arrays.
The layer below combines Free/Grid transmitter and receiver patterns, Free/Grid/Gaussian ray bundles, and two mapping pages. Switching uses the three scalar selectors rather than replacing the arrays:
#usda 1.0
(
defaultPrim = "World"
metersPerUnit = 1
upAxis = "Z"
timeCodesPerSecond = 10
subLayers = [@generic_wpm_base.usda@]
)
over "World"
{
over "Sensor"
{
# Role order consumes successive rows from each named family.
token[] omni:sensor:GenericWpm:tx:patternTypes = ["free", "grid", "free"]
uint[] omni:sensor:GenericWpm:freePatterns:tx:numElementsPerPattern = [1, 1]
float3[] omni:sensor:GenericWpm:freePatterns:tx:positions = [(0, 0, 0), (0, 0.2, 0)]
float4[] omni:sensor:GenericWpm:freePatterns:tx:orientations = [(0, 0, 0, 1), (0, 0, 0, 1)]
token[] omni:sensor:GenericWpm:gridPatterns:tx:modes = ["PLANAR"]
uint[] omni:sensor:GenericWpm:gridPatterns:tx:numRows = [1]
uint[] omni:sensor:GenericWpm:gridPatterns:tx:numCols = [2]
float[] omni:sensor:GenericWpm:gridPatterns:tx:startRowUnits = [0]
float[] omni:sensor:GenericWpm:gridPatterns:tx:endRowUnits = [0]
float[] omni:sensor:GenericWpm:gridPatterns:tx:startColUnits = [-0.5]
float[] omni:sensor:GenericWpm:gridPatterns:tx:endColUnits = [0.5]
token[] omni:sensor:GenericWpm:gridPatterns:tx:layouts = ["rowMajor"]
float3[] omni:sensor:GenericWpm:gridPatterns:tx:positions = [(0, 0, 0)]
float4[] omni:sensor:GenericWpm:gridPatterns:tx:orientations = [(0, 0, 0, 1)]
token[] omni:sensor:GenericWpm:rx:patternTypes = ["free", "grid"]
uint[] omni:sensor:GenericWpm:freePatterns:rx:numElementsPerPattern = [3]
float3[] omni:sensor:GenericWpm:freePatterns:rx:positions = [(0, -1, 0), (0, 0, 0), (0, 1, 0)]
float4[] omni:sensor:GenericWpm:freePatterns:rx:orientations = [(0, 0, 0, 1), (0, 0, 0, 1), (0, 0, 0, 1)]
token[] omni:sensor:GenericWpm:gridPatterns:rx:modes = ["PLANAR"]
uint[] omni:sensor:GenericWpm:gridPatterns:rx:numRows = [1]
uint[] omni:sensor:GenericWpm:gridPatterns:rx:numCols = [2]
float[] omni:sensor:GenericWpm:gridPatterns:rx:startRowUnits = [0]
float[] omni:sensor:GenericWpm:gridPatterns:rx:endRowUnits = [0]
float[] omni:sensor:GenericWpm:gridPatterns:rx:startColUnits = [-0.5]
float[] omni:sensor:GenericWpm:gridPatterns:rx:endColUnits = [0.5]
token[] omni:sensor:GenericWpm:gridPatterns:rx:layouts = ["rowMajor"]
float3[] omni:sensor:GenericWpm:gridPatterns:rx:positions = [(0, 0, 0)]
float4[] omni:sensor:GenericWpm:gridPatterns:rx:orientations = [(0, 0, 0, 1)]
token[] omni:sensor:GenericWpm:ray:patternTypes = ["free", "grid", "gaussian"]
uint[] omni:sensor:GenericWpm:freePatterns:ray:numElementsPerPattern = [1]
float3[] omni:sensor:GenericWpm:freePatterns:ray:positions = [(0, 0, 0)]
float4[] omni:sensor:GenericWpm:freePatterns:ray:orientations = [(0, 0, 0, 1)]
token[] omni:sensor:GenericWpm:gridPatterns:ray:modes = ["SPHERICAL"]
uint[] omni:sensor:GenericWpm:gridPatterns:ray:numRows = [1]
uint[] omni:sensor:GenericWpm:gridPatterns:ray:numCols = [3]
float[] omni:sensor:GenericWpm:gridPatterns:ray:startRowUnits = [0]
float[] omni:sensor:GenericWpm:gridPatterns:ray:endRowUnits = [0]
float[] omni:sensor:GenericWpm:gridPatterns:ray:startColUnits = [-5]
float[] omni:sensor:GenericWpm:gridPatterns:ray:endColUnits = [5]
token[] omni:sensor:GenericWpm:gridPatterns:ray:layouts = ["rowMajor"]
float3[] omni:sensor:GenericWpm:gridPatterns:ray:positions = [(0, 0, 0)]
float4[] omni:sensor:GenericWpm:gridPatterns:ray:orientations = [(0, 0, 0, 1)]
uint[] omni:sensor:GenericWpm:gaussianPatterns:ray:numElements = [9]
uint[] omni:sensor:GenericWpm:gaussianPatterns:ray:seeds = [7]
float[] omni:sensor:GenericWpm:gaussianPatterns:ray:stdDevsHorizontal = [1]
float[] omni:sensor:GenericWpm:gaussianPatterns:ray:stdDevsVertical = [0.5]
float3[] omni:sensor:GenericWpm:gaussianPatterns:ray:positions = [(0, 0, 0)]
float4[] omni:sensor:GenericWpm:gaussianPatterns:ray:orientations = [(0, 0, 0, 1)]
# Tx role patterns 0, 1, 2 select Free, Grid, Gaussian ray bundles.
uint[] omni:sensor:GenericWpm:tx:rayPatternIndices = [0, 1, 2]
token[] omni:sensor:GenericWpm:tx:mappingModes = ["map", "map", "map"]
uint[] omni:sensor:GenericWpm:tx:mappingTargetRxGroups = [1, 0, 1]
uint[] omni:sensor:GenericWpm:txRxMappings:numRxGroupsPerPages = [2, 2]
uint[] omni:sensor:GenericWpm:txRxMappings:numRxPerGroups = [3, 2, 1, 2]
# Page 0: [0,1,2], [2,0]. Page 1: [1], [0,1].
uint[] omni:sensor:GenericWpm:txRxMappings:rxIndices = [0, 1, 2, 2, 0, 1, 0, 1]
}
}
sensor = stage.GetPrimAtPath("/World/Sensor")
ns = "omni:sensor:GenericWpm:"
# Role order consumes successive rows from each named family.
sensor.CreateAttribute(ns + "tx:patternTypes", Sdf.ValueTypeNames.TokenArray, custom=False).Set(
["free", "grid", "free"]
)
sensor.CreateAttribute(ns + "rx:patternTypes", Sdf.ValueTypeNames.TokenArray, custom=False).Set(["free", "grid"])
sensor.CreateAttribute(ns + "ray:patternTypes", Sdf.ValueTypeNames.TokenArray, custom=False).Set(
["free", "grid", "gaussian"]
)
for role, counts, positions in (
("tx", [1, 1], [(0, 0, 0), (0, 0.2, 0)]),
("rx", [3], [(0, -1, 0), (0, 0, 0), (0, 1, 0)]),
("ray", [1], [(0, 0, 0)]),
):
free = ns + "freePatterns:" + role + ":"
sensor.CreateAttribute(free + "numElementsPerPattern", Sdf.ValueTypeNames.UIntArray, custom=False).Set(counts)
sensor.CreateAttribute(free + "positions", Sdf.ValueTypeNames.Float3Array, custom=False).Set(positions)
sensor.CreateAttribute(free + "orientations", Sdf.ValueTypeNames.Float4Array, custom=False).Set(
[(0, 0, 0, 1)] * len(positions)
)
for role, mode, columns, first, last in (
("tx", "PLANAR", 2, -0.5, 0.5),
("rx", "PLANAR", 2, -0.5, 0.5),
("ray", "SPHERICAL", 3, -5, 5),
):
grid = ns + "gridPatterns:" + role + ":"
sensor.CreateAttribute(grid + "modes", Sdf.ValueTypeNames.TokenArray, custom=False).Set([mode])
sensor.CreateAttribute(grid + "numRows", Sdf.ValueTypeNames.UIntArray, custom=False).Set([1])
sensor.CreateAttribute(grid + "numCols", Sdf.ValueTypeNames.UIntArray, custom=False).Set([columns])
sensor.CreateAttribute(grid + "startRowUnits", Sdf.ValueTypeNames.FloatArray, custom=False).Set([0])
sensor.CreateAttribute(grid + "endRowUnits", Sdf.ValueTypeNames.FloatArray, custom=False).Set([0])
sensor.CreateAttribute(grid + "startColUnits", Sdf.ValueTypeNames.FloatArray, custom=False).Set([first])
sensor.CreateAttribute(grid + "endColUnits", Sdf.ValueTypeNames.FloatArray, custom=False).Set([last])
sensor.CreateAttribute(grid + "layouts", Sdf.ValueTypeNames.TokenArray, custom=False).Set(["rowMajor"])
sensor.CreateAttribute(grid + "positions", Sdf.ValueTypeNames.Float3Array, custom=False).Set([(0, 0, 0)])
sensor.CreateAttribute(grid + "orientations", Sdf.ValueTypeNames.Float4Array, custom=False).Set([(0, 0, 0, 1)])
ray = ns + "gaussianPatterns:ray:"
sensor.CreateAttribute(ray + "numElements", Sdf.ValueTypeNames.UIntArray, custom=False).Set([9])
sensor.CreateAttribute(ray + "seeds", Sdf.ValueTypeNames.UIntArray, custom=False).Set([7])
sensor.CreateAttribute(ray + "stdDevsHorizontal", Sdf.ValueTypeNames.FloatArray, custom=False).Set([1])
sensor.CreateAttribute(ray + "stdDevsVertical", Sdf.ValueTypeNames.FloatArray, custom=False).Set([0.5])
sensor.CreateAttribute(ray + "positions", Sdf.ValueTypeNames.Float3Array, custom=False).Set([(0, 0, 0)])
sensor.CreateAttribute(ray + "orientations", Sdf.ValueTypeNames.Float4Array, custom=False).Set([(0, 0, 0, 1)])
# Tx role patterns 0, 1, 2 select Free, Grid, Gaussian ray bundles.
sensor.CreateAttribute(ns + "tx:rayPatternIndices", Sdf.ValueTypeNames.UIntArray, custom=False).Set([0, 1, 2])
sensor.CreateAttribute(ns + "tx:mappingModes", Sdf.ValueTypeNames.TokenArray, custom=False).Set(
["map", "map", "map"]
)
sensor.CreateAttribute(ns + "tx:mappingTargetRxGroups", Sdf.ValueTypeNames.UIntArray, custom=False).Set([1, 0, 1])
mapping = ns + "txRxMappings:"
sensor.CreateAttribute(mapping + "numRxGroupsPerPages", Sdf.ValueTypeNames.UIntArray, custom=False).Set([2, 2])
sensor.CreateAttribute(mapping + "numRxPerGroups", Sdf.ValueTypeNames.UIntArray, custom=False).Set([3, 2, 1, 2])
# Page 0: [0,1,2], [2,0]. Page 1: [1], [0,1].
sensor.CreateAttribute(mapping + "rxIndices", Sdf.ValueTypeNames.UIntArray, custom=False).Set(
[0, 1, 2, 2, 0, 1, 0, 1]
)
The stored pages contain groups [0, 1, 2] and [2, 0] on page 0,
and [1] and [0, 1] on page 1. The following selections are valid:
Tx / Rx / page |
Active Tx / Rx |
Rays per Tx |
Ordered Rx IDs |
Slots |
|---|---|---|---|---|
|
1 / 3 |
1 (Free) |
|
2 |
|
2 / 2 |
3 (Grid) |
|
6 |
|
1 / 2 |
9 (Gaussian) |
|
18 |
For the initial selection, transmitter pattern 0 assigns ray bundle 0 and
page-local group 1. Page 0’s first group consumes the first three entries of
rxIndices, so group 1 reads entries 3 and 4: receiver IDs [2, 0].
Its two slots address elements of receiver pattern 0, not stored global IDs.
Requesting 0 / 1 / 0 is invalid because page 0 includes receiver ID 2 while
receiver pattern 1 has only two elements. If the previous accepted selection
was 2 / 1 / 1, it remains active with 18 slots. Selecting 0 / 0 / 0
again returns to two slots. This demonstrates why page and receiver selections
must be coordinated and why output metadata reports the accepted selectors.
Publish coordinated edits#
Write all related selectors at one new ordinal, finish the writes, and advance the write floor once before rendering. Do not step between those writes. The paired Python and C example shows this sequence. Read the accepted selector parameters from the completed output before deciding that an edit took effect. Attribute meanings are on USD Attributes; complete types and defaults are in Sensor API Schemas.
Verification#
Run the example with live edits.
The requested selector triplets are
0/0/0,1/1/1,2/1/1,0/1/0and0/0/0.Read the accepted triplet and capacity after each request: capacities are 2, 6, 18, 18 and 2.
The invalid fourth request must retain
2/1/1; the final request must restore0/0/0.This verifies configuration acceptance rather than a scene-dependent valid-return count.
Potential issues#
Use the Generic wpm checks for confirming checks and recovery.
The accepted selectors stay unchanged. A rejected batch retains the complete previously accepted configuration while the scene continues to advance. Refer to configuration acceptance.