Outputs#

The Lidar generic wpm model delivers one PointCloud composite output per requesting RenderVar. It supports no other output type. Each entry is one return from a pulse sent by an emitter row of the firing pattern. This page lists the channels, parameters and compact, dense and tiled layouts. See USD Attributes for the controls that select them.

Sensor Outputs explains mapping, DLPack tensors, params, Counts and validity flags. See Output Configuration for RenderProduct and RenderVar setup, and the C API or Python API for container definitions.

The model supports eight selectable channels:

  • Coordinates

  • Intensity

  • TimeOffsetNs

  • Flags

  • ChannelId

  • MaterialId

  • EchoId

  • FiringPatternIndex

Every output also includes Counts. Compact output additionally includes TilePointCounts and TilePointOffsets.

The model does not provide EmitterId, TickId, TickState, ObjectId, HitNormal, Velocity, backscatter or Reflectivity. See Lidar generic core outputs for that model’s channels, tensor layouts and parameters.

Requesting the output#

You request the output with a RenderVar whose sourceName is PointCloud. How channels are requested on Output Configuration explains the channels attribute in general; this model reads the list as follows.

  • An empty channels list selects all eight channels.

  • An explicit list selects the channels you named, and Flags is added whether or not you named it.

  • Counts, an int32 tensor of shape [1], is published with every output whether or not it was asked for. In compact output, the default, TilePointCounts and TilePointOffsets are published as well; see Compact layout.

  • Only the eight names are produced. A name from another model’s set, or a misspelling, is not delivered, so when a channel is missing from the mapped output, check its spelling and case against the table below.

  • An explicit list must name at least one of the eight channels; Counts, TilePointCounts and TilePointOffsets come with every output but do not count as names here. A list that names none of the eight is rejected and the reason is logged as an error; correct the list before the sensor can publish.

For an existing WPM lidar at /Lidar, this example requests coordinates, intensity and firing-time offsets. Flags and Counts are included automatically, along with the tile tensors when using compact output.

#usda 1.0
def RenderProduct "LidarProduct"
{
    rel camera = </Lidar>
    rel orderedVars = [</PointCloud>]
}

def RenderVar "PointCloud"
{
    uniform string sourceName = "PointCloud"
    token[] channels = ["Coordinates", "Intensity", "TimeOffsetNs"]
}
from pxr import Sdf, UsdRender

product = UsdRender.Product.Define(stage, "/LidarProduct")
# Target the existing WPM lidar prim.
product.GetCameraRel().SetTargets(["/Lidar"])
point_cloud = UsdRender.Var.Define(stage, "/PointCloud")
point_cloud.GetSourceNameAttr().Set("PointCloud")
# Select channels; Flags and Counts are included automatically.
point_cloud.GetPrim().CreateAttribute(
    "channels", Sdf.ValueTypeNames.TokenArray, custom=False
).Set(["Coordinates", "Intensity", "TimeOffsetNs"])
product.GetOrderedVarsRel().SetTargets([point_cloud.GetPath()])

The rotary example on Configure a Firing Pattern requests the default set with token[] channels = []; its solid-state example names six channels explicitly.

Multiple PointCloud outputs#

One RenderProduct can request several PointCloud RenderVars with separate channels lists. The model runs one scan and computes their combined channel set, then publishes each RenderVar’s selected channels with Flags, Counts and, for compact output, tile tensors. All outputs contain the same points: counts and slot indices agree. Outputs are identified by RenderVar prim path.

Channels#

In the shapes below, Nmax is the point capacity, published as the maxPoints param: the number of slots the output has room for, not the number of returns it holds. Which slots carry a return depends on the layout: in compact output read the first Counts[0] slots, in dense output select by Flags. Both layouts are described further down.

Channel

Type

Shape

Unit

Meaning

Coordinates

float32

[Nmax, 3]

m, deg

Cartesian [xM, yM, zM] or ISO 8855 spherical [azimuthDeg, elevationDeg, rangeM], in the configured frame of reference; point-first.

Intensity

float32

[Nmax]

unitless

Presented intensity in the configured processing mode.

TimeOffsetNs

int32

[Nmax]

ns

Firing time of the return relative to the output’s timestampNs.

Flags

uint8

[Nmax]

unitless

Validity: the valid bit is set on a slot that holds a return.

ChannelId

uint32

[Nmax]

unitless

The detector channel id of the emitter row, exactly as authored on the firing pattern.

MaterialId

uint32

[Nmax]

unitless

Encoded non-visual material identifier of the hit surface.

EchoId

