Harmonizer#
A harmonizer defines the relationship among randomized mutable attributes.
If the key-value pair in the description file has a key of harmonizer_type
, it defines a harmonizer. A harmonizer constrains how a mutable attribute randomizes. For example:
rotate_H:
harmonizer_type: mutable_attribute
mutable_attribute:
distribution_type: range
start: -180
end: 180
Mutable attribute harmonizer (Deprecated)
If harmonizer_type
is a mutable_attribute
, it is a mutable attribute harmonizer. When the harmonizers harmonize, a value is resolved for it just as in any other mutable attributes.
To randomize a value that is shared across different mutable attributes, but is different across different frames. Consider a scene where there are two OROs standing side by side:
oro:
count: 2
type: geometry
subtype: mesh
usd_path: [PATH_TO_ORO]
transform_operators:
- translate:
- ($[../index] % 2 - 0.5) * 600
- 0
- 0
Use rotateY
to rotate them by 30 degrees each:
transform_operators:
- translate:
- ($[../index] % 2 - 0.5) * 600
- 0
- 0
- rotateY: 30
But if you specify rotateY
as a mutable attribute, they rotate differently within the same frame:
transform_operators:
- translate:
- ($[../index] % 2 - 0.5) * 600
- 0
- 0
- rotateY:
distribution_type: range
start: -180
end: 180
To have them rotate the same angle in the same frame, but different angles across different frames use the harmonizer. To define a harmonizer:
rotate_H:
harmonizer_type: mutable_attribute
mutable_attribute:
distribution_type: range
start: -180
end: 180
This evaluates only once per frame in the harmonize stage, then the ORO mutables retrieve this value per frame from the harmonizer:
- rotateY:
distribution_type: harmonized
harmonizer_name: rotate_H
If they rotate the same amount:
This can be used in all other transform operators and all other distribution types.
Note
Now that standalone mutable attributes are supported in the description symbol resolution process, mutable attribute harmonizers are no longer needed, allowing for more streamlined code. For example:
rotate_H:
distribution_type: range
start: -180
end: 180
oro:
count: 2
type: geometry
subtype: mesh
usd_path: [PATH_TO_ORO]
transform_operators:
- translate:
- ($[../index] % 2 - 0.5) * 600
- 0
- 0
- rotateY: $[/rotate_H]
Permutation harmonizer
If harmonizer_type
is permutate
, it is a permutation harmonizer. When you free randomize a harmonized
mutable attribute, you can specify a pitch
as the input to the permutation harmonizer. Then the permutation harmonizer shuffles these inputs and sends back the value to the harmonized attribute, which in turn can be used in a transform operator in the harmonized randomize stage.
For example, to define three OROs, facing in three directions:
oro:
count: 3
type: geometry
subtype: mesh
usd_path: [PATH_TO_ORO]
transform_operators:
- translate:
- ($[../index] % $[../count] - 1) * 600
- 0
- 0
- rotateY: ($[../index] - 1) * 60
These three OROs have X-axis position -600, 0, 600; and they are rotated around Y-axis by -60, 0, 60 degrees.
To shuffle the positions of these OROs, so that the ORO that rotates -60 degrees can appear to the right:
Define a mutable attribute permutated_index
as harmonized
. During the free randomize stage, it submits its index as its pitch
to the harmonizer permutate_H
, which is a permutation harmonizer.
oro:
...
permutated_index:
distribution_type: harmonized
harmonizer_name: permutate_H
pitch: $[index]
permutate_H:
harmonizer_type: permutate
During the harmonize stage, permutate_H
shuffles the received pitches from all relevant harmonized mutable attributes and resonates them back to each of them.
During the harmonized randomize stage, permutated_index
gets the shuffled value back. So you can use it in transform operators just like using an index.
oro:
...
transform_operators:
- translate:
- ($[permutated_index] % $[../count] - 1) * 600
- 0
- 0
- rotateY: ($[../index] - 1) * 60
This feature can be used with any values within scope.
Bin pack harmonizer
If harmonizer_type
is bin_pack
, it is a bin pack harmonizer that packs objects into a cuboid space according to their axis-aligned bounding boxes. You can define a cuboid with custom dimensions like this:
bin_pack_H:
harmonizer_type: bin_pack
bin_size:
- 480
- 260
- 700
You can define many OROs, and pack them into this cuboid:
oro:
count: 200
physics: rigidbody
type: geometry
subtype: mesh
tracked: true
transform_operators:
- translate:
- 0
- 300
- 0
- transform:
distribution_type: harmonized
harmonizer_name: bin_pack_H
pitch: local_aabb
- scale:
- 30
- 30
- 30
usd_path: PATH_TO_ORO
For example, with many OROs densely packed together:
In this example, 200 OROs are spawned during initialization.
At free randomize stage, the usd_path
of mutable oro
is determined, which can be harmonized, randomized regularly, or just a constant value; at the same stage, the transform
transform operator, which is a harmonized mutable attribute that retrives its value from bin_pack_H
, submits the prims’ local axis-aligned bounding boxes to bin_pack_H
by specifying pitch: local_aabb
.
While at harmonize stage<simulation workflow>, bin_pack_H
collects all those bounding boxes and determines the transform for each of these boxes; the boxes that don’t fit in are moved to invisible areas.
Finally, at harmonized randomize stage, each oro
retrives their transforms and goes to their allocated position and orientation.