conquer3d 0.2.4__tar.gz → 0.2.5__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.
Files changed (68) hide show
  1. {conquer3d-0.2.4/conquer3d.egg-info → conquer3d-0.2.5}/PKG-INFO +49 -12
  2. {conquer3d-0.2.4 → conquer3d-0.2.5}/README.md +48 -11
  3. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/_C.pyi +18 -2
  4. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/_C.so +0 -0
  5. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/binds/data_structure/bvh.cpp +52 -1
  6. conquer3d-0.2.5/conquer3d/csrc/binds/data_structure/mesh_bvh.cpp +36 -0
  7. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/binds/data_structure/triangle_mesh.cpp +25 -2
  8. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/data_structure/bvh.cu +89 -0
  9. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/data_structure/bvh.h +19 -0
  10. conquer3d-0.2.5/conquer3d/csrc/data_structure/mesh_bvh.cu +205 -0
  11. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/data_structure/mesh_bvh.h +9 -0
  12. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/data_structure/triangle_mesh.cu +1 -0
  13. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/data_structure/triangle_mesh.h +5 -0
  14. conquer3d-0.2.5/conquer3d/csrc/primitive/ray.h +62 -0
  15. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/primitive/triangles.h +71 -21
  16. {conquer3d-0.2.4 → conquer3d-0.2.5/conquer3d.egg-info}/PKG-INFO +49 -12
  17. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d.egg-info/SOURCES.txt +1 -0
  18. {conquer3d-0.2.4 → conquer3d-0.2.5}/pyproject.toml +1 -1
  19. {conquer3d-0.2.4 → conquer3d-0.2.5}/setup.py +0 -10
  20. conquer3d-0.2.4/conquer3d/csrc/binds/data_structure/mesh_bvh.cpp +0 -22
  21. conquer3d-0.2.4/conquer3d/csrc/data_structure/mesh_bvh.cu +0 -98
  22. {conquer3d-0.2.4 → conquer3d-0.2.5}/LICENSE +0 -0
  23. {conquer3d-0.2.4 → conquer3d-0.2.5}/MANIFEST.in +0 -0
  24. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/__init__.py +0 -0
  25. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/creation/__init__.py +0 -0
  26. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/creation/triangle_creation.py +0 -0
  27. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/binds/creation/triangle_creation.cpp +0 -0
  28. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/binds/data_structure/gs_bvh.cpp +0 -0
  29. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/binds/data_structure/kdtree.cpp +0 -0
  30. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/binds/data_structure/pgs_bvh.cpp +0 -0
  31. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/binds/primitive/gs.cpp +0 -0
  32. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/binds/primitive/pgs.cpp +0 -0
  33. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/check.h +0 -0
  34. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/constants.h +0 -0
  35. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/creation/triangle_creation.h +0 -0
  36. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/data_structure/gs_bvh.h +0 -0
  37. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/data_structure/kdtree.cu +0 -0
  38. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/data_structure/kdtree.h +0 -0
  39. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/data_structure/pgs_bvh.h +0 -0
  40. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/data_structure/zcurve.h +0 -0
  41. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/maths/f2x2.h +0 -0
  42. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/maths/f3x1.h +0 -0
  43. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/maths/f3x3.h +0 -0
  44. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/maths/f3x4.h +0 -0
  45. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/maths/f4x1.h +0 -0
  46. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/maths/f4x4.h +0 -0
  47. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/maths/maths.h +0 -0
  48. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/maths/ops.h +0 -0
  49. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/primitive/aabb.h +0 -0
  50. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/primitive/edge.h +0 -0
  51. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/primitive/gs.cu +0 -0
  52. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/primitive/gs.h +0 -0
  53. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/primitive/gs_aabb.cu +0 -0
  54. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/primitive/gs_math.cuh +0 -0
  55. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/primitive/pgs.cu +0 -0
  56. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/primitive/pgs.h +0 -0
  57. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/primitive/pgs_aabb.cu +0 -0
  58. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/primitive/pgs_math.cuh +0 -0
  59. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/csrc/pybind.cpp +0 -0
  60. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/data_structure/__init__.py +0 -0
  61. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/primitive/__init__.py +0 -0
  62. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/primitive/gs.py +0 -0
  63. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d/primitive/pgs.py +0 -0
  64. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d.egg-info/dependency_links.txt +0 -0
  65. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d.egg-info/not-zip-safe +0 -0
  66. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d.egg-info/requires.txt +0 -0
  67. {conquer3d-0.2.4 → conquer3d-0.2.5}/conquer3d.egg-info/top_level.txt +0 -0
  68. {conquer3d-0.2.4 → conquer3d-0.2.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conquer3d
3
- Version: 0.2.4
3
+ Version: 0.2.5
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,10 @@ class BVH:
14
14
  """
15
15
  Query the BVH with bounding boxes or segments. Returns (query_ids, object_ids).
16
16
  """
17
+ def query_ray(self, ray_origins: torch.Tensor, ray_dirs: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
18
+ """
19
+ Query the BVH with rays. Returns (query_ids, object_ids).
20
+ """
17
21
  def query_self(self) -> tuple[torch.Tensor, torch.Tensor]:
18
22
  """
19
23
  Query the BVH against itself. Returns unique overlapping (query_ids, object_ids).
@@ -49,6 +53,10 @@ class MeshBVH(BVH):
49
53
  """
50
54
  Construct MeshBVH from Triangle AABBs.
51
55
  """
56
+ 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:
57
+ """
58
+ Find all ray-triangle intersections. Returns (ray_ids, triangle_ids, intersect_points, [distances])
59
+ """
52
60
  def get_self_intersection(self, vertices: torch.Tensor, triangles: torch.Tensor) -> torch.Tensor:
53
61
  """
54
62
  Find all self-intersecting triangle pairs
@@ -87,8 +95,14 @@ class TriangleMesh:
87
95
  ...
88
96
  def get_non_manifold_vertices(self) -> torch.Tensor:
89
97
  ...
98
+ def get_ray_intersection(self, ray_origins: torch.Tensor, ray_dirs: torch.Tensor, return_distance: bool = False) -> typing.Any:
99
+ """
100
+ Find all ray-triangle intersections. Returns (ray_ids, triangle_ids, intersect_points, [distances])
101
+ """
90
102
  def get_self_intersection(self) -> torch.Tensor:
91
- ...
103
+ """
104
+ Find all self-intersecting triangle pairs
105
+ """
92
106
  def get_vertices_to_triangle_map(self) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
93
107
  ...
94
108
  def is_edge_manifold(self, allow_boundary_edge: bool = True) -> bool:
@@ -96,7 +110,9 @@ class TriangleMesh:
96
110
  def is_manifold(self, allow_boundary_edge: bool = True) -> bool:
97
111
  ...
98
112
  def is_self_intersection(self) -> bool:
99
- ...
113
+ """
114
+ Check if there are any self-intersecting triangle pairs
115
+ """
100
116
  def is_vertex_manifold(self) -> bool:
101
117
  ...
102
118
  def remove_triangles_by_mask(self, keep_mask: torch.Tensor) -> None:
@@ -153,6 +153,52 @@ 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
+ {
160
+ CHECK_INPUT(ray_origins);
161
+ CHECK_INPUT(ray_dirs);
162
+ TORCH_CHECK(ray_origins.scalar_type() == torch::kFloat32, "ray_origins must be float32");
163
+ TORCH_CHECK(ray_dirs.scalar_type() == torch::kFloat32, "ray_dirs must be float32");
164
+ TORCH_CHECK(ray_origins.size(1) == 3, "ray_origins must have shape (M, 3)");
165
+ TORCH_CHECK(ray_dirs.size(1) == 3, "ray_dirs must have shape (M, 3)");
166
+
167
+ const uint32_t num_queries = static_cast<uint32_t>(ray_origins.size(0));
168
+ auto options_int64 = ray_origins.options().dtype(torch::kInt64);
169
+
170
+ if (num_queries == 0) {
171
+ throw std::runtime_error("Cannot query BVH with 0 queries.");
172
+ }
173
+
174
+ torch::Tensor out_query_ids = torch::empty({BVH_MAX_CAPACITY}, options_int64);
175
+ torch::Tensor out_object_ids = torch::empty({BVH_MAX_CAPACITY}, options_int64);
176
+ torch::Tensor hit_counter = torch::zeros({1}, options_int64);
177
+
178
+ bvh::query_ray(
179
+ num_queries,
180
+ this->num_objects,
181
+ reinterpret_cast<const float3 *>(ray_origins.data_ptr<float>()),
182
+ reinterpret_cast<const float3 *>(ray_dirs.data_ptr<float>()),
183
+ reinterpret_cast<const float3 *>(this->aabb_mins.data_ptr<float>()),
184
+ reinterpret_cast<const float3 *>(this->aabb_maxs.data_ptr<float>()),
185
+ reinterpret_cast<const int2 *>(this->bvh_children.data_ptr<int>()),
186
+ reinterpret_cast<const int *>(this->object_ids.data_ptr<int>()),
187
+ reinterpret_cast<int64_t *>(out_query_ids.data_ptr<int64_t>()),
188
+ reinterpret_cast<int64_t *>(out_object_ids.data_ptr<int64_t>()),
189
+ reinterpret_cast<int64_t *>(hit_counter.data_ptr<int64_t>()),
190
+ static_cast<int64_t>(BVH_MAX_CAPACITY)
191
+ );
192
+
193
+ int64_t num_hits = hit_counter.item<int64_t>();
194
+ num_hits = std::min(num_hits, static_cast<int64_t>(BVH_MAX_CAPACITY));
195
+
196
+ return std::make_tuple(
197
+ out_query_ids.slice(0, 0, num_hits),
198
+ out_object_ids.slice(0, 0, num_hits)
199
+ );
200
+ }
201
+
156
202
  void bind_ds_bvh(py::module_& m)
157
203
  {
158
204
  py::class_<BVH>(m, "BVH")
@@ -167,5 +213,10 @@ void bind_ds_bvh(py::module_& m)
167
213
  "Query the BVH with bounding boxes or segments. Returns (query_ids, object_ids).")
168
214
 
169
215
  .def("query_self", &BVH::query_self,
170
- "Query the BVH against itself. Returns unique overlapping (query_ids, object_ids).");
216
+ "Query the BVH against itself. Returns unique overlapping (query_ids, object_ids).")
217
+
218
+ .def("query_ray", &BVH::query_ray,
219
+ py::arg("ray_origins"),
220
+ py::arg("ray_dirs"),
221
+ "Query the BVH with rays. Returns (query_ids, object_ids).");
171
222
  }
