Clash Detection Bake API#
The Clash Detection Bake extension (included in the Clash Detection Bundle extension) is an API that allows baking the resulting meshes of a clash detection to a time-sampled OpenUSD layer. The time sampled OpenUSD layer containing the animated clash will be playing along with the existing animations.
The suggested integration of the Clash Detection Bake API is in the clash detection pipeline as a headless process. Nevertheless a simple integration of the Clash Bake API has been added to the Clash Detection Window (reference application).



Warning
Only timesampled animated layers are officially supported by the clash layers bake extension.
Any animation created through the use of omni.anim.curve.core
must be baked to a time-sampled layer and the original animation curves must be deleted.
If deleting animation curves data is not feasible, disabling the omni.anim.curve.core
extension while generating and viewing clash backed layer can avoid such issues.
Failure to do any of the above may cause clash faces not to be animated correctly with the timeline position.
User Interface Usage#
Clash detection window has now a Bake Layer...
button that invokes a sub-menu:

The entries of the sub-menu are:
Attach Clash Bake Layers
: Attaches two new layers to the current stage, one for clash meshes (per query ID) and one for clash materials.Detach Clash Bake Layers
: Detaches the two layers from current stage, added byAttach Clash Bake Layers
.Save Clash Bake Layers
: Saves the content of the two clash bake layers.Reload Clash Bake Layers
: Reloads the saved content (from disk) of the two clash bake layers.Clear Clash Bake Layers
: Detaches the clash bake layer to clear its content and re-attaches it afterwards.
The Save Clash Bake Layers
, Reload Clash Bake Layers
and Clear Clash Bake Layers
options will be working only when the two layers are attached to the stage.
Warning
Attaching or detaching Clash Bake Layers causes a full USD re-composition (resync) that can take some time, depending on stage size.
Note
Attaching or detaching Clash Bake Layers works only on non-anonymous stages.
Clash Bake Layer Creation#
A Clash Bake layer is created when
Attach Clash Bake Layers
is invokedA Clash Bake layer is always associated with a specific query, by its query ID
When attaching a new Clash Bake layer, two additional .usd files will be created in the same folder where the root layer of current stage lives
One
.usd
file will start with the same file name as the root layer and end with_CLASH_MATERIALS.usd
One
.usd
file will start with the same file name as the root layer and end with_CLASH_QUERY_{query_id}
where{query_id}
is the integer ID of the selected clash queryAdditional support files (for example
emissive_two_sided.mdl
) will be created in the same directoryA Clash Bake layer is loaded if an already existing file with the expected file name exists in the destination folder
Once a bake layer has been attached for a given Clash Query, when switching to other queries other clash mesh layers will be created. This allows to bake clash meshes for a given query, save the baked layer and then switch to other queries without having to bake again over and over.
As an example given a source root layer named cylidner_sphere_animated.usda
that has 4 queries (with ID from 1
to 4
), the generated files will be:
cylidner_sphere_animated_CLASH_MATERIALS.usd
cylidner_sphere_animated_CLASH_QUERY_1.usd
cylidner_sphere_animated_CLASH_QUERY_2.usd
cylidner_sphere_animated_CLASH_QUERY_3.usd
cylidner_sphere_animated_CLASH_QUERY_4.usd
emissive_two_sided.mdl
Note
Clash Bake layers are added as sublayers of the session layer

Warning
Switching query with a clash bake layer attached will cause a full USD re-composition (resync) that can take some time, depending on stage size.
Clash Bake Meshes Creation#
Select all the clashes for which to generate clash meshes from a clash detection query window
Right Click on any of the selected rows and Left click
Generate Clash Meshes
Note
Before baking any mesh, a clash Bake layer must be attached (through Attach Clash Bake Layers
)
Generate Clash Meshes
will:
Remove all meshes previously created for selected clash records
Generate all relevant clash meshes for selected clash records
If the same mesh is impacted by multiple clashes, the API will generate a merged clash mesh, where relevant clash polygons will be highlighted at the right timecode


Note
The clash baking process can be interrupted at any time by clicking on the clash detection window progress bar
Clash Bake Layer Composition#
The clash baked layer can be composed in the same way as any other USD layer and viewed without the need of any clash detection extension, because the output of clash bake layer extension is just pure USD.
If animation curves are used to animate the stage they will need to be baked to a timesampled animation layer in order to delete (or disable) the animation curves from the original layer.
In the following example we see:
ClashBakingCurve.usd
the base layer containing original meshesClashBakingCurveTimeSampled.usd
the over layer containing time-sampled animation for all meshesClashBakingCurveTimeSampled_CLASH_MATERIALS.usd
the over layer containing clash materialsClashBakingCurveTimeSampled_CLASH_MESHES.usd
the over layer containing clash meshes

