Looking up group 0 should restrict traversal to the items assigned to group 0, regardless of whether another group is labeled 1 or 2.
For the mesh case below, a ray restricted to group 0 should not hit face 2, which belongs to group 2.
A BVH query restricted to sparse group 0 returns items from both groups. A mesh ray restricted to sparse group 0 hits a face from group 2.
import warp as wp
@wp.kernel
def query_bvh_group(
bvh_id: wp.uint64,
group_id: int,
hits: wp.array[wp.int32],
):
root = wp.bvh_get_group_root(bvh_id, group_id)
query = wp.bvh_query_aabb(
bvh_id,
wp.vec3(-10.0, -10.0, -10.0),
wp.vec3(200.0, 10.0, 10.0),
root,
)
item = int(0)
while wp.bvh_query_next(query, item):
hits[item] = 1
@wp.kernel
def query_mesh_group(
mesh_id: wp.uint64,
group_id: int,
face_out: wp.array[wp.int32],
):
root = wp.mesh_get_group_root(mesh_id, group_id)
hit = wp.mesh_query_ray(
mesh_id,
wp.vec3(100.2, 0.2, -1.0),
wp.vec3(0.0, 0.0, 1.0),
1.0e6,
root,
)
if hit.result:
face_out[0] = hit.face
def run_bvh_case(device: str, group_ids: list[int]) -> list[int]:
lowers = wp.array(
[
[0.0, 0.0, 0.0],
[2.0, 0.0, 0.0],
[100.0, 0.0, 0.0],
[102.0, 0.0, 0.0],
],
dtype=wp.vec3,
device=device,
)
uppers = wp.array(
[
[1.0, 1.0, 1.0],
[3.0, 1.0, 1.0],
[101.0, 1.0, 1.0],
[103.0, 1.0, 1.0],
],
dtype=wp.vec3,
device=device,
)
groups = wp.array(group_ids, dtype=wp.int32, device=device)
bvh = wp.Bvh(lowers, uppers, groups=groups)
hits = wp.zeros(4, dtype=wp.int32, device=device)
wp.launch(
query_bvh_group,
dim=1,
inputs=[bvh.id, 0],
outputs=[hits],
device=device,
)
return [index for index, value in enumerate(hits.numpy()) if value]
def run_mesh_case(device: str, group_ids: list[int]) -> int:
points = wp.array(
[
[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[2.0, 0.0, 0.0],
[3.0, 0.0, 0.0],
[2.0, 1.0, 0.0],
[100.0, 0.0, 0.0],
[101.0, 0.0, 0.0],
[100.0, 1.0, 0.0],
[102.0, 0.0, 0.0],
[103.0, 0.0, 0.0],
[102.0, 1.0, 0.0],
],
dtype=wp.vec3,
device=device,
)
indices = wp.array(list(range(12)), dtype=wp.int32, device=device)
groups = wp.array(group_ids, dtype=wp.int32, device=device)
mesh = wp.Mesh(points, indices, groups=groups)
face = wp.full(1, -1, dtype=wp.int32, device=device)
wp.launch(
query_mesh_group,
dim=1,
inputs=[mesh.id, 0],
outputs=[face],
device=device,
)
return int(face.numpy()[0])
devices = ["cpu"]
if wp.is_cuda_available():
devices.append("cuda:0")
for device in devices:
dense_groups = [0, 0, 1, 1]
sparse_groups = [0, 0, 2, 2]
print(f"{device} dense BVH hits: {run_bvh_case(device, dense_groups)}")
print(f"{device} sparse BVH hits: {run_bvh_case(device, sparse_groups)}")
print(f"{device} dense mesh face: {run_mesh_case(device, dense_groups)}")
print(f"{device} sparse mesh face: {run_mesh_case(device, sparse_groups)}")
cpu dense BVH hits: [0, 1]
cpu sparse BVH hits: [0, 1, 2, 3]
cpu dense mesh face: -1
cpu sparse mesh face: 2
cuda:0 dense BVH hits: [0, 1]
cuda:0 sparse BVH hits: [0, 1, 2, 3]
cuda:0 dense mesh face: -1
cuda:0 sparse mesh face: 2
wp.Bvhandwp.Meshaccept sparse, nonnegative group IDs at construction, butwp.bvh_get_group_root()andwp.mesh_get_group_root()do not reliably isolate the requested group.With dense groups
[0, 0, 1, 1], querying group 0 is correctly restricted to items 0 and 1. Changing only the second group ID to produce[0, 0, 2, 2]causes a group-0 query to include items from group 2.This reproduces with both
BvhandMeshon CPU and CUDA.Expected behavior
Looking up group 0 should restrict traversal to the items assigned to group 0, regardless of whether another group is labeled 1 or 2.
For the mesh case below, a ray restricted to group 0 should not hit face 2, which belongs to group 2.
Actual behavior
A BVH query restricted to sparse group 0 returns items from both groups. A mesh ray restricted to sparse group 0 hits a face from group 2.
Reproduction
Output
System Information
59e6ba10c79b572856dd21ba17b520a97d9c3e30