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).

Two clashing meshes.
Two clashing meshes at frame 38.
Two clashing meshes at frame 72.

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:

``Bake Layer...`` button and 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 by Attach 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 invoked

  • A 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 query

  • Additional support files (for example emissive_two_sided.mdl) will be created in the same directory

  • A 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

Clash Bake Layers are added as sublayers of 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

Two clashing meshes.
Generated clash meshes

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 meshes

  • ClashBakingCurveTimeSampled.usd the over layer containing time-sampled animation for all meshes

  • ClashBakingCurveTimeSampled_CLASH_MATERIALS.usd the over layer containing clash materials

  • ClashBakingCurveTimeSampled_CLASH_MESHES.usd the over layer containing clash meshes

How to compose clash bake layers

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:

  1. [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.

  2. Copy support files (mainly MDL shaders) to the folder that will receive the USD file containing clash materials (get_support_files_paths)

  3. Bake Clash materials (bake_clash_materials)

Every time there is need to bake an array of ClashInfo objects:

  1. Collect all paths to be baked in the current run

  2. Remove previously baked meshes to avoid merging new results with them (remove_baked_meshes)

  3. Prepare meshes to be baked (prepare_clash_bake_infos)

  4. Bake clash meshes (bake_clash_meshes)

  5. 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 be

  • Set an edit target where clash materials need to be written

  • bake_clash_materials creates materials in the current edit target for a given stage

  • Potentially 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:
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]],
) None#

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],
) list[ClashBakeInfo]#

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,
) None#

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]],
) None#

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.