Technical Notes#
The Generated clash layers are not standalone but they contain only some delta that must be set as over to the original USD layer used to generate them.
Efficient usage of references allow such delta clash layer to be significantly smaller than a full time-sampled animated USD containing all mesh faces, indices and vertices. The delta contains just the time-sampled list of faces impacted by the clash over time.
The USD meshes impacted by the clash are hidden through the use of an Invisible material rather than manipulating the USD visibility attribute. This avoids manipulating the visibility attribute that is often written in the session layer by Animation Curve system if there are any active curves.
The API is also able to visualize meshes that are part of an instanced prim (instancing proxies), through use of references.
API Usage#
The high-level clash baking API usage workflow is the following:
One time:
[Optional] Create and attach any additional layer to write clash meshes and clash materials. Make sure that they have same timeCodesPerSecond of the root layer being baked.
Copy support files (mainly MDL shaders) to the folder that will receive the USD file containing clash materials (
get_support_files_paths
)Bake Clash materials (
bake_clash_materials
)
Every time there is need to bake an array of ClashInfo objects:
Collect all paths to be baked in the current run
Remove previously baked meshes to avoid merging new results with them (
remove_baked_meshes
)Prepare meshes to be baked (
prepare_clash_bake_infos
)Bake clash meshes (
bake_clash_meshes
)Finalize clash meshes (
finalize_clash_meshes
)
The following example shows how to generate a baked clashes layer offline from a non-interactive / headless command-line program:
Clash Bake Layer Example#
from omni.physxclashdetectionbake import ClashDetectionBake
stage_path_name = self._test_data_dir + "ClashBaking/ClashBakingTimeSampled.usda"
carb.log_info(f"Opening stage '{stage_path_name}'...")
stage = Usd.Stage.Open(stage_path_name)
self.assertIsNotNone(stage)
UsdUtils.StageCache.Get().Insert(stage)
# use clash detection core api to get ClashInfo objects from current stage
clash_infos = self._execute_clash_on(stage)
# Collect all a/b paths
paths = [(str(ci.object_a_path), str(ci.object_b_path)) for ci in clash_infos]
# Prepare bake infos
bake_infos = ClashDetectionBake.prepare_clash_bake_infos(stage=stage, clash_infos=clash_infos)
# Open or create two dedicates layers for clash baking, one for materials
# and one for meshes
root_layer = stage.GetRootLayer()
base_path, _ = os.path.splitext(root_layer.identifier)
extension = "usd"
layer_meshes_path = base_path + f"_CLASH_MESHES.{extension}"
layer_materials_path = base_path + f"_CLASH_MATERIALS.{extension}"
# It's possible also to open an existing layer before creating new ones
layer_meshes: Sdf.Layer = Sdf.Layer.CreateNew(layer_meshes_path)
layer_materials: Sdf.Layer = Sdf.Layer.CreateNew(layer_materials_path)
# Remove previously baked meshes (useful when opening an existing layer
# with pre-baked clash meshes)
ClashDetectionBake.remove_baked_meshes(stage=stage, paths=paths)
# NOTE: The layers must have same time codes per second as the original stage
layer_meshes.timeCodesPerSecond = root_layer.timeCodesPerSecond # type: ignore
layer_materials.timeCodesPerSecond = root_layer.timeCodesPerSecond # type: ignore
# Insert layers into stage
session_layer = stage.GetSessionLayer()
session_layer.subLayerPaths.append(layer_meshes.identifier)
session_layer.subLayerPaths.append(layer_materials.identifier)
# Copy Support files (material shaders mainly) to same folder where layers live
support_paths = ClashDetectionBake.get_support_files_paths()
dest_folder = os.path.dirname(str(layer_materials.identifier))
for src in support_paths:
dest = os.path.join(dest_folder, os.path.basename(src))
await omni.client.copy_async(src, dest, omni.client.CopyBehavior.OVERWRITE)
old_edit_target = stage.GetEditTarget()
try:
# Generate materials before they're referenced by meshes.
# Generating them on a separate layer is not mandatory.
stage.SetEditTarget(layer_materials)
carb.log_info("Baking materials")
materials = ClashDetectionBake.bake_clash_materials(stage)
# Bake clash meshes
# This can be taking some time so if needed just split the bake_infos in batches
# to give some time to user interfaces updates in order to display progress.
# Generating them on a separate layer is not mandatory.
stage.SetEditTarget(layer_meshes)
carb.log_info("Baking Meshes")
ClashDetectionBake.bake_clash_meshes(stage=stage, bake_infos=bake_infos, materials=materials)
# Finalize mesh baking (runs optimization / merge operations)
# Also this operation can be taking some time so if needed split paths in batches
# and interleave with user interface updates in order to display progress.
carb.log_info("Finalizing Meshes")
ClashDetectionBake.finalize_clash_meshes(stage=stage, paths=paths)
finally:
# Make sure to restore original edit target in any case
# And remove clash dedicated layers from session layer
stage.SetEditTarget(old_edit_target)
session_layer.subLayerPaths.remove(layer_meshes.identifier)
session_layer.subLayerPaths.remove(layer_materials.identifier)
carb.log_info("Clash baking finished")
API Reference#
ClashDetectionBake Class#
- class ClashDetectionBake#
A class to bake clash meshes to a USD layer. All methods of this class are
@staticmethod
so this class doesn’t need to be instantiated.The API enables baking a list of
ClashInfo
objects from Clash Detection Core API extension to OpenUSD meshes.The general usage workflow is:
- Setup (when a new stage is loaded):
get_support_files_paths
obtains support files that must be copied where the result of clash bake will beSet an edit target where clash materials need to be written
bake_clash_materials
creates materials in the current edit target for a given stagePotentially create an additional layer to contain only the clash meshes
Attach the layer containing the material and the clash meshes one as sublayers of current session layer
- Runtime:
prepare_clash_bake_infos
transforms a [ClashInfo
] (withclash_frame_info_items
filled) in a [ClashBakeInfo]Set an edit target where clash meshes need to be written
bake_clash_meshes
takes a [ClashBakeInfo] and a stage + materials and writes the meshes in the stage.Finally
finalize_clash_meshes
will finalize meshes, doing merging and / or keyframe simplifications.
- Update:
remove_baked_meshes
removes the baked meshes from a previous run when needing to update an existing layer.
Static Methods#
- remove_baked_meshes(
- stage: Usd.Stage,
- paths: list[tuple[str, str]],
Removes additional clash prims baked for prims at given paths.
- Parameters:
stage (Usd.Stage) – The USD Stage.
paths (list[tuple[str, str]]) – List of tuples containing the paths of the prims to remove.
- prepare_clash_bake_infos(
- stage: Usd.Stage,
- clash_infos: list[ClashInfo],
Prepare ClashBakeInfo objects that are needed to bake meshes for a given list of clashes.
- Parameters:
stage (Usd.Stage) – The USD Stage.
clash_infos (list[ClashInfo]) – List of ClashInfo objects from omni.physx.clashdetection.core.
- Returns:
List of ClashBakeInfo objects that can be used with bake_clash_meshes.
- Return type:
list[ClashBakeInfo]
- get_support_files_paths() list[str] #
Obtain a list of paths to support files needed by bake_clash_meshes.
For example it contains the path to material file used by the baked meshes materials. Copy these files in the target directory where the clash layer is saved.
- Returns:
List of file paths to support files needed by bake_clash_meshes.
- Return type:
list[str]
- bake_clash_materials(stage: Usd.Stage) ClashMaterialsPaths #
Write materials used by bake_clash_meshes to current stage.
Note: Before calling this function you can change the edit layer to save the materials to.
- Parameters:
stage (Usd.Stage) – The USD Stage.
- Returns:
The materials created (to be passed in to bake_clash_meshes)
- Return type:
ClashMaterialsPaths
- bake_clash_meshes(
- stage: Usd.Stage,
- bake_infos: list[ClashBakeInfo],
- materials: ClashMaterialsPaths,
Bakes meshes prepared with prepare_clash_bake_infos applying the materials created with bake_clash_materials.
Note: Before calling this function you can change the edit layer to save the clash mesh USD overs to.
- Parameters:
stage (Usd.Stage) – The USD Stage.
bake_infos (list[ClashBakeInfo]) – List of ClashBakeInfo objects prepared with prepare_clash_bake_infos.
materials (ClashMaterialsPaths) – Materials created with bake_clash_materials.
- finalize_clash_meshes(
- stage: Usd.Stage,
- paths: list[tuple[str, str]],
Merges multiple clash pairs at paths previously baked with bake_clash_meshes
- Parameters:
stage (Usd.Stage) – The USD Stage.
paths (list[tuple[str, str]]) – List of tuples containing the paths of the prims to merge.