Overview#

An extension wraps around RTX Raycast Query to provide simpler raycast interface into the stage.

Class List#

  • IRaycastQuery: Interface class for Raycast Query operations. This class represents the interface for performing Raycast Query operations in the current scene. This class is thread-safe and can be called from any thread. There are several sets of functions to do raycast query:

    • submit_raycast_query as a single call that casts one Ray into the scene and returns hit result via callback.

    • The combination of add_raycast_sequence/remove_raycast_sequence, submit_ray_to_raycast_sequence, get_latest_result_from_raycast_sequence as a way to cast one ray into the scene and get result by polling.

    • The combination of add_raycast_sequence/remove_raycast_sequence, submit_ray_to_raycast_sequence_array, get_latest_result_from_raycast_sequence_array as a way to cast multiple rays into the scene and get result by polling.

  • Result: An enumeration class called “Result” which represents the possible error codes for a raycast query system.

  • RayQueryResult: Alias of the struct rtx::raytracing::RaycastQueryResult, represents the result of a raycast query. Inclued whether this query is valid, the hit position, normal and so on.

  • Ray: Alias of the struct rtx::raytracing::RaycastQueryRay, defines a ray that is used as input for a raycast query.

Example Usage#

Using submit_raycast_query for single raycast#

import omni.kit.raycast.query
from pxr import Gf

# assuming a stage is already opened and has geometry that the ray will hit
# ...

# get raycast interface
raycast = omni.kit.raycast.query.acquire_raycast_query_interface()

# generate a ray
ray = omni.kit.raycast.query.Ray((1000, 0, 0), (-1, 0, 0))

def callback(ray, result):
    if result.valid:
        # Got the raycast result in the callback
        print(Gf.Vec3d(*result.hit_position)
        print(result.hit_t)
        print(Gf.Vec3d(*result.normal))
        print(result.get_target_usd_path())

raycast.submit_raycast_query(ray, callback)

Using submit_ray_to_raycast_sequence/get_latest_result_from_raycast_sequence for single raycast#

  • Setup raycast sequence

import omni.kit.raycast.query
from pxr import Gf

# assuming a stage is already opened and has geometry that the ray will hit
# ...

# get raycast interface
raycast = omni.kit.raycast.query.acquire_raycast_query_interface()

# generate a ray
ray = omni.kit.raycast.query.Ray((1000, 0, 0), (-1, 0, 0))

seq_id = raycast.add_raycast_sequence()
result = raycast.submit_ray_to_raycast_sequence(seq_id, ray)
  • Poll for result

async def poll_for_result():
    while True:
        (error, seq_ray, result) = (
            raycast.get_latest_result_from_raycast_sequence(seq_id)
        )
        if error == omni.kit.raycast.query.Result.SUCCESS:
            if result.valid:
                # Got the raycast result in the callback
                print(Gf.Vec3d(*result.hit_position)
                print(result.hit_t)
                print(Gf.Vec3d(*result.normal))
                print(result.get_target_usd_path())
                break

        await self._app.next_update_async()

# You can also put get_latest_result_from_raycast_sequence in some `update` function that's ticked periodically without using async function.
  • Remove raycast sequence

result = raycast.remove_raycast_sequence(seq_id)

Using submit_ray_to_raycast_sequence_array/get_latest_result_from_raycast_sequence_array for multiple raycasts#

  • Setup raycast sequence array

import omni.kit.raycast.query
from pxr import Gf

# assuming a stage is already opened and has geometry that the ray will hit
# ...

# get raycast interface
raycast = omni.kit.raycast.query.acquire_raycast_query_interface()

# generate ray array
ray1 = omni.kit.raycast.query.Ray(
    (-1, 0, -3), (0, 0, 1), 0, 4
)
ray2 = omni.kit.raycast.query.Ray(
    (-1, 0, 1), (1, 0, 0)
)
ray3 = omni.kit.raycast.query.Ray(
    (1, 0, 3), (-1, 0, 0)
)
ray4 = omni.kit.raycast.query.Ray(
    (1, 0, -1), (1, 0, 0)
)
ray_array = [ray1, ray2, ray3, ray4]

# Optional. The python API submit_ray_to_raycast_sequence_array will set the size automatically.
# In C++ API, the size needs to be set explicitly.
# result = raycast.set_raycast_sequence_array_size(seq_id, len(ray_array))

seq_id = raycast.add_raycast_sequence()
result = raycast.submit_ray_to_raycast_sequence_array(seq_id, ray_array)
  • Poll for result

async def poll_for_result():
    while True:
        (error, seq_rays, results) = (
            raycast.get_latest_result_from_raycast_sequence_array(seq_id)
        )
        if error == omni.kit.raycast.query.Result.SUCCESS:

            for i, ray in enumerate(ray_array):
                seq_ray = seq_rays[i]
                result = results[i]
                if result.valid:
                    # Got the raycast result in the callback
                    print(Gf.Vec3d(*result.hit_position)
                    print(result.hit_t)
                    print(Gf.Vec3d(*result.normal))
                    print(result.get_target_usd_path())

        # have some exit criteria to break the loop
        # break

        await self._app.next_update_async()

# You can also put get_latest_result_from_raycast_sequence in some `update` function that's ticked periodically without using async function.
  • Remove raycast sequence

result = raycast.remove_raycast_sequence(seq_id)