conquer3d 0.2.4__tar.gz → 0.2.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {conquer3d-0.2.4/conquer3d.egg-info → conquer3d-0.2.6}/PKG-INFO +49 -12
- {conquer3d-0.2.4 → conquer3d-0.2.6}/README.md +48 -11
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/_C.pyi +30 -2
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/_C.so +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/binds/data_structure/bvh.cpp +89 -1
- conquer3d-0.2.6/conquer3d/csrc/binds/data_structure/mesh_bvh.cpp +44 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/binds/data_structure/triangle_mesh.cpp +47 -2
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/bvh.cu +182 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/bvh.h +35 -0
- conquer3d-0.2.6/conquer3d/csrc/data_structure/mesh_bvh.cu +413 -0
- conquer3d-0.2.6/conquer3d/csrc/data_structure/mesh_bvh.h +41 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/triangle_mesh.cu +1 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/triangle_mesh.h +12 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/primitive/aabb.h +18 -0
- conquer3d-0.2.6/conquer3d/csrc/primitive/ray.h +62 -0
- conquer3d-0.2.6/conquer3d/csrc/primitive/triangles.h +200 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6/conquer3d.egg-info}/PKG-INFO +49 -12
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d.egg-info/SOURCES.txt +1 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/pyproject.toml +1 -1
- {conquer3d-0.2.4 → conquer3d-0.2.6}/setup.py +0 -10
- conquer3d-0.2.4/conquer3d/csrc/binds/data_structure/mesh_bvh.cpp +0 -22
- conquer3d-0.2.4/conquer3d/csrc/data_structure/mesh_bvh.cu +0 -98
- conquer3d-0.2.4/conquer3d/csrc/data_structure/mesh_bvh.h +0 -24
- conquer3d-0.2.4/conquer3d/csrc/primitive/triangles.h +0 -106
- {conquer3d-0.2.4 → conquer3d-0.2.6}/LICENSE +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/MANIFEST.in +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/__init__.py +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/creation/__init__.py +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/creation/triangle_creation.py +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/binds/creation/triangle_creation.cpp +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/binds/data_structure/gs_bvh.cpp +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/binds/data_structure/kdtree.cpp +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/binds/data_structure/pgs_bvh.cpp +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/binds/primitive/gs.cpp +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/binds/primitive/pgs.cpp +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/check.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/constants.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/creation/triangle_creation.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/gs_bvh.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/kdtree.cu +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/kdtree.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/pgs_bvh.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/zcurve.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/maths/f2x2.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/maths/f3x1.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/maths/f3x3.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/maths/f3x4.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/maths/f4x1.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/maths/f4x4.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/maths/maths.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/maths/ops.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/primitive/edge.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/primitive/gs.cu +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/primitive/gs.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/primitive/gs_aabb.cu +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/primitive/gs_math.cuh +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/primitive/pgs.cu +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/primitive/pgs.h +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/primitive/pgs_aabb.cu +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/primitive/pgs_math.cuh +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/csrc/pybind.cpp +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/data_structure/__init__.py +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/primitive/__init__.py +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/primitive/gs.py +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d/primitive/pgs.py +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d.egg-info/dependency_links.txt +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d.egg-info/not-zip-safe +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d.egg-info/requires.txt +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/conquer3d.egg-info/top_level.txt +0 -0
- {conquer3d-0.2.4 → conquer3d-0.2.6}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: conquer3d
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
4
|
Summary: Geometric Cuda Tool Box
|
|
5
5
|
Author-email: Do Hoang Khoi <khoido8899@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -68,17 +68,54 @@ twine upload dist/* --verbose
|
|
|
68
68
|
## Research Paper
|
|
69
69
|
```bibtex
|
|
70
70
|
@inproceedings{2383795.2383801,
|
|
71
|
-
author = {Karras, Tero},
|
|
72
|
-
title = {Maximizing parallelism in the construction of BVHs, octrees, and k-d trees},
|
|
73
|
-
year = {2012},
|
|
74
|
-
isbn = {9783905674415},
|
|
75
|
-
publisher = {Eurographics Association},
|
|
76
|
-
address = {Goslar, DEU},
|
|
77
|
-
booktitle = {Proceedings of the Fourth ACM SIGGRAPH / Eurographics Conference on High-Performance Graphics},
|
|
78
|
-
pages = {33–37},
|
|
79
|
-
numpages = {5},
|
|
80
|
-
location = {Paris, France},
|
|
81
|
-
series = {EGGH-HPG'12}
|
|
71
|
+
author = {Karras, Tero},
|
|
72
|
+
title = {Maximizing parallelism in the construction of BVHs, octrees, and k-d trees},
|
|
73
|
+
year = {2012},
|
|
74
|
+
isbn = {9783905674415},
|
|
75
|
+
publisher = {Eurographics Association},
|
|
76
|
+
address = {Goslar, DEU},
|
|
77
|
+
booktitle = {Proceedings of the Fourth ACM SIGGRAPH / Eurographics Conference on High-Performance Graphics},
|
|
78
|
+
pages = {33–37},
|
|
79
|
+
numpages = {5},
|
|
80
|
+
location = {Paris, France},
|
|
81
|
+
series = {EGGH-HPG'12}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
```bibtex
|
|
86
|
+
@article{10.1080/10867651.1997.10487472,
|
|
87
|
+
author = {M\"{o}ller, Tomas},
|
|
88
|
+
title = {A fast triangle-triangle intersection test},
|
|
89
|
+
year = {1997},
|
|
90
|
+
issue_date = {1997},
|
|
91
|
+
publisher = {A. K. Peters, Ltd.},
|
|
92
|
+
address = {USA},
|
|
93
|
+
volume = {2},
|
|
94
|
+
number = {2},
|
|
95
|
+
issn = {1086-7651},
|
|
96
|
+
url = {https://doi.org/10.1080/10867651.1997.10487472},
|
|
97
|
+
doi = {10.1080/10867651.1997.10487472},
|
|
98
|
+
journal = {J. Graph. Tools},
|
|
99
|
+
month = nov,
|
|
100
|
+
pages = {25–30},
|
|
101
|
+
numpages = {6}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
```bibtex
|
|
106
|
+
@inproceedings{10.1145/1198555.1198746,
|
|
107
|
+
author = {M\"{o}ller, Tomas and Trumbore, Ben},
|
|
108
|
+
title = {Fast, minimum storage ray/triangle intersection},
|
|
109
|
+
year = {2005},
|
|
110
|
+
isbn = {9781450378338},
|
|
111
|
+
publisher = {Association for Computing Machinery},
|
|
112
|
+
address = {New York, NY, USA},
|
|
113
|
+
url = {https://doi.org/10.1145/1198555.1198746},
|
|
114
|
+
doi = {10.1145/1198555.1198746},
|
|
115
|
+
pages = {7–es},
|
|
116
|
+
keywords = {base transformation, intersection, ray tracing, ray/triangle-intersection},
|
|
117
|
+
location = {Los Angeles, California},
|
|
118
|
+
series = {SIGGRAPH '05}
|
|
82
119
|
}
|
|
83
120
|
```
|
|
84
121
|
|
|
@@ -44,17 +44,54 @@ twine upload dist/* --verbose
|
|
|
44
44
|
## Research Paper
|
|
45
45
|
```bibtex
|
|
46
46
|
@inproceedings{2383795.2383801,
|
|
47
|
-
author = {Karras, Tero},
|
|
48
|
-
title = {Maximizing parallelism in the construction of BVHs, octrees, and k-d trees},
|
|
49
|
-
year = {2012},
|
|
50
|
-
isbn = {9783905674415},
|
|
51
|
-
publisher = {Eurographics Association},
|
|
52
|
-
address = {Goslar, DEU},
|
|
53
|
-
booktitle = {Proceedings of the Fourth ACM SIGGRAPH / Eurographics Conference on High-Performance Graphics},
|
|
54
|
-
pages = {33–37},
|
|
55
|
-
numpages = {5},
|
|
56
|
-
location = {Paris, France},
|
|
57
|
-
series = {EGGH-HPG'12}
|
|
47
|
+
author = {Karras, Tero},
|
|
48
|
+
title = {Maximizing parallelism in the construction of BVHs, octrees, and k-d trees},
|
|
49
|
+
year = {2012},
|
|
50
|
+
isbn = {9783905674415},
|
|
51
|
+
publisher = {Eurographics Association},
|
|
52
|
+
address = {Goslar, DEU},
|
|
53
|
+
booktitle = {Proceedings of the Fourth ACM SIGGRAPH / Eurographics Conference on High-Performance Graphics},
|
|
54
|
+
pages = {33–37},
|
|
55
|
+
numpages = {5},
|
|
56
|
+
location = {Paris, France},
|
|
57
|
+
series = {EGGH-HPG'12}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```bibtex
|
|
62
|
+
@article{10.1080/10867651.1997.10487472,
|
|
63
|
+
author = {M\"{o}ller, Tomas},
|
|
64
|
+
title = {A fast triangle-triangle intersection test},
|
|
65
|
+
year = {1997},
|
|
66
|
+
issue_date = {1997},
|
|
67
|
+
publisher = {A. K. Peters, Ltd.},
|
|
68
|
+
address = {USA},
|
|
69
|
+
volume = {2},
|
|
70
|
+
number = {2},
|
|
71
|
+
issn = {1086-7651},
|
|
72
|
+
url = {https://doi.org/10.1080/10867651.1997.10487472},
|
|
73
|
+
doi = {10.1080/10867651.1997.10487472},
|
|
74
|
+
journal = {J. Graph. Tools},
|
|
75
|
+
month = nov,
|
|
76
|
+
pages = {25–30},
|
|
77
|
+
numpages = {6}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```bibtex
|
|
82
|
+
@inproceedings{10.1145/1198555.1198746,
|
|
83
|
+
author = {M\"{o}ller, Tomas and Trumbore, Ben},
|
|
84
|
+
title = {Fast, minimum storage ray/triangle intersection},
|
|
85
|
+
year = {2005},
|
|
86
|
+
isbn = {9781450378338},
|
|
87
|
+
publisher = {Association for Computing Machinery},
|
|
88
|
+
address = {New York, NY, USA},
|
|
89
|
+
url = {https://doi.org/10.1145/1198555.1198746},
|
|
90
|
+
doi = {10.1145/1198555.1198746},
|
|
91
|
+
pages = {7–es},
|
|
92
|
+
keywords = {base transformation, intersection, ray tracing, ray/triangle-intersection},
|
|
93
|
+
location = {Los Angeles, California},
|
|
94
|
+
series = {SIGGRAPH '05}
|
|
58
95
|
}
|
|
59
96
|
```
|
|
60
97
|
|
|
@@ -14,6 +14,14 @@ class BVH:
|
|
|
14
14
|
"""
|
|
15
15
|
Query the BVH with bounding boxes or segments. Returns (query_ids, object_ids).
|
|
16
16
|
"""
|
|
17
|
+
def query_point(self, query_points: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
|
18
|
+
"""
|
|
19
|
+
Find the closest leaf AABB to each query point. Returns (query_ids, object_ids, distances)
|
|
20
|
+
"""
|
|
21
|
+
def query_ray(self, ray_origins: torch.Tensor, ray_dirs: torch.Tensor, max_capacity: int = 10000000) -> tuple[torch.Tensor, torch.Tensor]:
|
|
22
|
+
"""
|
|
23
|
+
Find all ray-AABB intersections. Returns (ray_ids, object_ids)
|
|
24
|
+
"""
|
|
17
25
|
def query_self(self) -> tuple[torch.Tensor, torch.Tensor]:
|
|
18
26
|
"""
|
|
19
27
|
Query the BVH against itself. Returns unique overlapping (query_ids, object_ids).
|
|
@@ -49,6 +57,10 @@ class MeshBVH(BVH):
|
|
|
49
57
|
"""
|
|
50
58
|
Construct MeshBVH from Triangle AABBs.
|
|
51
59
|
"""
|
|
60
|
+
def get_ray_intersection(self, ray_origins: torch.Tensor, ray_dirs: torch.Tensor, vertices: torch.Tensor, triangles: torch.Tensor, return_distance: bool = False) -> typing.Any:
|
|
61
|
+
"""
|
|
62
|
+
Find all ray-triangle intersections. Returns (ray_ids, triangle_ids, intersect_points, [distances])
|
|
63
|
+
"""
|
|
52
64
|
def get_self_intersection(self, vertices: torch.Tensor, triangles: torch.Tensor) -> torch.Tensor:
|
|
53
65
|
"""
|
|
54
66
|
Find all self-intersecting triangle pairs
|
|
@@ -57,6 +69,10 @@ class MeshBVH(BVH):
|
|
|
57
69
|
"""
|
|
58
70
|
Check if there are any self-intersecting triangle pairs
|
|
59
71
|
"""
|
|
72
|
+
def query_point(self, query_points: torch.Tensor, vertices: torch.Tensor, triangles: torch.Tensor, return_sdf: bool = False, return_prj_pts: bool = True, sign_mode: int = 0) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
|
|
73
|
+
"""
|
|
74
|
+
Find the closest triangle to each query point. Returns (query_ids, triangle_ids, projected_points, distances)
|
|
75
|
+
"""
|
|
60
76
|
class PGSBVH(BVH):
|
|
61
77
|
def __init__(self, in_aabb_mins: torch.Tensor, in_aabb_maxs: torch.Tensor) -> None:
|
|
62
78
|
"""
|
|
@@ -87,8 +103,14 @@ class TriangleMesh:
|
|
|
87
103
|
...
|
|
88
104
|
def get_non_manifold_vertices(self) -> torch.Tensor:
|
|
89
105
|
...
|
|
106
|
+
def get_ray_intersection(self, ray_origins: torch.Tensor, ray_dirs: torch.Tensor, return_distance: bool = False) -> typing.Any:
|
|
107
|
+
"""
|
|
108
|
+
Find all ray-triangle intersections. Returns (ray_ids, triangle_ids, intersect_points, [distances])
|
|
109
|
+
"""
|
|
90
110
|
def get_self_intersection(self) -> torch.Tensor:
|
|
91
|
-
|
|
111
|
+
"""
|
|
112
|
+
Find all self-intersecting triangle pairs
|
|
113
|
+
"""
|
|
92
114
|
def get_vertices_to_triangle_map(self) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
|
93
115
|
...
|
|
94
116
|
def is_edge_manifold(self, allow_boundary_edge: bool = True) -> bool:
|
|
@@ -96,9 +118,15 @@ class TriangleMesh:
|
|
|
96
118
|
def is_manifold(self, allow_boundary_edge: bool = True) -> bool:
|
|
97
119
|
...
|
|
98
120
|
def is_self_intersection(self) -> bool:
|
|
99
|
-
|
|
121
|
+
"""
|
|
122
|
+
Check if there are any self-intersecting triangle pairs
|
|
123
|
+
"""
|
|
100
124
|
def is_vertex_manifold(self) -> bool:
|
|
101
125
|
...
|
|
126
|
+
def query_points(self, query_pts: torch.Tensor, return_sdf: bool = False, return_prj_pts: bool = True, sign_mode: int = 0, distance_mode: int = 0) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
|
|
127
|
+
"""
|
|
128
|
+
Query points against the mesh. Returns (query_ids, triangle_ids, projected_points, distances)
|
|
129
|
+
"""
|
|
102
130
|
def remove_triangles_by_mask(self, keep_mask: torch.Tensor) -> None:
|
|
103
131
|
...
|
|
104
132
|
@property
|
|
Binary file
|
|
@@ -153,6 +153,85 @@ std::tuple<torch::Tensor, torch::Tensor> BVH::query_self()
|
|
|
153
153
|
);
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
std::tuple<torch::Tensor, torch::Tensor> BVH::query_ray(
|
|
157
|
+
const torch::Tensor &ray_origins,
|
|
158
|
+
const torch::Tensor &ray_dirs,
|
|
159
|
+
int64_t max_capacity)
|
|
160
|
+
{
|
|
161
|
+
CHECK_INPUT(ray_origins);
|
|
162
|
+
CHECK_INPUT(ray_dirs);
|
|
163
|
+
TORCH_CHECK(ray_origins.size(0) == ray_dirs.size(0), "ray_origins and ray_dirs must have the same number of rays");
|
|
164
|
+
|
|
165
|
+
int num_queries = ray_origins.size(0);
|
|
166
|
+
|
|
167
|
+
auto options_i64 = torch::TensorOptions().dtype(torch::kInt64).device(ray_origins.device());
|
|
168
|
+
torch::Tensor out_query_ids = torch::empty({max_capacity}, options_i64);
|
|
169
|
+
torch::Tensor out_object_ids = torch::empty({max_capacity}, options_i64);
|
|
170
|
+
torch::Tensor hit_counter = torch::zeros({1}, options_i64);
|
|
171
|
+
|
|
172
|
+
bvh::query_ray(
|
|
173
|
+
num_queries,
|
|
174
|
+
this->num_objects,
|
|
175
|
+
(const float3 *)ray_origins.data_ptr<float>(),
|
|
176
|
+
(const float3 *)ray_dirs.data_ptr<float>(),
|
|
177
|
+
(const float3 *)this->aabb_mins.data_ptr<float>(),
|
|
178
|
+
(const float3 *)this->aabb_maxs.data_ptr<float>(),
|
|
179
|
+
(const int2 *)this->bvh_children.data_ptr<int>(),
|
|
180
|
+
this->object_ids.data_ptr<int>(),
|
|
181
|
+
out_query_ids.data_ptr<int64_t>(),
|
|
182
|
+
out_object_ids.data_ptr<int64_t>(),
|
|
183
|
+
hit_counter.data_ptr<int64_t>(),
|
|
184
|
+
max_capacity);
|
|
185
|
+
|
|
186
|
+
int64_t h_hit_counter = hit_counter.item<int64_t>();
|
|
187
|
+
|
|
188
|
+
if (h_hit_counter >= max_capacity)
|
|
189
|
+
{
|
|
190
|
+
TORCH_WARN("BVH ray query capacity exceeded. Some hits were dropped.");
|
|
191
|
+
h_hit_counter = max_capacity;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (h_hit_counter == 0) {
|
|
195
|
+
return std::make_tuple(
|
|
196
|
+
torch::empty({0}, options_i64),
|
|
197
|
+
torch::empty({0}, options_i64)
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return std::make_tuple(
|
|
202
|
+
out_query_ids.slice(0, 0, h_hit_counter),
|
|
203
|
+
out_object_ids.slice(0, 0, h_hit_counter));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
std::tuple<torch::Tensor, torch::Tensor, torch::Tensor> BVH::query_point(
|
|
207
|
+
const torch::Tensor &query_points)
|
|
208
|
+
{
|
|
209
|
+
CHECK_INPUT(query_points);
|
|
210
|
+
|
|
211
|
+
int num_queries = query_points.size(0);
|
|
212
|
+
|
|
213
|
+
auto options_i64 = torch::TensorOptions().dtype(torch::kInt64).device(query_points.device());
|
|
214
|
+
auto options_f32 = torch::TensorOptions().dtype(torch::kFloat32).device(query_points.device());
|
|
215
|
+
|
|
216
|
+
torch::Tensor out_query_ids = torch::empty({num_queries}, options_i64);
|
|
217
|
+
torch::Tensor out_object_ids = torch::empty({num_queries}, options_i64);
|
|
218
|
+
torch::Tensor out_distances = torch::empty({num_queries}, options_f32);
|
|
219
|
+
|
|
220
|
+
bvh::query_point(
|
|
221
|
+
num_queries,
|
|
222
|
+
this->num_objects,
|
|
223
|
+
(const float3 *)query_points.data_ptr<float>(),
|
|
224
|
+
(const float3 *)this->aabb_mins.data_ptr<float>(),
|
|
225
|
+
(const float3 *)this->aabb_maxs.data_ptr<float>(),
|
|
226
|
+
(const int2 *)this->bvh_children.data_ptr<int>(),
|
|
227
|
+
this->object_ids.data_ptr<int>(),
|
|
228
|
+
out_query_ids.data_ptr<int64_t>(),
|
|
229
|
+
out_object_ids.data_ptr<int64_t>(),
|
|
230
|
+
out_distances.data_ptr<float>());
|
|
231
|
+
|
|
232
|
+
return std::make_tuple(out_query_ids, out_object_ids, out_distances);
|
|
233
|
+
}
|
|
234
|
+
|
|
156
235
|
void bind_ds_bvh(py::module_& m)
|
|
157
236
|
{
|
|
158
237
|
py::class_<BVH>(m, "BVH")
|
|
@@ -167,5 +246,14 @@ void bind_ds_bvh(py::module_& m)
|
|
|
167
246
|
"Query the BVH with bounding boxes or segments. Returns (query_ids, object_ids).")
|
|
168
247
|
|
|
169
248
|
.def("query_self", &BVH::query_self,
|
|
170
|
-
"Query the BVH against itself. Returns unique overlapping (query_ids, object_ids).")
|
|
249
|
+
"Query the BVH against itself. Returns unique overlapping (query_ids, object_ids).")
|
|
250
|
+
|
|
251
|
+
.def("query_ray", &BVH::query_ray,
|
|
252
|
+
py::arg("ray_origins"),
|
|
253
|
+
py::arg("ray_dirs"),
|
|
254
|
+
py::arg("max_capacity") = BVH_MAX_CAPACITY,
|
|
255
|
+
"Find all ray-AABB intersections. Returns (ray_ids, object_ids)")
|
|
256
|
+
.def("query_point", &BVH::query_point,
|
|
257
|
+
py::arg("query_points"),
|
|
258
|
+
"Find the closest leaf AABB to each query point. Returns (query_ids, object_ids, distances)");
|
|
171
259
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#include <torch/extension.h>
|
|
2
|
+
#include "../../data_structure/mesh_bvh.h"
|
|
3
|
+
#include <pybind11/pybind11.h>
|
|
4
|
+
|
|
5
|
+
namespace py = pybind11;
|
|
6
|
+
|
|
7
|
+
void bind_ds_mesh_bvh(py::module_& m)
|
|
8
|
+
{
|
|
9
|
+
py::class_<MeshBVH, BVH>(m, "MeshBVH")
|
|
10
|
+
.def(py::init<const torch::Tensor &, const torch::Tensor &>(),
|
|
11
|
+
py::arg("in_aabb_mins"),
|
|
12
|
+
py::arg("in_aabb_maxs"),
|
|
13
|
+
"Construct MeshBVH from Triangle AABBs.")
|
|
14
|
+
.def("get_self_intersection", &MeshBVH::get_self_intersection,
|
|
15
|
+
py::arg("vertices"),
|
|
16
|
+
py::arg("triangles"),
|
|
17
|
+
"Find all self-intersecting triangle pairs")
|
|
18
|
+
.def("is_self_intersection", &MeshBVH::is_self_intersection,
|
|
19
|
+
py::arg("vertices"),
|
|
20
|
+
py::arg("triangles"),
|
|
21
|
+
"Check if there are any self-intersecting triangle pairs")
|
|
22
|
+
.def("get_ray_intersection", [](MeshBVH& self, const torch::Tensor& ray_origins, const torch::Tensor& ray_dirs, const torch::Tensor& vertices, const torch::Tensor& triangles, bool return_distance) -> py::object {
|
|
23
|
+
auto result = self.get_ray_intersection(ray_origins, ray_dirs, vertices, triangles, return_distance);
|
|
24
|
+
if (return_distance) {
|
|
25
|
+
return py::cast(result);
|
|
26
|
+
} else {
|
|
27
|
+
return py::cast(std::make_tuple(std::get<0>(result), std::get<1>(result), std::get<2>(result)));
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
py::arg("ray_origins"),
|
|
31
|
+
py::arg("ray_dirs"),
|
|
32
|
+
py::arg("vertices"),
|
|
33
|
+
py::arg("triangles"),
|
|
34
|
+
py::arg("return_distance") = false,
|
|
35
|
+
"Find all ray-triangle intersections. Returns (ray_ids, triangle_ids, intersect_points, [distances])")
|
|
36
|
+
.def("query_point", &MeshBVH::query_point,
|
|
37
|
+
py::arg("query_points"),
|
|
38
|
+
py::arg("vertices"),
|
|
39
|
+
py::arg("triangles"),
|
|
40
|
+
py::arg("return_sdf") = false,
|
|
41
|
+
py::arg("return_prj_pts") = true,
|
|
42
|
+
py::arg("sign_mode") = 0,
|
|
43
|
+
"Find the closest triangle to each query point. Returns (query_ids, triangle_ids, projected_points, distances)");
|
|
44
|
+
}
|
|
@@ -97,6 +97,30 @@ bool TriangleMesh::is_self_intersection()
|
|
|
97
97
|
return this->bvh.value().is_self_intersection(this->vertices, this->triangles);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
std::tuple<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor> TriangleMesh::query_points(
|
|
101
|
+
const torch::Tensor &query_pts,
|
|
102
|
+
bool return_sdf,
|
|
103
|
+
bool return_prj_pts,
|
|
104
|
+
int sign_mode,
|
|
105
|
+
int distance_mode)
|
|
106
|
+
{
|
|
107
|
+
if (distance_mode == 0) {
|
|
108
|
+
this->build_bvh();
|
|
109
|
+
return this->bvh.value().query_point(query_pts, this->vertices, this->triangles, return_sdf, return_prj_pts, sign_mode);
|
|
110
|
+
} else {
|
|
111
|
+
throw std::runtime_error("distance_mode != 0 not implemented yet");
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
std::tuple<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor> TriangleMesh::get_ray_intersection(
|
|
116
|
+
const torch::Tensor &ray_origins,
|
|
117
|
+
const torch::Tensor &ray_dirs,
|
|
118
|
+
bool return_distance)
|
|
119
|
+
{
|
|
120
|
+
this->build_bvh();
|
|
121
|
+
return this->bvh.value().get_ray_intersection(ray_origins, ray_dirs, this->vertices, this->triangles, return_distance);
|
|
122
|
+
}
|
|
123
|
+
|
|
100
124
|
torch::Tensor TriangleMesh::get_triangle_areas()
|
|
101
125
|
{
|
|
102
126
|
if (!this->triangle_areas.defined())
|
|
@@ -313,8 +337,29 @@ void bind_ds_triangle_mesh(py::module_ &m)
|
|
|
313
337
|
.def_property_readonly("surface_area", &TriangleMesh::get_surface_area)
|
|
314
338
|
.def_property_readonly("bvh", &TriangleMesh::build_bvh)
|
|
315
339
|
.def("build_bvh", &TriangleMesh::build_bvh)
|
|
316
|
-
.def("get_self_intersection", &TriangleMesh::get_self_intersection
|
|
317
|
-
|
|
340
|
+
.def("get_self_intersection", &TriangleMesh::get_self_intersection,
|
|
341
|
+
"Find all self-intersecting triangle pairs")
|
|
342
|
+
.def("is_self_intersection", &TriangleMesh::is_self_intersection,
|
|
343
|
+
"Check if there are any self-intersecting triangle pairs")
|
|
344
|
+
.def("get_ray_intersection", [](TriangleMesh& self, const torch::Tensor& ray_origins, const torch::Tensor& ray_dirs, bool return_distance) -> py::object {
|
|
345
|
+
auto result = self.get_ray_intersection(ray_origins, ray_dirs, return_distance);
|
|
346
|
+
if (return_distance) {
|
|
347
|
+
return py::cast(result);
|
|
348
|
+
} else {
|
|
349
|
+
return py::cast(std::make_tuple(std::get<0>(result), std::get<1>(result), std::get<2>(result)));
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
py::arg("ray_origins"),
|
|
353
|
+
py::arg("ray_dirs"),
|
|
354
|
+
py::arg("return_distance") = false,
|
|
355
|
+
"Find all ray-triangle intersections. Returns (ray_ids, triangle_ids, intersect_points, [distances])")
|
|
356
|
+
.def("query_points", &TriangleMesh::query_points,
|
|
357
|
+
py::arg("query_pts"),
|
|
358
|
+
py::arg("return_sdf") = false,
|
|
359
|
+
py::arg("return_prj_pts") = true,
|
|
360
|
+
py::arg("sign_mode") = 0,
|
|
361
|
+
py::arg("distance_mode") = 0,
|
|
362
|
+
"Query points against the mesh. Returns (query_ids, triangle_ids, projected_points, distances)")
|
|
318
363
|
.def_property_readonly("edges", &TriangleMesh::get_edges)
|
|
319
364
|
.def_property_readonly("edge_to_triangle_offsets", &TriangleMesh::get_edge_to_triangle_offsets)
|
|
320
365
|
.def_property_readonly("edge_to_triangle_counts", &TriangleMesh::get_edge_to_triangle_counts)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include "bvh.h"
|
|
2
2
|
#include "zcurve.h"
|
|
3
|
+
#include "../primitive/ray.h"
|
|
3
4
|
|
|
4
5
|
#include <thrust/device_vector.h>
|
|
5
6
|
#include <thrust/device_ptr.h>
|
|
@@ -453,4 +454,185 @@ namespace bvh
|
|
|
453
454
|
max_capacity
|
|
454
455
|
);
|
|
455
456
|
}
|
|
457
|
+
|
|
458
|
+
__global__ void query_ray_bvh_kernel(
|
|
459
|
+
const uint32_t num_queries,
|
|
460
|
+
const uint32_t num_objects,
|
|
461
|
+
const float3* __restrict__ ray_origins,
|
|
462
|
+
const float3* __restrict__ ray_dirs,
|
|
463
|
+
const float3* __restrict__ bvh_aabb_mins,
|
|
464
|
+
const float3* __restrict__ bvh_aabb_maxs,
|
|
465
|
+
const int2* __restrict__ bvh_children,
|
|
466
|
+
const int* __restrict__ object_ids,
|
|
467
|
+
int64_t* __restrict__ out_query_ids,
|
|
468
|
+
int64_t* __restrict__ out_object_ids,
|
|
469
|
+
int64_t* __restrict__ hit_counter,
|
|
470
|
+
const int64_t max_capacity)
|
|
471
|
+
{
|
|
472
|
+
uint32_t q_idx = blockIdx.x * blockDim.x + threadIdx.x;
|
|
473
|
+
if (q_idx >= num_queries) return;
|
|
474
|
+
|
|
475
|
+
Ray ray(ray_origins[q_idx], ray_dirs[q_idx]);
|
|
476
|
+
|
|
477
|
+
int stack[BVH_STACK_SIZE];
|
|
478
|
+
int stack_ptr = 0;
|
|
479
|
+
stack[0] = 0;
|
|
480
|
+
|
|
481
|
+
while (stack_ptr >= 0)
|
|
482
|
+
{
|
|
483
|
+
int node_idx = stack[stack_ptr--];
|
|
484
|
+
float t_hit;
|
|
485
|
+
|
|
486
|
+
if (ray.is_intersect_aabb(bvh_aabb_mins[node_idx], bvh_aabb_maxs[node_idx], t_hit))
|
|
487
|
+
{
|
|
488
|
+
if (node_idx >= num_objects - 1)
|
|
489
|
+
{
|
|
490
|
+
int leaf_idx = node_idx - (num_objects - 1);
|
|
491
|
+
int original_obj_id = object_ids[leaf_idx];
|
|
492
|
+
|
|
493
|
+
uint64_t write_idx = (uint64_t)atomicAdd((unsigned long long int*)hit_counter, 1ULL);
|
|
494
|
+
|
|
495
|
+
if (write_idx < max_capacity) {
|
|
496
|
+
out_query_ids[write_idx] = q_idx;
|
|
497
|
+
out_object_ids[write_idx] = original_obj_id;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
else
|
|
501
|
+
{
|
|
502
|
+
if (stack_ptr + 2 < BVH_STACK_SIZE)
|
|
503
|
+
{
|
|
504
|
+
int2 children = bvh_children[node_idx];
|
|
505
|
+
stack[++stack_ptr] = children.x;
|
|
506
|
+
stack[++stack_ptr] = children.y;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
void query_ray(
|
|
514
|
+
const uint32_t num_queries,
|
|
515
|
+
const uint32_t num_objects,
|
|
516
|
+
const float3* __restrict__ ray_origins,
|
|
517
|
+
const float3* __restrict__ ray_dirs,
|
|
518
|
+
const float3* __restrict__ bvh_aabb_mins,
|
|
519
|
+
const float3* __restrict__ bvh_aabb_maxs,
|
|
520
|
+
const int2* __restrict__ bvh_children,
|
|
521
|
+
const int* __restrict__ object_ids,
|
|
522
|
+
int64_t* __restrict__ out_query_ids,
|
|
523
|
+
int64_t* __restrict__ out_object_ids,
|
|
524
|
+
int64_t* __restrict__ hit_counter,
|
|
525
|
+
const int64_t max_capacity)
|
|
526
|
+
{
|
|
527
|
+
uint32_t threads = NTHREADS;
|
|
528
|
+
uint32_t blocks = (num_queries + threads - 1) / threads;
|
|
529
|
+
|
|
530
|
+
query_ray_bvh_kernel<<<blocks, threads>>>(
|
|
531
|
+
num_queries,
|
|
532
|
+
num_objects,
|
|
533
|
+
ray_origins,
|
|
534
|
+
ray_dirs,
|
|
535
|
+
bvh_aabb_mins,
|
|
536
|
+
bvh_aabb_maxs,
|
|
537
|
+
bvh_children,
|
|
538
|
+
object_ids,
|
|
539
|
+
out_query_ids,
|
|
540
|
+
out_object_ids,
|
|
541
|
+
hit_counter,
|
|
542
|
+
max_capacity
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
__global__ void query_point_bvh_kernel(
|
|
547
|
+
const uint32_t num_queries,
|
|
548
|
+
const uint32_t num_objects,
|
|
549
|
+
const float3* __restrict__ query_points,
|
|
550
|
+
const float3* __restrict__ bvh_aabb_mins,
|
|
551
|
+
const float3* __restrict__ bvh_aabb_maxs,
|
|
552
|
+
const int2* __restrict__ bvh_children,
|
|
553
|
+
const int* __restrict__ object_ids,
|
|
554
|
+
int64_t* __restrict__ out_query_ids,
|
|
555
|
+
int64_t* __restrict__ out_object_ids,
|
|
556
|
+
float* __restrict__ out_distances)
|
|
557
|
+
{
|
|
558
|
+
uint32_t q_idx = blockIdx.x * blockDim.x + threadIdx.x;
|
|
559
|
+
if (q_idx >= num_queries) return;
|
|
560
|
+
|
|
561
|
+
float3 p = query_points[q_idx];
|
|
562
|
+
|
|
563
|
+
int stack[BVH_STACK_SIZE];
|
|
564
|
+
int stack_ptr = 0;
|
|
565
|
+
stack[0] = 0;
|
|
566
|
+
|
|
567
|
+
float best_dist_sq = FLT_MAX;
|
|
568
|
+
int best_leaf_original_id = -1;
|
|
569
|
+
|
|
570
|
+
while (stack_ptr >= 0)
|
|
571
|
+
{
|
|
572
|
+
int node_idx = stack[stack_ptr--];
|
|
573
|
+
|
|
574
|
+
float dist_sq = aabb::compute_squared_distance(p, bvh_aabb_mins[node_idx], bvh_aabb_maxs[node_idx]);
|
|
575
|
+
|
|
576
|
+
if (dist_sq > best_dist_sq) continue; // Prune branch
|
|
577
|
+
|
|
578
|
+
if (node_idx >= num_objects - 1)
|
|
579
|
+
{
|
|
580
|
+
if (dist_sq < best_dist_sq) {
|
|
581
|
+
best_dist_sq = dist_sq;
|
|
582
|
+
best_leaf_original_id = object_ids[node_idx - (num_objects - 1)];
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
else
|
|
586
|
+
{
|
|
587
|
+
if (stack_ptr + 2 < BVH_STACK_SIZE)
|
|
588
|
+
{
|
|
589
|
+
int2 children = bvh_children[node_idx];
|
|
590
|
+
|
|
591
|
+
float dist_l = aabb::compute_squared_distance(p, bvh_aabb_mins[children.x], bvh_aabb_maxs[children.x]);
|
|
592
|
+
float dist_r = aabb::compute_squared_distance(p, bvh_aabb_mins[children.y], bvh_aabb_maxs[children.y]);
|
|
593
|
+
|
|
594
|
+
if (dist_l > dist_r) {
|
|
595
|
+
stack[++stack_ptr] = children.x;
|
|
596
|
+
stack[++stack_ptr] = children.y;
|
|
597
|
+
} else {
|
|
598
|
+
stack[++stack_ptr] = children.y;
|
|
599
|
+
stack[++stack_ptr] = children.x;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
out_query_ids[q_idx] = q_idx;
|
|
606
|
+
out_object_ids[q_idx] = best_leaf_original_id;
|
|
607
|
+
out_distances[q_idx] = sqrtf(best_dist_sq);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
void query_point(
|
|
611
|
+
const uint32_t num_queries,
|
|
612
|
+
const uint32_t num_objects,
|
|
613
|
+
const float3* __restrict__ query_points,
|
|
614
|
+
const float3* __restrict__ bvh_aabb_mins,
|
|
615
|
+
const float3* __restrict__ bvh_aabb_maxs,
|
|
616
|
+
const int2* __restrict__ bvh_children,
|
|
617
|
+
const int* __restrict__ object_ids,
|
|
618
|
+
int64_t* __restrict__ out_query_ids,
|
|
619
|
+
int64_t* __restrict__ out_object_ids,
|
|
620
|
+
float* __restrict__ out_distances)
|
|
621
|
+
{
|
|
622
|
+
uint32_t threads = NTHREADS;
|
|
623
|
+
uint32_t blocks = (num_queries + threads - 1) / threads;
|
|
624
|
+
|
|
625
|
+
query_point_bvh_kernel<<<blocks, threads>>>(
|
|
626
|
+
num_queries,
|
|
627
|
+
num_objects,
|
|
628
|
+
query_points,
|
|
629
|
+
bvh_aabb_mins,
|
|
630
|
+
bvh_aabb_maxs,
|
|
631
|
+
bvh_children,
|
|
632
|
+
object_ids,
|
|
633
|
+
out_query_ids,
|
|
634
|
+
out_object_ids,
|
|
635
|
+
out_distances
|
|
636
|
+
);
|
|
637
|
+
}
|
|
456
638
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
#include "../maths/maths.h"
|
|
5
5
|
#include "../constants.h"
|
|
6
6
|
#include "../primitive/aabb.h"
|
|
7
|
+
#include "../primitive/ray.h"
|
|
7
8
|
|
|
8
9
|
#include <torch/extension.h>
|
|
9
10
|
#include <cuda_runtime.h>
|
|
@@ -29,6 +30,14 @@ public:
|
|
|
29
30
|
const torch::Tensor &query_aabb_maxs);
|
|
30
31
|
|
|
31
32
|
std::tuple<torch::Tensor, torch::Tensor> query_self();
|
|
33
|
+
|
|
34
|
+
std::tuple<torch::Tensor, torch::Tensor> query_ray(
|
|
35
|
+
const torch::Tensor &ray_origins,
|
|
36
|
+
const torch::Tensor &ray_dirs,
|
|
37
|
+
int64_t max_capacity = BVH_MAX_CAPACITY);
|
|
38
|
+
|
|
39
|
+
std::tuple<torch::Tensor, torch::Tensor, torch::Tensor> query_point(
|
|
40
|
+
const torch::Tensor &query_points);
|
|
32
41
|
};
|
|
33
42
|
|
|
34
43
|
namespace bvh
|
|
@@ -69,6 +78,32 @@ namespace bvh
|
|
|
69
78
|
int64_t *__restrict__ out_object_ids,
|
|
70
79
|
int64_t *__restrict__ hit_counter,
|
|
71
80
|
const int64_t max_capacity);
|
|
81
|
+
|
|
82
|
+
__host__ void query_ray(
|
|
83
|
+
const uint32_t num_queries,
|
|
84
|
+
const uint32_t num_objects,
|
|
85
|
+
const float3 *__restrict__ ray_origins,
|
|
86
|
+
const float3 *__restrict__ ray_dirs,
|
|
87
|
+
const float3 *__restrict__ bvh_aabb_mins,
|
|
88
|
+
const float3 *__restrict__ bvh_aabb_maxs,
|
|
89
|
+
const int2 *__restrict__ bvh_children,
|
|
90
|
+
const int *__restrict__ object_ids,
|
|
91
|
+
int64_t *__restrict__ out_query_ids,
|
|
92
|
+
int64_t *__restrict__ out_object_ids,
|
|
93
|
+
int64_t *__restrict__ hit_counter,
|
|
94
|
+
const int64_t max_capacity);
|
|
95
|
+
|
|
96
|
+
__host__ void query_point(
|
|
97
|
+
const uint32_t num_queries,
|
|
98
|
+
const uint32_t num_objects,
|
|
99
|
+
const float3 *__restrict__ query_points,
|
|
100
|
+
const float3 *__restrict__ bvh_aabb_mins,
|
|
101
|
+
const float3 *__restrict__ bvh_aabb_maxs,
|
|
102
|
+
const int2 *__restrict__ bvh_children,
|
|
103
|
+
const int *__restrict__ object_ids,
|
|
104
|
+
int64_t *__restrict__ out_query_ids,
|
|
105
|
+
int64_t *__restrict__ out_object_ids,
|
|
106
|
+
float *__restrict__ out_distances);
|
|
72
107
|
}
|
|
73
108
|
|
|
74
109
|
#endif // BVH_H
|