uint8

[Nmax]

unitless

Index of the return among the returns of its emitter row, from 0, in the order the return-processing mode defines (below).

FiringPatternIndex

uint8

[Nmax]

unitless

Zero-based position of the pattern that fired the return, in the lexicographic order of the pattern instance names.

Coordinates has shape [Nmax, 3], with each point’s three components adjacent in memory. Use the descriptor’s strides when reading it. SPHERICAL encoding (default) stores [azimuthDeg, elevationDeg, rangeM]; CARTESIAN stores [xM, yM, zM]. Both use the configured reference frame. See the ISO 8855 sensor convention for axes and angular units.

The Lidar generic core model uses component-first packing ([3, Nmax]). A reader must account for this difference when switching models; see tensor packing.

Intensity uses the configured processing, mapping and scale. These settings are not reported in the output, so the consumer must retain them. omni:sensor:LidarWpm:intensityProcessing selects rangeNormalized (default) or raw; mapping and scale control the reported value. There is no separate reflectivity or backscatter channel. See Tune Intensity for the conventions. These settings do not change return detection.

TimeOffsetNs records each return’s firing time relative to timestampNs, the scan start. Request it when the consumer performs motion compensation. The signed 32-bit nanosecond count has a maximum of 2147483647 ns, about 2.147 s. Keep the scan rate at or above roughly 0.47 Hz to avoid exceeding that range. Other models use different reference times for this channel; see shared channel names.

Flags marks valid returns with the VALID bit (0x40). This model sets no other bits. Test the bit as described in Checking validity; see the compact and dense layouts for which slots to read.

ChannelId reports the detector channel id authored on the firing pattern. Ids are labels, not indices; see channel-id constraints and cost on USD Attributes. Dense output writes 0 to invalid slots, but 0 is also a valid detector id. Select valid slots with Flags before reading ChannelId.

MaterialId identifies the hit surface’s non-visual material. It uses the same encoding as the Lidar generic core model; see its bit layout and decoding example. Only the two lidar models report material ids. See Non-Visual Sensor Materials for the meaning of 0 and how to verify material labels.

EchoId numbers the returns retained by an emitter row, from 0 to maxReturns - 1. In waveform mode, returns are ordered by decreasing detected signal strength, with nearer returns first on ties, including saturation. This signal is the value reported by raw intensity processing (Tune Intensity); rangeNormalized intensity need not decrease with EchoId. In the two direct modes, returns follow the order in which the pulse’s path encountered their surfaces. EchoId is a uint8, which limits omni:sensor:LidarWpm:maxReturns; see the scan-schedule table on USD Attributes.

FiringPatternIndex is the zero-based position of the firing-pattern instance in lexicographic order, which also determines firing order. Adding, removing or renaming an earlier instance shifts later indices. Do not use it as a persistent pattern identifier. Dense output fills it for every slot, including invalid slots, using the pattern of that slot’s emitter row.

Coordinates and motion compensation#

Four attributes under omni:sensor:LidarWpm: control the returned coordinates:

  • elementsCoordsType: Cartesian or spherical coordinates.

  • outputFrameOfReference: sensor, world or custom reference frame.

  • customFrameOfReferenceTrafo: the transform used for the custom frame.

  • outputMotionCompensationState: whether to compensate for sensor motion during the scan.

See coordinate attributes for values, units and defaults.

Each point is reconstructed in Cartesian sensor coordinates from the receiver’s direction and the detected range. The reference-frame and compensation settings then determine its transform, as shown below. The transformed point is returned in the selected Cartesian or spherical representation.

The table uses two sensor poses:

  • Scan-start pose: the sensor pose at the output’s timestampNs.

  • Fire-time pose: the sensor pose at the return’s firing time, interpolated over the scan’s motion interval.

Set outputMotionCompensationState to true to enable compensation or false to disable it.

Reference frame

Compensation disabled

Compensation enabled

SENSOR

Return the point in its original sensor coordinates.

Transform the point to world coordinates using its fire-time pose, then into the scan-start sensor frame. This removes distortion caused by sensor motion during the scan (deskewing).

WORLD

Transform all points using the scan-start pose.

Transform each point using its fire-time pose.

CUSTOM

Apply the custom transform to the point’s original sensor coordinates.

Compensate as for SENSOR, then apply the custom transform.

The defaults are SPHERICAL coordinates in the SENSOR frame with compensation disabled. Azimuth, elevation and range then come directly from the receiver direction and detected range, without a sensor-motion correction. Other settings transform the point before encoding it. Spherical coordinates in WORLD or CUSTOM are measured from the selected frame’s origin.

