Clash Detection Point Cloud API#

omni.physx.clashdetection.pointcloud is a lightweight extension that provides point cloud extraction utilities for the clash detection pipeline.

It depends on the omni.pointcloud.streaming.potree extension to stream point cloud data from Potree-format sources, then writes the result as UsdGeom.Points prims in the active stage. The extracted prims are consumed by ClashDetection when SETTING_ENABLE_POINT_CLOUDS is enabled.

Note

This extension is included in omni.physx.clashdetection.bundle. Enable the bundle to make this extension available.

Module#

The public surface of omni.physxclashdetectionpointcloud exports:

from omni.physxclashdetectionpointcloud import extract_point_cloud, ExtensionConfig

Functions#

async omni.physxclashdetectionpointcloud.extract_point_cloud(
stage: Usd.Stage,
point_cloud_prim_path: str,
destination_path: str,
aabbs: List[Gf.Range3d],
max_lod_level: int = 1000000,
extract_layer_name: str = '',
extract_to_session_layer: bool = True,
) Tuple[bool, str]#

Extracts a point cloud to UsdGeom.Points prims in the given stage.

The function streams point cloud geometry from a Potree source prim (referenced by point_cloud_prim_path), applies an optional axis-aligned bounding box (AABB) filter, and writes the resulting points as UsdGeom.Points prims under destination_path.

Parameters:
  • stage (Usd.Stage) – The USD stage containing the geometry to process.

  • point_cloud_prim_path (str) – USD prim path of the point cloud source.

  • destination_path (str) – Path where extraction results are written as UsdGeom.Points.

  • aabbs (List[Gf.Range3d]) – AABBs of inclusion regions of interest. Only the first entry is currently used. Pass an empty list (or a list with a single maximum-extent AABB) to include all available points; if the list is empty, a bounding box of ±1e38 is used internally.

  • max_lod_level (int) – Maximum level-of-detail level used during extraction. Higher values include finer detail at the cost of more memory and time. Defaults to 1 000 000.

  • extract_layer_name (str) – Display name of the sublayer to use for writing the extracted prims. When empty the current edit target is used without modification.

  • extract_to_session_layer (bool) – Relevant only when extract_layer_name is non-empty. If True, the named sublayer is found or created under the session layer. If False, it is found or created under the root layer.

Returns:

A (success, error_message) tuple. error_message is an empty string on success. Returns (True, "") also when the AABB filter matches no points (this is not treated as an error). Returns (False, error_message) on streaming or write failures.

Return type:

Tuple[bool, str]

Note

The coordinate space of the extracted points depends on the position of destination_path relative to the parent xform of point_cloud_prim_path. When destination_path is a child of that xform, points are kept in local space (the xform itself provides the world transform). Otherwise they are transformed to world space automatically.

Example#

Extracting a point cloud and running clash detection against meshes:

import asyncio
from pxr import Usd, UsdUtils, Gf
from omni.physxclashdetectionpointcloud import extract_point_cloud
from omni.physxclashdetectioncore.clash_detect import ClashDetection
from omni.physxclashdetectioncore.clash_detect_settings import SettingId
from omni.physxclashdetectioncore.clash_query import ClashQuery
from omni.physxclashdetectioncore.clash_data import ClashData
from omni.physxclashdetectioncore.clash_data_serializer_sqlite import ClashDataSerializerSqlite
from omni.physxclashdetectioncore.point_cloud_settings import PointCloudSettings


async def run_point_cloud_clash_detection(stage: Usd.Stage):
    stage_id = UsdUtils.StageCache.Get().GetId(stage).ToLongInt()

    # 1. Configure extraction settings
    pc_settings = PointCloudSettings(
        point_cloud_prim_path="/World/ScanData",
        destination_path="/World/ScanData/Extracted",
        save_to_session_layer=True,
        skip_rendering=True,
        max_lod_level=10,
    )

    # 2. Extract the point cloud into the stage
    roi_aabb = Gf.Range3d(Gf.Vec3d(-100, -100, -100), Gf.Vec3d(100, 100, 100))
    success, error = await extract_point_cloud(
        stage=stage,
        point_cloud_prim_path=pc_settings.point_cloud_prim_path,
        destination_path=pc_settings.destination_path,
        aabbs=[roi_aabb],
        max_lod_level=pc_settings.max_lod_level,
        extract_layer_name="ClashPointCloud",
        extract_to_session_layer=pc_settings.save_to_session_layer,
    )
    if not success:
        print(f"Extraction failed: {error}")
        return

    # 3. Set up ClashData and persist the point cloud settings
    clash_data = ClashData(ClashDataSerializerSqlite())
    clash_data.open(stage_id)
    clash_data.insert_point_cloud_settings(pc_settings)

    # 4. Create a point cloud clash query
    query = ClashQuery(
        query_name="Point Cloud vs Building Clash",
        object_a_path=pc_settings.point_cloud_prim_path,  # point cloud source
        object_b_path="/World/Building",                   # mesh geometry
        clash_detect_settings={
            SettingId.SETTING_ENABLE_POINT_CLOUDS.name: True,
            SettingId.SETTING_POINT_SIZE_OVERRIDE.name: 0.0,  # auto-compute size
            SettingId.SETTING_LOGGING.name: True,
        },
    )
    clash_data.insert_query(query)

    # 5. Run clash detection
    clash_detect = ClashDetection()
    clash_detect.set_settings(query.clash_detect_settings, stage)
    clash_detect.set_scope(stage, query.object_a_path, query.object_b_path)
    num_steps = clash_detect.create_pipeline()
    for i in range(num_steps):
        clash_detect.run_pipeline_step(i)

    num_overlaps = clash_detect.get_nb_overlaps()
    print(f"Found {num_overlaps} point cloud clashes")

    # Fetch and save results
    for _ in clash_detect.fetch_and_save_overlaps(stage, clash_data, query):
        pass

    clash_data.save()
    clash_data.close()
    clash_data.destroy()


# Run with: asyncio.ensure_future(run_point_cloud_clash_detection(stage))

Classes#

ExtensionConfig#

class omni.physxclashdetectionpointcloud.ExtensionConfig#

A configuration class that holds extension-wide parameters read from carb.settings at startup.

All attributes are class-level - do not instantiate this class.

SETTINGS_DEBUG_LOGGING_ENABLED = "/persistent/clashDetection/pointClouds/debugLogging"
Type:

str

carb.settings path for the debug-logging toggle. When the value at this path is True, the extractor logs verbose messages (source path, extents, LOD level) via carb.log_info.

debug_logging: bool = False

Whether debug logging is currently enabled. Updated at startup and whenever SETTINGS_DEBUG_LOGGING_ENABLED changes (via SettingChangeSubscription).

extension_path: Optional[str] = None

Absolute filesystem path to the installed extension directory. Set by ClashDetectionPointCloudExtension.on_startup; None before the extension starts.