@@ -0,0 +1,36 @@
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
+ }
@@ -97,6 +97,15 @@ 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::get_ray_intersection(
101
+ const torch::Tensor &ray_origins,
102
+ const torch::Tensor &ray_dirs,
103
+ bool return_distance)
104
+ {
105
+ this->build_bvh();
106
+ return this->bvh.value().get_ray_intersection(ray_origins, ray_dirs, this->vertices, this->triangles, return_distance);
107
+ }
108
+
100
109
  torch::Tensor TriangleMesh::get_triangle_areas()
101
110
  {
102
111
  if (!this->triangle_areas.defined())
@@ -313,8 +322,22 @@ void bind_ds_triangle_mesh(py::module_ &m)
313
322
  .def_property_readonly("surface_area", &TriangleMesh::get_surface_area)
314
323
  .def_property_readonly("bvh", &TriangleMesh::build_bvh)
315
324
  .def("build_bvh", &TriangleMesh::build_bvh)
316
- .def("get_self_intersection", &TriangleMesh::get_self_intersection)
317
- .def("is_self_intersection", &TriangleMesh::is_self_intersection)
325
+ .def("get_self_intersection", &TriangleMesh::get_self_intersection,
326
+ "Find all self-intersecting triangle pairs")
327
+ .def("is_self_intersection", &TriangleMesh::is_self_intersection,
328
+ "Check if there are any self-intersecting triangle pairs")
329
+ .def("get_ray_intersection", [](TriangleMesh& self, const torch::Tensor& ray_origins, const torch::Tensor& ray_dirs, bool return_distance) -> py::object {
330
+ auto result = self.get_ray_intersection(ray_origins, ray_dirs, return_distance);
331
+ if (return_distance) {
332
+ return py::cast(result);
333
+ } else {
334
+ return py::cast(std::make_tuple(std::get<0>(result), std::get<1>(result), std::get<2>(result)));
335
+ }
336
+ },
337
+ py::arg("ray_origins"),
338
+ py::arg("ray_dirs"),
339
+ py::arg("return_distance") = false,
340
+ "Find all ray-triangle intersections. Returns (ray_ids, triangle_ids, intersect_points, [distances])")
318
341
  .def_property_readonly("edges", &TriangleMesh::get_edges)
319
342
  .def_property_readonly("edge_to_triangle_offsets", &TriangleMesh::get_edge_to_triangle_offsets)
320
343
  .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,92 @@ 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
+ }
456
545
  }