Compensation corrects sensor motion, not target motion. It has no effect when the sensor is stationary. The output parameters coordsType, frameOfReference and motionCompensationState report the settings used.

An accepted edit to these four attributes applies to all detected and deferred returns in the next published output. Each point cloud uses one coordinate encoding. The edit preserves validity, Counts, ChannelId, EchoId, FiringPatternIndex and return order. See presentation-only updates for these updates and Retune the Sensor While It Runs for rejection behavior.

Motion#

Motion within a frame requires the renderer’s motion BVH, selected at renderer creation. See motion BVH configuration and Motion Artifacts for examples with and without it.

Without motion BVH, the model still publishes outputs. Each frame traces from the sensor’s end pose against a static scene, so its points contain no intra-frame motion effects, even though TimeOffsetNs retains the firing times. Tile start poses come from the end of the scan’s first frame; end poses come from the end of its latest contributing frame. These can differ across a multi-frame scan, and motion compensation interpolates between them. Enable motion BVH when evaluating motion effects or deskewing.

Params#

Output parameters apply to the entire point cloud and are stored in CPU memory. See parameter access. This model publishes the thirteen shared params, the lidar-specific compactionType and motionCompensationState, and additional tile and layout params listed below. Read params by name and ignore unrecognized names.

Param

Type

Shape

Meaning

maxPoints

uint32

[1]

The point capacity Nmax: tileCount x receiversPerTile x maxReturns. Every point channel has room for this many slots.

frameId

uint64

[1]

Always 0 for this model. Order outputs by timestampNs.

timestampNs

uint64

[1]

The start time of the scan the returns belong to, in nanoseconds; TimeOffsetNs is measured from it. With instantLidar it is the end of the frame, the instant at which the whole scan is traced.

modality

uint32

[1]

1, lidar.

compactionType

uint32

[1]

2 compacted (includeInvalidPoints false, the default) or 1 uncompacted (true): the inverse of the attribute.

frameStartTimeStampNs

uint64

[1]

Start of the first frame window that contributed to the published scan. For a scan delivered whole and stepped at its own period or a divisor of it, this is timestampNs. With instantLidar it is the frame’s end.

frameEndTimeStampNs

uint64

[1]

End of the latest frame window that contributed. For a completed scan with instantLidar off it is timestampNs plus the scan period; with instantLidar it is the frame’s end. With partialOutputs true it advances with every published window.

frameStartPosM, frameEndPosM

float32

[3]

Tile zero’s position at the two bounds of the interval, in meters, in the world frame.

frameStartOrientation, frameEndOrientation

float32

[4]

Tile zero’s orientation at the two bounds, as a unit quaternion ordered x, y, z, w.

tileFrameStartPosM, tileFrameEndPosM

float32

[tileCount, 3]

One start and one end position per tile, in meters, in rel camera order: the scan-wide motion interval that compensated conversion interpolates over.

tileFrameStartOrientation, tileFrameEndOrientation

float32

[tileCount, 4]

One start and one end orientation per tile, x, y, z, w, in the same order.

frameOfReference

uint16

[1]

0 SENSOR, 1 WORLD, 2 CUSTOM.

modelToAppTransform

float32

[4, 4]

The identity for this model.

motionCompensationState

uint16

[1]

0 non-compensated, 1 compensated.

coordsType

uint32

[1]

0 Cartesian, 1 spherical (the default).

tileIndex

uint32

[1]

Always 0: the whole aggregate is one output.

tileCount

uint32

[1]

The number of sensors in the product’s rel camera; 1 for a single sensor.

receiversPerTile

uint32

[1]

The number of emitter rows the schedule keeps for one sensor, every tick of a rotary scan and every pattern of a solid-state one, after subsampling.

maxReturns

uint32

[1]

The return capacity per emitter row, the authored omni:sensor:LidarWpm:maxReturns.

validPointCount

uint32

[1]

The slot capacity of the published layout, equal to maxPoints, or 0 in the empty output. It is not the number of valid returns; that is Counts[0].

tileStridePoints

uint32

[1]

Dense output: the slot distance between tiles, receiversPerTile x maxReturns. 0 in compact output.

receiverStridePoints

uint32

[1]

Dense output: the slot distance between emitter rows, maxReturns. 0 in compact output.

Which steps deliver an output follows from omni:sensor:LidarWpm:partialOutputs and omni:sensor:LidarWpm:instantLidar, explained under output shaping on USD Attributes. Sensor Scheduling covers stepping sensors that deliver at different rates.

