conquer3d 0.2.6__tar.gz → 0.2.7__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.6/conquer3d.egg-info → conquer3d-0.2.7}/PKG-INFO +1 -1
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/_C.pyi +10 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/_C.so +0 -0
- conquer3d-0.2.7/conquer3d/csrc/binds/data_structure/mesh_bvh.cpp +238 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/binds/data_structure/triangle_mesh.cpp +89 -2
- conquer3d-0.2.7/conquer3d/csrc/data_structure/mesh_bvh.cu +547 -0
- conquer3d-0.2.7/conquer3d/csrc/data_structure/mesh_bvh.h +112 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/data_structure/triangle_mesh.cu +151 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/data_structure/triangle_mesh.h +29 -1
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/primitive/triangles.h +13 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7/conquer3d.egg-info}/PKG-INFO +1 -1
- {conquer3d-0.2.6 → conquer3d-0.2.7}/pyproject.toml +1 -1
- conquer3d-0.2.6/conquer3d/csrc/binds/data_structure/mesh_bvh.cpp +0 -44
- conquer3d-0.2.6/conquer3d/csrc/data_structure/mesh_bvh.cu +0 -413
- conquer3d-0.2.6/conquer3d/csrc/data_structure/mesh_bvh.h +0 -41
- {conquer3d-0.2.6 → conquer3d-0.2.7}/LICENSE +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/MANIFEST.in +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/README.md +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/__init__.py +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/creation/__init__.py +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/creation/triangle_creation.py +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/binds/creation/triangle_creation.cpp +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/binds/data_structure/bvh.cpp +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/binds/data_structure/gs_bvh.cpp +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/binds/data_structure/kdtree.cpp +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/binds/data_structure/pgs_bvh.cpp +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/binds/primitive/gs.cpp +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/binds/primitive/pgs.cpp +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/check.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/constants.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/creation/triangle_creation.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/data_structure/bvh.cu +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/data_structure/bvh.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/data_structure/gs_bvh.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/data_structure/kdtree.cu +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/data_structure/kdtree.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/data_structure/pgs_bvh.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/data_structure/zcurve.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/maths/f2x2.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/maths/f3x1.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/maths/f3x3.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/maths/f3x4.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/maths/f4x1.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/maths/f4x4.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/maths/maths.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/maths/ops.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/primitive/aabb.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/primitive/edge.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/primitive/gs.cu +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/primitive/gs.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/primitive/gs_aabb.cu +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/primitive/gs_math.cuh +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/primitive/pgs.cu +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/primitive/pgs.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/primitive/pgs_aabb.cu +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/primitive/pgs_math.cuh +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/primitive/ray.h +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/csrc/pybind.cpp +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/data_structure/__init__.py +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/primitive/__init__.py +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/primitive/gs.py +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d/primitive/pgs.py +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d.egg-info/SOURCES.txt +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d.egg-info/dependency_links.txt +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d.egg-info/not-zip-safe +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d.egg-info/requires.txt +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/conquer3d.egg-info/top_level.txt +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/setup.cfg +0 -0
- {conquer3d-0.2.6 → conquer3d-0.2.7}/setup.py +0 -0
|
@@ -57,6 +57,10 @@ class MeshBVH(BVH):
|
|
|
57
57
|
"""
|
|
58
58
|
Construct MeshBVH from Triangle AABBs.
|
|
59
59
|
"""
|
|
60
|
+
def build_winding_data(self, vertices: torch.Tensor, triangles: torch.Tensor) -> None:
|
|
61
|
+
"""
|
|
62
|
+
Computes the hierarchical area-weighted constants for Fast Winding Number queries.
|
|
63
|
+
"""
|
|
60
64
|
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
65
|
"""
|
|
62
66
|
Find all ray-triangle intersections. Returns (ray_ids, triangle_ids, intersect_points, [distances])
|
|
@@ -97,6 +101,8 @@ class TriangleMesh:
|
|
|
97
101
|
...
|
|
98
102
|
def compute_triangle_normals(self) -> None:
|
|
99
103
|
...
|
|
104
|
+
def compute_vertex_normals(self) -> None:
|
|
105
|
+
...
|
|
100
106
|
def compute_vertices_to_triangle_map(self) -> None:
|
|
101
107
|
...
|
|
102
108
|
def get_edges_to_triangle_map(self) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
|
|
@@ -129,6 +135,10 @@ class TriangleMesh:
|
|
|
129
135
|
"""
|
|
130
136
|
def remove_triangles_by_mask(self, keep_mask: torch.Tensor) -> None:
|
|
131
137
|
...
|
|
138
|
+
def sample_points(self, num_points: int, uniform: bool = False, return_normals: bool = False, return_colors: bool = False, use_triangle_normal: bool = True) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor | None, torch.Tensor | None]:
|
|
139
|
+
"""
|
|
140
|
+
Sample points on the mesh
|
|
141
|
+
"""
|
|
132
142
|
@property
|
|
133
143
|
def bvh(self) -> MeshBVH:
|
|
134
144
|
...
|
|
Binary file
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
#include <torch/extension.h>
|
|
2
|
+
#include "../../data_structure/mesh_bvh.h"
|
|
3
|
+
#include <pybind11/pybind11.h>
|
|
4
|
+
#include "../../check.h"
|
|
5
|
+
|
|
6
|
+
namespace py = pybind11;
|
|
7
|
+
|
|
8
|
+
torch::Tensor MeshBVH::get_self_intersection(
|
|
9
|
+
const torch::Tensor &vertices,
|
|
10
|
+
const torch::Tensor &triangles)
|
|
11
|
+
{
|
|
12
|
+
// 1. Broad-phase AABB overlap query
|
|
13
|
+
auto [query_ids, object_ids] = this->query_self();
|
|
14
|
+
|
|
15
|
+
int num_pairs = query_ids.size(0);
|
|
16
|
+
if (num_pairs == 0)
|
|
17
|
+
{
|
|
18
|
+
return torch::empty({0, 2}, torch::TensorOptions().dtype(torch::kInt64).device(query_ids.device()));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// 2. Narrow-phase intersection
|
|
22
|
+
auto options_i64 = torch::TensorOptions().dtype(torch::kInt64).device(query_ids.device());
|
|
23
|
+
torch::Tensor out_query_ids = torch::empty({num_pairs}, options_i64);
|
|
24
|
+
torch::Tensor out_object_ids = torch::empty({num_pairs}, options_i64);
|
|
25
|
+
torch::Tensor valid_counter = torch::zeros({1}, options_i64);
|
|
26
|
+
|
|
27
|
+
mesh_bvh::filter_self_intersections(
|
|
28
|
+
num_pairs,
|
|
29
|
+
query_ids.data_ptr<int64_t>(),
|
|
30
|
+
object_ids.data_ptr<int64_t>(),
|
|
31
|
+
(const float3 *)vertices.data_ptr<float>(),
|
|
32
|
+
(const int3 *)triangles.data_ptr<int>(),
|
|
33
|
+
out_query_ids.data_ptr<int64_t>(),
|
|
34
|
+
out_object_ids.data_ptr<int64_t>(),
|
|
35
|
+
valid_counter.data_ptr<int64_t>());
|
|
36
|
+
|
|
37
|
+
int64_t h_valid_counter = valid_counter.item<int64_t>();
|
|
38
|
+
|
|
39
|
+
if (h_valid_counter == 0)
|
|
40
|
+
{
|
|
41
|
+
return torch::empty({0, 2}, options_i64);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
out_query_ids = out_query_ids.slice(0, 0, h_valid_counter).unsqueeze(1);
|
|
45
|
+
out_object_ids = out_object_ids.slice(0, 0, h_valid_counter).unsqueeze(1);
|
|
46
|
+
|
|
47
|
+
return torch::cat({out_query_ids, out_object_ids}, 1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
bool MeshBVH::is_self_intersection(
|
|
51
|
+
const torch::Tensor &vertices,
|
|
52
|
+
const torch::Tensor &triangles)
|
|
53
|
+
{
|
|
54
|
+
torch::Tensor pairs = this->get_self_intersection(vertices, triangles);
|
|
55
|
+
return pairs.size(0) > 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
std::tuple<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor> MeshBVH::get_ray_intersection(
|
|
59
|
+
const torch::Tensor &ray_origins,
|
|
60
|
+
const torch::Tensor &ray_dirs,
|
|
61
|
+
const torch::Tensor &vertices,
|
|
62
|
+
const torch::Tensor &triangles,
|
|
63
|
+
bool return_distance)
|
|
64
|
+
{
|
|
65
|
+
// 1. Broad-phase BVH query
|
|
66
|
+
auto [query_ids, object_ids] = this->query_ray(ray_origins, ray_dirs);
|
|
67
|
+
|
|
68
|
+
int num_pairs = query_ids.size(0);
|
|
69
|
+
auto options_i64 = torch::TensorOptions().dtype(torch::kInt64).device(query_ids.device());
|
|
70
|
+
auto options_f32 = torch::TensorOptions().dtype(torch::kFloat32).device(query_ids.device());
|
|
71
|
+
|
|
72
|
+
if (num_pairs == 0)
|
|
73
|
+
{
|
|
74
|
+
return std::make_tuple(
|
|
75
|
+
torch::empty({0}, options_i64),
|
|
76
|
+
torch::empty({0}, options_i64),
|
|
77
|
+
torch::empty({0, 3}, options_f32),
|
|
78
|
+
torch::empty({0}, options_f32));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 2. Narrow-phase intersection
|
|
82
|
+
torch::Tensor out_query_ids = torch::empty({num_pairs}, options_i64);
|
|
83
|
+
torch::Tensor out_object_ids = torch::empty({num_pairs}, options_i64);
|
|
84
|
+
torch::Tensor out_intersect_pts = torch::empty({num_pairs, 3}, options_f32);
|
|
85
|
+
|
|
86
|
+
torch::Tensor out_distances;
|
|
87
|
+
if (return_distance)
|
|
88
|
+
{
|
|
89
|
+
out_distances = torch::empty({num_pairs}, options_f32);
|
|
90
|
+
}
|
|
91
|
+
else
|
|
92
|
+
{
|
|
93
|
+
out_distances = torch::empty({0}, options_f32);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
torch::Tensor valid_counter = torch::zeros({1}, options_i64);
|
|
97
|
+
|
|
98
|
+
mesh_bvh::filter_ray_triangle_intersections(
|
|
99
|
+
num_pairs,
|
|
100
|
+
query_ids.data_ptr<int64_t>(),
|
|
101
|
+
object_ids.data_ptr<int64_t>(),
|
|
102
|
+
(const float3 *)ray_origins.data_ptr<float>(),
|
|
103
|
+
(const float3 *)ray_dirs.data_ptr<float>(),
|
|
104
|
+
(const float3 *)vertices.data_ptr<float>(),
|
|
105
|
+
(const int3 *)triangles.data_ptr<int>(),
|
|
106
|
+
out_query_ids.data_ptr<int64_t>(),
|
|
107
|
+
out_object_ids.data_ptr<int64_t>(),
|
|
108
|
+
(float3 *)out_intersect_pts.data_ptr<float>(),
|
|
109
|
+
return_distance ? out_distances.data_ptr<float>() : nullptr,
|
|
110
|
+
return_distance,
|
|
111
|
+
valid_counter.data_ptr<int64_t>());
|
|
112
|
+
|
|
113
|
+
int64_t h_valid_counter = valid_counter.item<int64_t>();
|
|
114
|
+
|
|
115
|
+
if (h_valid_counter == 0)
|
|
116
|
+
{
|
|
117
|
+
return std::make_tuple(
|
|
118
|
+
torch::empty({0}, options_i64),
|
|
119
|
+
torch::empty({0}, options_i64),
|
|
120
|
+
torch::empty({0, 3}, options_f32),
|
|
121
|
+
torch::empty({0}, options_f32));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return std::make_tuple(
|
|
125
|
+
out_query_ids.slice(0, 0, h_valid_counter),
|
|
126
|
+
out_object_ids.slice(0, 0, h_valid_counter),
|
|
127
|
+
out_intersect_pts.slice(0, 0, h_valid_counter),
|
|
128
|
+
return_distance ? out_distances.slice(0, 0, h_valid_counter) : out_distances);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
std::tuple<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor> MeshBVH::query_point(
|
|
132
|
+
const torch::Tensor &query_points,
|
|
133
|
+
const torch::Tensor &vertices,
|
|
134
|
+
const torch::Tensor &triangles,
|
|
135
|
+
bool return_sdf,
|
|
136
|
+
bool return_prj_pts,
|
|
137
|
+
int sign_mode)
|
|
138
|
+
{
|
|
139
|
+
if (sign_mode != 0 && sign_mode != 1)
|
|
140
|
+
{
|
|
141
|
+
throw std::runtime_error("sign_mode must be 0 (ray casting) or 1 (fast winding number)");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (sign_mode == 1 && !this->has_winding_data)
|
|
145
|
+
{
|
|
146
|
+
this->build_winding_data(vertices, triangles);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
int num_queries = query_points.size(0);
|
|
150
|
+
int num_objects = this->object_ids.size(0);
|
|
151
|
+
|
|
152
|
+
auto options_i64 = torch::TensorOptions().dtype(torch::kInt64).device(query_points.device());
|
|
153
|
+
auto options_f32 = torch::TensorOptions().dtype(torch::kFloat32).device(query_points.device());
|
|
154
|
+
|
|
155
|
+
torch::Tensor out_query_ids = torch::empty({num_queries}, options_i64);
|
|
156
|
+
torch::Tensor out_object_ids = torch::empty({num_queries}, options_i64);
|
|
157
|
+
torch::Tensor out_projected_pts;
|
|
158
|
+
if (return_prj_pts)
|
|
159
|
+
{
|
|
160
|
+
out_projected_pts = torch::empty({num_queries, 3}, options_f32);
|
|
161
|
+
}
|
|
162
|
+
else
|
|
163
|
+
{
|
|
164
|
+
out_projected_pts = torch::empty({0, 3}, options_f32);
|
|
165
|
+
}
|
|
166
|
+
torch::Tensor out_distances = torch::empty({num_queries}, options_f32);
|
|
167
|
+
|
|
168
|
+
mesh_bvh::query_point_mesh_bvh(
|
|
169
|
+
num_queries,
|
|
170
|
+
num_objects,
|
|
171
|
+
(const float3 *)query_points.data_ptr<float>(),
|
|
172
|
+
(const float3 *)vertices.data_ptr<float>(),
|
|
173
|
+
(const int3 *)triangles.data_ptr<int>(),
|
|
174
|
+
(const float3 *)this->aabb_mins.data_ptr<float>(),
|
|
175
|
+
(const float3 *)this->aabb_maxs.data_ptr<float>(),
|
|
176
|
+
(const int2 *)this->bvh_children.data_ptr<int>(),
|
|
177
|
+
this->object_ids.data_ptr<int>(),
|
|
178
|
+
this->has_winding_data ? (const WindingData *)this->winding_data.data_ptr() : nullptr,
|
|
179
|
+
out_query_ids.data_ptr<int64_t>(),
|
|
180
|
+
out_object_ids.data_ptr<int64_t>(),
|
|
181
|
+
return_prj_pts ? (float3 *)out_projected_pts.data_ptr<float>() : nullptr,
|
|
182
|
+
out_distances.data_ptr<float>(),
|
|
183
|
+
return_sdf,
|
|
184
|
+
return_prj_pts,
|
|
185
|
+
sign_mode);
|
|
186
|
+
|
|
187
|
+
return std::make_tuple(out_query_ids, out_object_ids, out_projected_pts, out_distances);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
void MeshBVH::build_winding_data(
|
|
191
|
+
const torch::Tensor &vertices,
|
|
192
|
+
const torch::Tensor &triangles)
|
|
193
|
+
{
|
|
194
|
+
int num_objects = this->object_ids.size(0);
|
|
195
|
+
int num_nodes = num_objects * 2 - 1;
|
|
196
|
+
|
|
197
|
+
auto options = torch::TensorOptions().dtype(torch::kByte).device(vertices.device());
|
|
198
|
+
this->winding_data = torch::empty({num_nodes * (int64_t)sizeof(WindingData)}, options);
|
|
199
|
+
|
|
200
|
+
mesh_bvh::bottom_up_winding_data(
|
|
201
|
+
num_objects,
|
|
202
|
+
this->object_ids.data_ptr<int>(),
|
|
203
|
+
(const float3 *)vertices.data_ptr<float>(),
|
|
204
|
+
(const int3 *)triangles.data_ptr<int>(),
|
|
205
|
+
this->bvh_parents.data_ptr<int>(),
|
|
206
|
+
(const int2 *)this->bvh_children.data_ptr<int>(),
|
|
207
|
+
(WindingData *)this->winding_data.data_ptr());
|
|
208
|
+
|
|
209
|
+
cudaDeviceSynchronize();
|
|
210
|
+
this->has_winding_data = true;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
void bind_ds_mesh_bvh(py::module_ &m)
|
|
214
|
+
{
|
|
215
|
+
py::class_<MeshBVH, BVH>(m, "MeshBVH")
|
|
216
|
+
.def(py::init<const torch::Tensor &, const torch::Tensor &>(),
|
|
217
|
+
py::arg("in_aabb_mins"),
|
|
218
|
+
py::arg("in_aabb_maxs"),
|
|
219
|
+
"Construct MeshBVH from Triangle AABBs.")
|
|
220
|
+
.def("get_self_intersection", &MeshBVH::get_self_intersection,
|
|
221
|
+
py::arg("vertices"),
|
|
222
|
+
py::arg("triangles"),
|
|
223
|
+
"Find all self-intersecting triangle pairs")
|
|
224
|
+
.def("is_self_intersection", &MeshBVH::is_self_intersection,
|
|
225
|
+
py::arg("vertices"),
|
|
226
|
+
py::arg("triangles"),
|
|
227
|
+
"Check if there are any self-intersecting triangle pairs")
|
|
228
|
+
.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
|
|
229
|
+
{
|
|
230
|
+
auto result = self.get_ray_intersection(ray_origins, ray_dirs, vertices, triangles, return_distance);
|
|
231
|
+
if (return_distance) {
|
|
232
|
+
return py::cast(result);
|
|
233
|
+
} else {
|
|
234
|
+
return py::cast(std::make_tuple(std::get<0>(result), std::get<1>(result), std::get<2>(result)));
|
|
235
|
+
} }, py::arg("ray_origins"), py::arg("ray_dirs"), py::arg("vertices"), py::arg("triangles"), py::arg("return_distance") = false, "Find all ray-triangle intersections. Returns (ray_ids, triangle_ids, intersect_points, [distances])")
|
|
236
|
+
.def("query_point", &MeshBVH::query_point, py::arg("query_points"), py::arg("vertices"), py::arg("triangles"), py::arg("return_sdf") = false, py::arg("return_prj_pts") = true, py::arg("sign_mode") = 0, "Find the closest triangle to each query point. Returns (query_ids, triangle_ids, projected_points, distances)")
|
|
237
|
+
.def("build_winding_data", &MeshBVH::build_winding_data, py::arg("vertices"), py::arg("triangles"), "Computes the hierarchical area-weighted constants for Fast Winding Number queries.");
|
|
238
|
+
}
|
|
@@ -50,11 +50,33 @@ void TriangleMesh::compute_triangle_normals()
|
|
|
50
50
|
this->triangle_normals = torch::empty({static_cast<int64_t>(this->num_triangles), 3}, torch::dtype(torch::kFloat32).device(this->vertices.device()));
|
|
51
51
|
triangle_mesh::compute_triangle_normals(
|
|
52
52
|
this->num_triangles,
|
|
53
|
-
reinterpret_cast<float3 *>(this->vertices.data_ptr<float>()),
|
|
54
|
-
reinterpret_cast<int3 *>(this->triangles.data_ptr<int>()),
|
|
53
|
+
reinterpret_cast<const float3 *>(this->vertices.data_ptr<float>()),
|
|
54
|
+
reinterpret_cast<const int3 *>(this->triangles.data_ptr<int>()),
|
|
55
55
|
reinterpret_cast<float3 *>(this->triangle_normals.data_ptr<float>()));
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
void TriangleMesh::compute_vertex_normals()
|
|
59
|
+
{
|
|
60
|
+
uint32_t num_vertices = this->vertices.size(0);
|
|
61
|
+
this->vertex_normals = torch::zeros({static_cast<int64_t>(num_vertices), 3}, torch::dtype(torch::kFloat32).device(this->vertices.device()));
|
|
62
|
+
|
|
63
|
+
triangle_mesh::compute_vertex_normals(
|
|
64
|
+
num_vertices,
|
|
65
|
+
this->num_triangles,
|
|
66
|
+
reinterpret_cast<const int3 *>(this->triangles.data_ptr<int>()),
|
|
67
|
+
reinterpret_cast<const float3 *>(this->get_triangle_normals().data_ptr<float>()),
|
|
68
|
+
reinterpret_cast<float3 *>(this->vertex_normals.data_ptr<float>()));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
torch::Tensor TriangleMesh::get_vertex_normals()
|
|
72
|
+
{
|
|
73
|
+
if (!this->vertex_normals.defined())
|
|
74
|
+
{
|
|
75
|
+
this->compute_vertex_normals();
|
|
76
|
+
}
|
|
77
|
+
return this->vertex_normals;
|
|
78
|
+
}
|
|
79
|
+
|
|
58
80
|
void TriangleMesh::compute_triangle_areas()
|
|
59
81
|
{
|
|
60
82
|
this->triangle_areas = torch::empty({static_cast<int64_t>(this->num_triangles)}, torch::dtype(torch::kFloat32).device(this->vertices.device()));
|
|
@@ -121,6 +143,69 @@ std::tuple<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor> TriangleM
|
|
|
121
143
|
return this->bvh.value().get_ray_intersection(ray_origins, ray_dirs, this->vertices, this->triangles, return_distance);
|
|
122
144
|
}
|
|
123
145
|
|
|
146
|
+
std::tuple<torch::Tensor, torch::Tensor, std::optional<torch::Tensor>, std::optional<torch::Tensor>> TriangleMesh::sample_points(
|
|
147
|
+
int num_points, bool uniform, bool return_normals, bool return_colors, bool use_triangle_normal)
|
|
148
|
+
{
|
|
149
|
+
if (this->num_triangles == 0) {
|
|
150
|
+
throw std::runtime_error("Cannot sample points from an empty mesh.");
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
torch::Tensor tri_indices;
|
|
154
|
+
if (!uniform) {
|
|
155
|
+
tri_indices = torch::randint(0, this->num_triangles, {num_points}, torch::TensorOptions().device(this->vertices.device()).dtype(torch::kInt64));
|
|
156
|
+
} else {
|
|
157
|
+
torch::Tensor areas = this->get_triangle_areas();
|
|
158
|
+
tri_indices = torch::multinomial(areas, num_points, true);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
torch::Tensor r1_r2 = torch::rand({num_points, 2}, torch::TensorOptions().device(this->vertices.device()).dtype(torch::kFloat32));
|
|
162
|
+
torch::Tensor out_points = torch::empty({num_points, 3}, torch::TensorOptions().device(this->vertices.device()).dtype(torch::kFloat32));
|
|
163
|
+
|
|
164
|
+
torch::Tensor out_normals, out_colors;
|
|
165
|
+
const float3* d_vertex_normals = nullptr;
|
|
166
|
+
const float3* d_triangle_normals = nullptr;
|
|
167
|
+
const float3* d_vertex_colors = nullptr;
|
|
168
|
+
float3* d_out_normals = nullptr;
|
|
169
|
+
float3* d_out_colors = nullptr;
|
|
170
|
+
|
|
171
|
+
if (return_normals) {
|
|
172
|
+
out_normals = torch::empty({num_points, 3}, torch::TensorOptions().device(this->vertices.device()).dtype(torch::kFloat32));
|
|
173
|
+
d_out_normals = reinterpret_cast<float3 *>(out_normals.data_ptr<float>());
|
|
174
|
+
if (use_triangle_normal) {
|
|
175
|
+
d_triangle_normals = reinterpret_cast<const float3 *>(this->get_triangle_normals().data_ptr<float>());
|
|
176
|
+
} else {
|
|
177
|
+
d_vertex_normals = reinterpret_cast<const float3 *>(this->get_vertex_normals().data_ptr<float>());
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (return_colors) {
|
|
182
|
+
if (!this->vertex_colors.defined()) {
|
|
183
|
+
throw std::runtime_error("Cannot sample colors because vertex_colors is not defined.");
|
|
184
|
+
}
|
|
185
|
+
out_colors = torch::empty({num_points, 3}, torch::TensorOptions().device(this->vertices.device()).dtype(torch::kFloat32));
|
|
186
|
+
d_out_colors = reinterpret_cast<float3 *>(out_colors.data_ptr<float>());
|
|
187
|
+
d_vertex_colors = reinterpret_cast<const float3 *>(this->vertex_colors.data_ptr<float>());
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
triangle_mesh::sample_points_triangle_mesh(
|
|
191
|
+
num_points,
|
|
192
|
+
reinterpret_cast<const float3 *>(this->vertices.data_ptr<float>()),
|
|
193
|
+
reinterpret_cast<const int3 *>(this->triangles.data_ptr<int>()),
|
|
194
|
+
reinterpret_cast<const int64_t *>(tri_indices.data_ptr<int64_t>()),
|
|
195
|
+
reinterpret_cast<const float2 *>(r1_r2.data_ptr<float>()),
|
|
196
|
+
d_vertex_normals,
|
|
197
|
+
d_triangle_normals,
|
|
198
|
+
d_vertex_colors,
|
|
199
|
+
reinterpret_cast<float3 *>(out_points.data_ptr<float>()),
|
|
200
|
+
d_out_normals,
|
|
201
|
+
d_out_colors);
|
|
202
|
+
|
|
203
|
+
std::optional<torch::Tensor> opt_normals = return_normals ? std::make_optional(out_normals) : std::nullopt;
|
|
204
|
+
std::optional<torch::Tensor> opt_colors = return_colors ? std::make_optional(out_colors) : std::nullopt;
|
|
205
|
+
|
|
206
|
+
return std::make_tuple(out_points, tri_indices, opt_normals, opt_colors);
|
|
207
|
+
}
|
|
208
|
+
|
|
124
209
|
torch::Tensor TriangleMesh::get_triangle_areas()
|
|
125
210
|
{
|
|
126
211
|
if (!this->triangle_areas.defined())
|
|
@@ -378,6 +463,8 @@ void bind_ds_triangle_mesh(py::module_ &m)
|
|
|
378
463
|
.def("is_manifold", &TriangleMesh::is_manifold, py::arg("allow_boundary_edge") = true)
|
|
379
464
|
.def("get_non_manifold_vertices", &TriangleMesh::get_non_manifold_vertices)
|
|
380
465
|
.def("remove_triangles_by_mask", &TriangleMesh::remove_triangles_by_mask, py::arg("keep_mask"))
|
|
466
|
+
.def("sample_points", &TriangleMesh::sample_points, py::arg("num_points"), py::arg("uniform") = false, py::arg("return_normals") = false, py::arg("return_colors") = false, py::arg("use_triangle_normal") = true, "Sample points on the mesh")
|
|
467
|
+
.def("compute_vertex_normals", &TriangleMesh::compute_vertex_normals)
|
|
381
468
|
.def_property_readonly("euler_characteristic", &TriangleMesh::get_euler_characteristic)
|
|
382
469
|
.def_property_readonly("genus", &TriangleMesh::get_genus);
|
|
383
470
|
}
|