@@ -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,10 @@ 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);
32
37
  };
33
38
 
34
39
  namespace bvh
@@ -69,6 +74,20 @@ namespace bvh
69
74
  int64_t *__restrict__ out_object_ids,
70
75
  int64_t *__restrict__ hit_counter,
71
76
  const int64_t max_capacity);
77
+
78
+ __host__ void query_ray(
79
+ const uint32_t num_queries,
80
+ const uint32_t num_objects,
81
+ const float3 *__restrict__ ray_origins,
82
+ const float3 *__restrict__ ray_dirs,
83
+ const float3 *__restrict__ bvh_aabb_mins,
84
+ const float3 *__restrict__ bvh_aabb_maxs,
85
+ const int2 *__restrict__ bvh_children,
86
+ const int *__restrict__ object_ids,
87
+ int64_t *__restrict__ out_query_ids,
88
+ int64_t *__restrict__ out_object_ids,
89
+ int64_t *__restrict__ hit_counter,
90
+ const int64_t max_capacity);
72
91
  }
73
92
 
74
93
  #endif // BVH_H
@@ -0,0 +1,205 @@
1
+ #include "mesh_bvh.h"
2
+ #include "../primitive/triangles.h"
3
+ #include <thrust/device_vector.h>
4
+
5
+
6
+ __global__ void filter_self_intersections_kernel(
7
+ const int num_pairs,
8
+ const int64_t* query_ids,
9
+ const int64_t* object_ids,
10
+ const float3* vertices,
11
+ const int3* triangles,
12
+ int64_t* out_query_ids,
13
+ int64_t* out_object_ids,
14
+ int64_t* valid_counter)
15
+ {
16
+ int idx = blockIdx.x * blockDim.x + threadIdx.x;
17
+ if (idx >= num_pairs) return;
18
+
19
+ int64_t idA = query_ids[idx];
20
+ int64_t idB = object_ids[idx];
21
+
22
+ int3 triA = triangles[idA];
23
+ int3 triB = triangles[idB];
24
+
25
+ // Filter shared vertices
26
+ if (triA.x == triB.x || triA.x == triB.y || triA.x == triB.z ||
27
+ triA.y == triB.x || triA.y == triB.y || triA.y == triB.z ||
28
+ triA.z == triB.x || triA.z == triB.y || triA.z == triB.z) {
29
+ return;
30
+ }
31
+
32
+ Triangle T1(vertices[triA.x], vertices[triA.y], vertices[triA.z]);
33
+ Triangle T2(vertices[triB.x], vertices[triB.y], vertices[triB.z]);
34
+
35
+ if (triangle::test_intersection(T1, T2)) {
36
+ uint64_t write_idx = (uint64_t)atomicAdd((unsigned long long int*)valid_counter, 1ULL);
37
+ out_query_ids[write_idx] = idA;
38
+ out_object_ids[write_idx] = idB;
39
+ }
40
+ }
41
+
42
+ torch::Tensor MeshBVH::get_self_intersection(
43
+ const torch::Tensor &vertices,
44
+ const torch::Tensor &triangles)
45
+ {
46
+ // 1. Broad-phase AABB overlap query
47
+ auto [query_ids, object_ids] = this->query_self();
48
+
49
+ int num_pairs = query_ids.size(0);
50
+ if (num_pairs == 0) {
51
+ return torch::empty({0, 2}, torch::TensorOptions().dtype(torch::kInt64).device(query_ids.device()));
52
+ }
53
+
54
+ // 2. Narrow-phase intersection
55
+ auto options_i64 = torch::TensorOptions().dtype(torch::kInt64).device(query_ids.device());
56
+ torch::Tensor out_query_ids = torch::empty({num_pairs}, options_i64);
57
+ torch::Tensor out_object_ids = torch::empty({num_pairs}, options_i64);
58
+ torch::Tensor valid_counter = torch::zeros({1}, options_i64);
59
+
60
+ int threads = NTHREADS;
61
+ int blocks = (num_pairs + threads - 1) / threads;
62
+
63
+ filter_self_intersections_kernel<<<blocks, threads>>>(
64
+ num_pairs,
65
+ query_ids.data_ptr<int64_t>(),
66
+ object_ids.data_ptr<int64_t>(),
67
+ (const float3*)vertices.data_ptr<float>(),
68
+ (const int3*)triangles.data_ptr<int>(),
69
+ out_query_ids.data_ptr<int64_t>(),
70
+ out_object_ids.data_ptr<int64_t>(),
71
+ valid_counter.data_ptr<int64_t>()
72
+ );
73
+
74
+ int64_t h_valid_counter = valid_counter.item<int64_t>();
75
+
76
+ if (h_valid_counter == 0) {
77
+ return torch::empty({0, 2}, options_i64);
78
+ }
79
+
80
+ out_query_ids = out_query_ids.slice(0, 0, h_valid_counter).unsqueeze(1);
81
+ out_object_ids = out_object_ids.slice(0, 0, h_valid_counter).unsqueeze(1);
82
+
83
+ return torch::cat({out_query_ids, out_object_ids}, 1);
84
+ }
85
+
86
+ bool MeshBVH::is_self_intersection(
87
+ const torch::Tensor &vertices,
88
+ const torch::Tensor &triangles)
89
+ {
90
+ torch::Tensor pairs = this->get_self_intersection(vertices, triangles);
91
+ return pairs.size(0) > 0;
92
+ }
93
+
94
+ __global__ void filter_ray_triangle_intersections_kernel(
95
+ const int num_pairs,
96
+ const int64_t* query_ids,
97
+ const int64_t* object_ids,
98
+ const float3* ray_origins,
99
+ const float3* ray_dirs,
100
+ const float3* vertices,
101
+ const int3* triangles,
102
+ int64_t* out_query_ids,
103
+ int64_t* out_object_ids,
104
+ float3* out_intersect_pts,
105
+ float* out_distances,
106
+ bool return_distance,
107
+ int64_t* valid_counter)
108
+ {
109
+ int idx = blockIdx.x * blockDim.x + threadIdx.x;
110
+ if (idx >= num_pairs) return;
111
+
112
+ int64_t ray_id = query_ids[idx];
113
+ int64_t tri_id = object_ids[idx];
114
+
115
+ Ray ray(ray_origins[ray_id], ray_dirs[ray_id]);
116
+
117
+ int3 tri = triangles[tri_id];
118
+ Triangle T(vertices[tri.x], vertices[tri.y], vertices[tri.z]);
119
+
120
+ float t_hit, u, v;
121
+ if (T.is_intersect_ray(ray, t_hit, u, v)) {
122
+ uint64_t write_idx = (uint64_t)atomicAdd((unsigned long long int*)valid_counter, 1ULL);
123
+ out_query_ids[write_idx] = ray_id;
124
+ out_object_ids[write_idx] = tri_id;
125
+ out_intersect_pts[write_idx] = ray.at(t_hit);
126
+ if (return_distance) {
127
+ out_distances[write_idx] = t_hit;
128
+ }
129
+ }
130
+ }
131
+
132
+ std::tuple<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor> MeshBVH::get_ray_intersection(
133
+ const torch::Tensor &ray_origins,
134
+ const torch::Tensor &ray_dirs,
135
+ const torch::Tensor &vertices,
136
+ const torch::Tensor &triangles,
137
+ bool return_distance)
138
+ {
139
+ // 1. Broad-phase BVH query
140
+ auto [query_ids, object_ids] = this->query_ray(ray_origins, ray_dirs);
141
+
142
+ int num_pairs = query_ids.size(0);
143
+ auto options_i64 = torch::TensorOptions().dtype(torch::kInt64).device(query_ids.device());
144
+ auto options_f32 = torch::TensorOptions().dtype(torch::kFloat32).device(query_ids.device());
145
+
146
+ if (num_pairs == 0) {
147
+ return std::make_tuple(
148
+ torch::empty({0}, options_i64),
149
+ torch::empty({0}, options_i64),
150
+ torch::empty({0, 3}, options_f32),
151
+ torch::empty({0}, options_f32)
152
+ );
153
+ }
154
+
155
+ // 2. Narrow-phase intersection
156
+ torch::Tensor out_query_ids = torch::empty({num_pairs}, options_i64);
157
+ torch::Tensor out_object_ids = torch::empty({num_pairs}, options_i64);
158
+ torch::Tensor out_intersect_pts = torch::empty({num_pairs, 3}, options_f32);
159
+
160
+ torch::Tensor out_distances;
161
+ if (return_distance) {
162
+ out_distances = torch::empty({num_pairs}, options_f32);
163
+ } else {
164
+ out_distances = torch::empty({0}, options_f32);
165
+ }
166
+
167
+ torch::Tensor valid_counter = torch::zeros({1}, options_i64);
168
+
169
+ int threads = NTHREADS;
170
+ int blocks = (num_pairs + threads - 1) / threads;
171
+
172
+ filter_ray_triangle_intersections_kernel<<<blocks, threads>>>(
173
+ num_pairs,
174
+ query_ids.data_ptr<int64_t>(),
175
+ object_ids.data_ptr<int64_t>(),
176
+ (const float3*)ray_origins.data_ptr<float>(),
177
+ (const float3*)ray_dirs.data_ptr<float>(),
178
+ (const float3*)vertices.data_ptr<float>(),
179
+ (const int3*)triangles.data_ptr<int>(),
180
+ out_query_ids.data_ptr<int64_t>(),
181
+ out_object_ids.data_ptr<int64_t>(),
182
+ (float3*)out_intersect_pts.data_ptr<float>(),
183
+ return_distance ? out_distances.data_ptr<float>() : nullptr,
184
+ return_distance,
185
+ valid_counter.data_ptr<int64_t>()
186
+ );
187
+
188
+ int64_t h_valid_counter = valid_counter.item<int64_t>();
189
+
190
+ if (h_valid_counter == 0) {
191
+ return std::make_tuple(
192
+ torch::empty({0}, options_i64),
193
+ torch::empty({0}, options_i64),
194
+ torch::empty({0, 3}, options_f32),
195
+ torch::empty({0}, options_f32)
196
+ );
197
+ }
198
+
199
+ return std::make_tuple(
200
+ out_query_ids.slice(0, 0, h_valid_counter),
201
+ out_object_ids.slice(0, 0, h_valid_counter),
202
+ out_intersect_pts.slice(0, 0, h_valid_counter),
203
+ return_distance ? out_distances.slice(0, 0, h_valid_counter) : out_distances
204
+ );
205
+ }