Compact layout#

Compact output is the default (omni:sensor:LidarWpm:includeInvalidPoints = false). Valid returns occupy slots [0, Counts[0]), ordered by tile, then emitter row, then return within the row. Compaction preserves that order.

Read only the first Counts[0] entries. The remaining slots have zero Flags and unspecified channel values; see read bounds. Point tensors retain their capacity shapes, [Nmax] or [Nmax, 3], regardless of the return count. compactionType is 2.

Two additional tensors locate each tile’s returns in rel camera order:

  • TilePointCounts: a uint64 tensor of shape [tileCount] containing the number of returns from each tile. Its entries sum to Counts[0].

  • TilePointOffsets: a uint64 tensor of shape [tileCount + 1]. Tile t occupies slots [TilePointOffsets[t], TilePointOffsets[t + 1]). The first offset is 0 and the last is Counts[0].

For one sensor, these tensors contain [Counts[0]] and [0, Counts[0]], respectively.

The dense and the compact point layout of a two-tile aggregate with three emitter rows per tile and two returns per row: above, twelve capacity slots in tile-major, row-major, return-major order with the valid ones marked by Flags and the two stride params annotated; below, the valid returns gathered into a prefix of length Counts[0], with TilePointOffsets and TilePointCounts drawn above it and the unspecified tail grayed out

Dense (top) and compact (bottom) layouts for two tiles, each with three emitter rows and two return slots per row. Dense output retains all 12 slots, ordered by tile, emitter row and return; Flags identifies valid returns. tileStridePoints = 6 and receiverStridePoints = 2 locate tiles and rows. Compact output packs valid returns into the first Counts[0] slots. For tile counts c0 and c1, TilePointCounts = [c0, c1] and TilePointOffsets = [0, c0, Counts[0]]. Gray slots are unused and their values are unspecified.#

Dense layout#

Set includeInvalidPoints = true to retain a slot for every possible return. Each point channel has capacity tileCount * receiversPerTile * maxReturns, with slots indexed as follows:

slot = tile * tileStridePoints + emitterRow * receiverStridePoints + return

The index uses:

  • tileStridePoints: receiversPerTile * maxReturns, reported as an output parameter.

  • receiverStridePoints: maxReturns, also reported as an output parameter.

  • emitterRow: the row index among those retained by the tile’s scan schedule.

Filter slots using the Flags valid bit. Counts[0] reports capacity, not the number of valid returns. compactionType is 1.

Invalid slots contain zero in Coordinates, Intensity, TimeOffsetNs, ChannelId, MaterialId and EchoId. FiringPatternIndex is populated for every slot. Dense output has no TilePointCounts or TilePointOffsets tensors; use the strides to locate each tile.

Tiled aggregates#

When several WPM lidars share a RenderProduct’s camera relationship, they use one scan schedule and the first sensor’s attributes. Each PointCloud RenderVar returns one combined point cloud. See Tile Lidars for setup and verification.

Locate each sensor’s returns using compact-layout tile tensors or dense-layout strides. For separate point clouds, use one RenderProduct per sensor. The Lidar generic core model requires separate RenderProducts.

Startup outputs#

During initialization, accepted PointCloud requests return empty outputs:

  • Coordinates has shape [0, 3]; other point channels have shape [0].

  • Counts[0] and validPointCount are zero.

  • Compact output includes zeroed TilePointCounts and TilePointOffsets.

  • maxPoints reports the configured capacity.

  • timestampNs is the frame end time.

Other layout parameters, coordinate settings and channel types match the configured sensor. Unlike normal outputs, startup point tensors have zero length rather than capacity-sized shapes. Readers bounded by the count or tensor length need no special case.

Initialization performs no tracing or return accumulation, but scan timing continues to follow the simulation clock. The first populated output therefore belongs to the scan window active when initialization finishes. Empty startup outputs are expected.

Reading the output#

Follow the mapping, synchronization and lifetime rules for CPU or CUDA access. Read each tensor’s data type, shape and strides from its DLPack descriptor and bound point reads by Counts[0].

  • Compact output stores valid returns in [0, Counts[0]); tile tensors locate each tile’s range.

  • Dense output reports capacity in Counts[0]. Filter by the Flags valid bit and locate tiles and emitter rows using strides.

  • Startup output has zero-length point tensors and a zero count.

Read coordsType, frameOfReference and motionCompensationState to interpret the coordinates; see coordinate conversion. The rotary example produces this output. Read its coordinates with point-first indexing.