conquer3d 0.3.2__tar.gz → 0.3.3__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.3.2/conquer3d.egg-info → conquer3d-0.3.3}/PKG-INFO +19 -1
- {conquer3d-0.3.2 → conquer3d-0.3.3}/README.md +18 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/_C.so +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/__init__.py +3 -1
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/triangle_mesh.cpp +299 -0
- conquer3d-0.3.3/conquer3d/csrc/binds/primitive/ray.cpp +37 -0
- conquer3d-0.3.3/conquer3d/csrc/binds/primitive/triangle.cpp +68 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/mesh_bvh.cu +1 -1
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/triangle_mesh.cu +299 -1
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/triangle_mesh.h +71 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/maths/f3x1.h +14 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/primitive/edge.h +7 -0
- conquer3d-0.3.2/conquer3d/csrc/primitive/triangles.h → conquer3d-0.3.3/conquer3d/csrc/primitive/triangle.h +156 -6
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/pybind.cpp +4 -0
- conquer3d-0.3.3/conquer3d/primitive/__init__.py +3 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3/conquer3d.egg-info}/PKG-INFO +19 -1
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d.egg-info/SOURCES.txt +3 -1
- {conquer3d-0.3.2 → conquer3d-0.3.3}/pyproject.toml +1 -1
- conquer3d-0.3.2/conquer3d/primitive/__init__.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/LICENSE +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/MANIFEST.in +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/_C.pyi +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/conversion/__init__.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/conversion/grid.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/conversion/mesh.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/creation/__init__.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/creation/triangle_creation.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/binds/creation/triangle_creation.cpp +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/bvh.cpp +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/grid.cpp +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/gs_bvh.cpp +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/kdtree.cpp +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/mesh_bvh.cpp +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/pgs_bvh.cpp +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/binds/ops/chamfer.cpp +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/binds/ops/mc.cpp +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/binds/primitive/gs.cpp +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/binds/primitive/pgs.cpp +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/check.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/constants.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/creation/triangle_creation.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/bvh.cu +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/bvh.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/gs_bvh.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/kdtree.cu +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/kdtree.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/mesh_bvh.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/pgs_bvh.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/zcurve.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/maths/f2x2.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/maths/f3x3.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/maths/f3x4.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/maths/f4x1.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/maths/f4x4.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/maths/maths.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/maths/ops.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/ops/chamfer.cu +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/ops/chamfer.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/ops/mc.cu +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/ops/mc.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/ops/mc_data.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/primitive/aabb.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/primitive/gs.cu +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/primitive/gs.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/primitive/gs_aabb.cu +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/primitive/gs_math.cuh +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/primitive/pgs.cu +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/primitive/pgs.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/primitive/pgs_aabb.cu +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/primitive/pgs_math.cuh +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/csrc/primitive/ray.h +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/data/__init__.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/data/collate/__init__.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/data/collate/mesh.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/data/collate/sparse_tensor.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/data/dataset/__init__.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/data/dataset/base_mesh.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/data/dataset/digit3d.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/data/transform/__init__.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/data/transform/base.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/data/transform/ops.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/data/transform/vertex.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/data_structure/__init__.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/data_structure/bmesh.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/data_structure/grid.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/ops/__init__.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/ops/diff_marching_cubes.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/ops/distance.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/ops/marching_cubes.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/primitive/gs.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d/primitive/pgs.py +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d.egg-info/dependency_links.txt +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d.egg-info/not-zip-safe +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d.egg-info/requires.txt +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/conquer3d.egg-info/top_level.txt +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/setup.cfg +0 -0
- {conquer3d-0.3.2 → conquer3d-0.3.3}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: conquer3d
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: Geometric Cuda Tool Box
|
|
5
5
|
Author-email: Do Hoang Khoi <khoido8899@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -131,6 +131,24 @@ twine upload dist/* --verbose
|
|
|
131
131
|
}
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
+
```bibtex
|
|
135
|
+
@InProceedings{10.1007/978-3-662-05105-4_2,
|
|
136
|
+
author="Meyer, Mark
|
|
137
|
+
and Desbrun, Mathieu
|
|
138
|
+
and Schr{\"o}der, Peter
|
|
139
|
+
and Barr, Alan H.",
|
|
140
|
+
editor="Hege, Hans-Christian
|
|
141
|
+
and Polthier, Konrad",
|
|
142
|
+
title="Discrete Differential-Geometry Operators for Triangulated 2-Manifolds",
|
|
143
|
+
booktitle="Visualization and Mathematics III",
|
|
144
|
+
year="2003",
|
|
145
|
+
publisher="Springer Berlin Heidelberg",
|
|
146
|
+
address="Berlin, Heidelberg",
|
|
147
|
+
pages="35--57",
|
|
148
|
+
isbn="978-3-662-05105-4"
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
134
152
|
## Blog Post
|
|
135
153
|
- [Thinking Parallel, Part I: Collision Detection on the GPU](https://developer.nvidia.com/blog/thinking-parallel-part-i-collision-detection-gpu/)
|
|
136
154
|
- [Thinking Parallel, Part II: Tree Traversal on the GPU](https://developer.nvidia.com/blog/thinking-parallel-part-ii-tree-traversal-gpu/)
|
|
@@ -102,6 +102,24 @@ twine upload dist/* --verbose
|
|
|
102
102
|
}
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
```bibtex
|
|
106
|
+
@InProceedings{10.1007/978-3-662-05105-4_2,
|
|
107
|
+
author="Meyer, Mark
|
|
108
|
+
and Desbrun, Mathieu
|
|
109
|
+
and Schr{\"o}der, Peter
|
|
110
|
+
and Barr, Alan H.",
|
|
111
|
+
editor="Hege, Hans-Christian
|
|
112
|
+
and Polthier, Konrad",
|
|
113
|
+
title="Discrete Differential-Geometry Operators for Triangulated 2-Manifolds",
|
|
114
|
+
booktitle="Visualization and Mathematics III",
|
|
115
|
+
year="2003",
|
|
116
|
+
publisher="Springer Berlin Heidelberg",
|
|
117
|
+
address="Berlin, Heidelberg",
|
|
118
|
+
pages="35--57",
|
|
119
|
+
isbn="978-3-662-05105-4"
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
105
123
|
## Blog Post
|
|
106
124
|
- [Thinking Parallel, Part I: Collision Detection on the GPU](https://developer.nvidia.com/blog/thinking-parallel-part-i-collision-detection-gpu/)
|
|
107
125
|
- [Thinking Parallel, Part II: Tree Traversal on the GPU](https://developer.nvidia.com/blog/thinking-parallel-part-ii-tree-traversal-gpu/)
|
|
Binary file
|
|
@@ -7,4 +7,6 @@ from . import primitive
|
|
|
7
7
|
from . import ops
|
|
8
8
|
from . import conversion
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
from .primitive import Triangle, Ray
|
|
11
|
+
|
|
12
|
+
__all__ = ['_C', 'creation', 'data_structure', 'primitive', 'ops', 'conversion', 'Triangle', 'Ray']
|
|
@@ -77,6 +77,238 @@ torch::Tensor TriangleMesh::get_vertex_normals()
|
|
|
77
77
|
return this->vertex_normals;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
void TriangleMesh::compute_vertex_degrees()
|
|
81
|
+
{
|
|
82
|
+
if (this->vertex_degrees.defined()) return;
|
|
83
|
+
|
|
84
|
+
if (!this->edges.defined()) {
|
|
85
|
+
this->compute_edges_to_triangle_map();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
uint32_t num_vertices = this->vertices.size(0);
|
|
89
|
+
this->vertex_degrees = torch::zeros({static_cast<int64_t>(num_vertices)}, torch::dtype(torch::kInt32).device(this->vertices.device()));
|
|
90
|
+
|
|
91
|
+
uint32_t num_edges = this->edges.size(0);
|
|
92
|
+
triangle_mesh::compute_vertex_degree(
|
|
93
|
+
num_edges,
|
|
94
|
+
reinterpret_cast<const int *>(this->edges.data_ptr<int>()),
|
|
95
|
+
reinterpret_cast<int *>(this->vertex_degrees.data_ptr<int>()));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
torch::Tensor TriangleMesh::get_vertex_degrees()
|
|
99
|
+
{
|
|
100
|
+
if (!this->vertex_degrees.defined())
|
|
101
|
+
{
|
|
102
|
+
this->compute_vertex_degrees();
|
|
103
|
+
}
|
|
104
|
+
return this->vertex_degrees;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
void TriangleMesh::compute_vertex_lb_uniform()
|
|
108
|
+
{
|
|
109
|
+
if (this->vertex_lb_uniform.defined()) return;
|
|
110
|
+
|
|
111
|
+
if (!this->edges.defined()) {
|
|
112
|
+
this->compute_edges_to_triangle_map();
|
|
113
|
+
}
|
|
114
|
+
if (!this->vertex_degrees.defined()) {
|
|
115
|
+
this->compute_vertex_degrees();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
uint32_t num_vertices = this->vertices.size(0);
|
|
119
|
+
this->vertex_lb_uniform = torch::zeros({static_cast<int64_t>(num_vertices), 3}, torch::dtype(torch::kFloat32).device(this->vertices.device()));
|
|
120
|
+
|
|
121
|
+
uint32_t num_edges = this->edges.size(0);
|
|
122
|
+
triangle_mesh::compute_uniform_laplacian(
|
|
123
|
+
num_vertices,
|
|
124
|
+
num_edges,
|
|
125
|
+
reinterpret_cast<const int *>(this->edges.data_ptr<int>()),
|
|
126
|
+
reinterpret_cast<const int *>(this->vertex_degrees.data_ptr<int>()),
|
|
127
|
+
reinterpret_cast<const float3 *>(this->vertices.data_ptr<float>()),
|
|
128
|
+
reinterpret_cast<float3 *>(this->vertex_lb_uniform.data_ptr<float>()));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
torch::Tensor TriangleMesh::get_vertex_lb_uniform()
|
|
132
|
+
{
|
|
133
|
+
if (!this->vertex_lb_uniform.defined())
|
|
134
|
+
{
|
|
135
|
+
this->compute_vertex_lb_uniform();
|
|
136
|
+
}
|
|
137
|
+
return this->vertex_lb_uniform;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
torch::Tensor TriangleMesh::compute_laplacian(int mode) {
|
|
141
|
+
if (mode == 0) {
|
|
142
|
+
return this->get_vertex_lb_uniform();
|
|
143
|
+
} else if (mode == 1) {
|
|
144
|
+
return this->get_vertex_lb_cotangent();
|
|
145
|
+
} else {
|
|
146
|
+
throw std::runtime_error("Unsupported laplacian mode. Use 0 for Uniform, 1 for Cotangent.");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
torch::Tensor TriangleMesh::get_mean_curvature(bool signed_curvature) {
|
|
151
|
+
// mode 1 is cotangent laplacian
|
|
152
|
+
torch::Tensor lb_cotangent = this->compute_laplacian(1);
|
|
153
|
+
|
|
154
|
+
if (!signed_curvature) {
|
|
155
|
+
// Absolute Mean Curvature: || 2 * H * n || / 2.0 = |H|
|
|
156
|
+
return torch::norm(lb_cotangent, 2, 1) / 2.0f;
|
|
157
|
+
} else {
|
|
158
|
+
// Signed Mean Curvature: dot(2 * H * n, n) / 2.0 = H
|
|
159
|
+
torch::Tensor v_normals = this->get_vertex_normals();
|
|
160
|
+
return torch::sum(lb_cotangent * v_normals, 1) / 2.0f;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
torch::Tensor TriangleMesh::get_principal_curvatures(bool signed_curvature) {
|
|
165
|
+
torch::Tensor H = this->get_mean_curvature(signed_curvature);
|
|
166
|
+
torch::Tensor K = this->get_gaussian_curvature();
|
|
167
|
+
|
|
168
|
+
// In discrete settings, floating point inaccuracies can rarely cause H^2 < K.
|
|
169
|
+
// We use torch::relu to clamp negative values to 0 before sqrt to prevent NaNs.
|
|
170
|
+
torch::Tensor delta = torch::relu(H * H - K);
|
|
171
|
+
torch::Tensor sqrt_delta = torch::sqrt(delta);
|
|
172
|
+
|
|
173
|
+
torch::Tensor k1 = H + sqrt_delta;
|
|
174
|
+
torch::Tensor k2 = H - sqrt_delta;
|
|
175
|
+
|
|
176
|
+
return torch::stack({k1, k2}, 1);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
void TriangleMesh::compute_voronoi_areas()
|
|
180
|
+
{
|
|
181
|
+
if (this->voronoi_areas.defined()) return;
|
|
182
|
+
|
|
183
|
+
uint32_t num_vertices = this->vertices.size(0);
|
|
184
|
+
this->voronoi_areas = torch::zeros({static_cast<int64_t>(num_vertices)}, torch::dtype(torch::kFloat32).device(this->vertices.device()));
|
|
185
|
+
uint32_t num_triangles = this->triangles.size(0);
|
|
186
|
+
|
|
187
|
+
triangle_mesh::compute_voronoi_areas(
|
|
188
|
+
num_triangles,
|
|
189
|
+
reinterpret_cast<const int3 *>(this->triangles.data_ptr<int>()),
|
|
190
|
+
reinterpret_cast<const float3 *>(this->vertices.data_ptr<float>()),
|
|
191
|
+
reinterpret_cast<float *>(this->voronoi_areas.data_ptr<float>()));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
void TriangleMesh::compute_gaussian_curvature()
|
|
195
|
+
{
|
|
196
|
+
if (this->gaussian_curvature.defined()) return;
|
|
197
|
+
|
|
198
|
+
if (!this->voronoi_areas.defined()) {
|
|
199
|
+
this->compute_voronoi_areas();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
uint32_t num_vertices = this->vertices.size(0);
|
|
203
|
+
this->gaussian_curvature = torch::zeros({static_cast<int64_t>(num_vertices)}, torch::dtype(torch::kFloat32).device(this->vertices.device()));
|
|
204
|
+
|
|
205
|
+
uint32_t num_triangles = this->triangles.size(0);
|
|
206
|
+
auto vertex_angle_sum = torch::zeros({static_cast<int64_t>(num_vertices)}, torch::dtype(torch::kFloat32).device(this->vertices.device()));
|
|
207
|
+
|
|
208
|
+
triangle_mesh::compute_gaussian_curvature(
|
|
209
|
+
num_vertices,
|
|
210
|
+
num_triangles,
|
|
211
|
+
reinterpret_cast<const int3 *>(this->triangles.data_ptr<int>()),
|
|
212
|
+
reinterpret_cast<const float3 *>(this->vertices.data_ptr<float>()),
|
|
213
|
+
reinterpret_cast<const float *>(this->voronoi_areas.data_ptr<float>()),
|
|
214
|
+
reinterpret_cast<float *>(vertex_angle_sum.data_ptr<float>()),
|
|
215
|
+
reinterpret_cast<float *>(this->gaussian_curvature.data_ptr<float>()));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
torch::Tensor TriangleMesh::get_gaussian_curvature()
|
|
219
|
+
{
|
|
220
|
+
if (!this->gaussian_curvature.defined())
|
|
221
|
+
{
|
|
222
|
+
this->compute_gaussian_curvature();
|
|
223
|
+
}
|
|
224
|
+
return this->gaussian_curvature;
|
|
225
|
+
}
|
|
226
|
+
void TriangleMesh::compute_vertex_lb_cotangent()
|
|
227
|
+
{
|
|
228
|
+
if (this->vertex_lb_cotangent.defined()) return;
|
|
229
|
+
|
|
230
|
+
if (!this->voronoi_areas.defined()) {
|
|
231
|
+
this->compute_voronoi_areas();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
uint32_t num_vertices = this->vertices.size(0);
|
|
235
|
+
this->vertex_lb_cotangent = torch::zeros({static_cast<int64_t>(num_vertices), 3}, torch::dtype(torch::kFloat32).device(this->vertices.device()));
|
|
236
|
+
|
|
237
|
+
uint32_t num_triangles = this->triangles.size(0);
|
|
238
|
+
triangle_mesh::compute_cotangent_laplacian(
|
|
239
|
+
num_vertices,
|
|
240
|
+
num_triangles,
|
|
241
|
+
reinterpret_cast<const int3 *>(this->triangles.data_ptr<int>()),
|
|
242
|
+
reinterpret_cast<const float3 *>(this->vertices.data_ptr<float>()),
|
|
243
|
+
reinterpret_cast<float *>(this->voronoi_areas.data_ptr<float>()),
|
|
244
|
+
reinterpret_cast<float3 *>(this->vertex_lb_cotangent.data_ptr<float>()));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
torch::Tensor TriangleMesh::get_vertex_lb_cotangent()
|
|
248
|
+
{
|
|
249
|
+
if (!this->vertex_lb_cotangent.defined())
|
|
250
|
+
{
|
|
251
|
+
this->compute_vertex_lb_cotangent();
|
|
252
|
+
}
|
|
253
|
+
return this->vertex_lb_cotangent;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
torch::Tensor TriangleMesh::get_voronoi_areas()
|
|
257
|
+
{
|
|
258
|
+
if (!this->voronoi_areas.defined())
|
|
259
|
+
{
|
|
260
|
+
this->compute_voronoi_areas();
|
|
261
|
+
}
|
|
262
|
+
return this->voronoi_areas;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
torch::Tensor TriangleMesh::get_isolated_vertices() {
|
|
266
|
+
torch::Tensor degrees = this->get_vertex_degrees();
|
|
267
|
+
return torch::nonzero(degrees == 0).squeeze(1);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
int32_t TriangleMesh::get_num_isolated_vertices() {
|
|
271
|
+
return this->get_isolated_vertices().size(0);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
void TriangleMesh::remove_isolated_vertices() {
|
|
275
|
+
torch::Tensor degrees = this->get_vertex_degrees();
|
|
276
|
+
torch::Tensor keep_mask = degrees > 0;
|
|
277
|
+
|
|
278
|
+
int64_t num_kept = keep_mask.sum().item<int64_t>();
|
|
279
|
+
if (num_kept == this->vertices.size(0)) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Create old to new mapping. Unused vertices map to -1.
|
|
284
|
+
torch::Tensor cumsum = torch::cumsum(keep_mask.to(torch::kInt32), 0);
|
|
285
|
+
torch::Tensor old_to_new = (cumsum - 1).masked_fill_(~keep_mask, -1);
|
|
286
|
+
|
|
287
|
+
// Filter vertices
|
|
288
|
+
this->vertices = this->vertices.index({keep_mask});
|
|
289
|
+
|
|
290
|
+
// Update triangles
|
|
291
|
+
torch::Tensor flat_tris = this->triangles.to(torch::kInt64).view({-1});
|
|
292
|
+
this->triangles = old_to_new.index_select(0, flat_tris).view({-1, 3}).to(torch::kInt32);
|
|
293
|
+
|
|
294
|
+
// Invalidate all caches
|
|
295
|
+
this->triangle_areas = torch::Tensor();
|
|
296
|
+
this->triangle_normals = torch::Tensor();
|
|
297
|
+
this->surface_area = torch::Tensor();
|
|
298
|
+
this->bvh.reset();
|
|
299
|
+
this->edges = torch::Tensor();
|
|
300
|
+
this->edge_to_triangle_offsets = torch::Tensor();
|
|
301
|
+
this->edge_to_triangle_counts = torch::Tensor();
|
|
302
|
+
this->edge_to_triangle_indices = torch::Tensor();
|
|
303
|
+
this->vertex_to_triangle_offsets = torch::Tensor();
|
|
304
|
+
this->vertex_to_triangle_counts = torch::Tensor();
|
|
305
|
+
this->vertex_to_triangle_indices = torch::Tensor();
|
|
306
|
+
this->vertex_degrees = torch::Tensor();
|
|
307
|
+
this->vertex_lb_uniform = torch::Tensor();
|
|
308
|
+
this->vertex_lb_cotangent = torch::Tensor();
|
|
309
|
+
this->voronoi_areas = torch::Tensor();
|
|
310
|
+
}
|
|
311
|
+
|
|
80
312
|
void TriangleMesh::compute_triangle_areas()
|
|
81
313
|
{
|
|
82
314
|
this->triangle_areas = torch::empty({static_cast<int64_t>(this->num_triangles)}, torch::dtype(torch::kFloat32).device(this->vertices.device()));
|
|
@@ -342,6 +574,11 @@ void TriangleMesh::remove_triangles_by_mask(const torch::Tensor &keep_mask)
|
|
|
342
574
|
this->vertex_to_triangle_offsets = torch::Tensor();
|
|
343
575
|
this->vertex_to_triangle_counts = torch::Tensor();
|
|
344
576
|
this->vertex_to_triangle_indices = torch::Tensor();
|
|
577
|
+
|
|
578
|
+
this->vertex_degrees = torch::Tensor();
|
|
579
|
+
this->vertex_lb_uniform = torch::Tensor();
|
|
580
|
+
this->vertex_lb_cotangent = torch::Tensor();
|
|
581
|
+
this->voronoi_areas = torch::Tensor();
|
|
345
582
|
}
|
|
346
583
|
|
|
347
584
|
int32_t TriangleMesh::get_euler_characteristic()
|
|
@@ -460,6 +697,18 @@ void bind_ds_triangle_mesh(py::module_ &m)
|
|
|
460
697
|
Returns:
|
|
461
698
|
torch.Tensor - Shape (N, 3) float32 tensor of vertex colors.
|
|
462
699
|
)doc")
|
|
700
|
+
.def_property_readonly("vertex_degrees", &TriangleMesh::get_vertex_degrees, R"doc(
|
|
701
|
+
Degree of each vertex (number of incident edges).
|
|
702
|
+
|
|
703
|
+
Returns:
|
|
704
|
+
torch.Tensor - Shape (N,) int32 tensor of vertex degrees.
|
|
705
|
+
)doc")
|
|
706
|
+
.def_property_readonly("vertex_lb_uniform", &TriangleMesh::get_vertex_lb_uniform, R"doc(
|
|
707
|
+
Uniform Laplace-Beltrami operator evaluated at each vertex.
|
|
708
|
+
|
|
709
|
+
Returns:
|
|
710
|
+
torch.Tensor - Shape (N, 3) float32 tensor of uniform laplacian vectors.
|
|
711
|
+
)doc")
|
|
463
712
|
.def_property_readonly("triangles", &TriangleMesh::get_triangles, R"doc(
|
|
464
713
|
Mesh triangles.
|
|
465
714
|
|
|
@@ -629,6 +878,56 @@ void bind_ds_triangle_mesh(py::module_ &m)
|
|
|
629
878
|
Returns:
|
|
630
879
|
torch.Tensor: Tensor of vertex indices that are non-manifold.
|
|
631
880
|
)doc")
|
|
881
|
+
.def("get_isolated_vertices", &TriangleMesh::get_isolated_vertices, R"doc(
|
|
882
|
+
Gets the indices of all isolated vertices (degree 0).
|
|
883
|
+
|
|
884
|
+
Returns:
|
|
885
|
+
torch.Tensor - 1D tensor of isolated vertex indices.
|
|
886
|
+
)doc")
|
|
887
|
+
.def_property_readonly("num_isolated_vertices", &TriangleMesh::get_num_isolated_vertices, R"doc(
|
|
888
|
+
Gets the total number of isolated vertices.
|
|
889
|
+
|
|
890
|
+
Returns:
|
|
891
|
+
int - The total number of isolated vertices.
|
|
892
|
+
)doc")
|
|
893
|
+
.def("remove_isolated_vertices", &TriangleMesh::remove_isolated_vertices, R"doc(
|
|
894
|
+
Removes all isolated vertices from the mesh and reindexes the triangles.
|
|
895
|
+
)doc")
|
|
896
|
+
.def("get_voronoi_areas", &TriangleMesh::get_voronoi_areas, R"doc(
|
|
897
|
+
Get the per-vertex voronoi areas.
|
|
898
|
+
)doc")
|
|
899
|
+
.def("get_gaussian_curvature", &TriangleMesh::get_gaussian_curvature, R"doc(
|
|
900
|
+
Compute and return the discrete Gaussian curvature (angle deficit) at each vertex.
|
|
901
|
+
)doc")
|
|
902
|
+
.def("get_mean_curvature", &TriangleMesh::get_mean_curvature, py::arg("signed_curvature") = false, R"doc(
|
|
903
|
+
Compute and return the discrete Mean curvature at each vertex using the Laplace-Beltrami operator.
|
|
904
|
+
If signed_curvature is true, returns H. If false, returns |H|.
|
|
905
|
+
)doc")
|
|
906
|
+
.def("get_principal_curvatures", &TriangleMesh::get_principal_curvatures, py::arg("signed_curvature") = true, R"doc(
|
|
907
|
+
Compute and return the two principal curvatures (k1, k2) at each vertex as an [N, 2] tensor.
|
|
908
|
+
k1 is the maximum principal curvature, k2 is the minimum principal curvature.
|
|
909
|
+
)doc")
|
|
910
|
+
.def("compute_laplacian", &TriangleMesh::compute_laplacian, py::arg("mode") = 0, R"doc(
|
|
911
|
+
Computes the Laplace-Beltrami operator.
|
|
912
|
+
|
|
913
|
+
Args:
|
|
914
|
+
mode (int): The laplacian mode. 0 for Uniform, 1 for Cotangent.
|
|
915
|
+
|
|
916
|
+
Returns:
|
|
917
|
+
torch.Tensor - Shape (N, 3) float32 tensor of laplacian vectors.
|
|
918
|
+
)doc")
|
|
919
|
+
.def_property_readonly("vertex_lb_cotangent", &TriangleMesh::get_vertex_lb_cotangent, R"doc(
|
|
920
|
+
Cotangent Laplace-Beltrami operator evaluated at each vertex.
|
|
921
|
+
|
|
922
|
+
Returns:
|
|
923
|
+
torch.Tensor - Shape (N, 3) float32 tensor.
|
|
924
|
+
)doc")
|
|
925
|
+
.def_property_readonly("voronoi_areas", &TriangleMesh::get_voronoi_areas, R"doc(
|
|
926
|
+
Vertex voronoi areas (1/3 of the sum of incident triangle areas).
|
|
927
|
+
|
|
928
|
+
Returns:
|
|
929
|
+
torch.Tensor - Shape (N,) float32 tensor.
|
|
930
|
+
)doc")
|
|
632
931
|
.def("remove_triangles_by_mask", &TriangleMesh::remove_triangles_by_mask, py::arg("keep_mask"), R"doc(
|
|
633
932
|
Removes triangles from the mesh based on a boolean mask.
|
|
634
933
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#include <torch/extension.h>
|
|
2
|
+
#include "../../primitive/ray.h"
|
|
3
|
+
#include "../../check.h"
|
|
4
|
+
#include <pybind11/pybind11.h>
|
|
5
|
+
|
|
6
|
+
namespace py = pybind11;
|
|
7
|
+
|
|
8
|
+
inline float3 tensor_to_float3_ray(const torch::Tensor& t) {
|
|
9
|
+
TORCH_CHECK(t.dim() == 1 && t.size(0) == 3, "Tensor must be 1D with 3 elements");
|
|
10
|
+
auto t_contig = t.contiguous().cpu().to(torch::kFloat32);
|
|
11
|
+
float* ptr = t_contig.data_ptr<float>();
|
|
12
|
+
return make_float3(ptr[0], ptr[1], ptr[2]);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
inline torch::Tensor float3_to_tensor_ray(const float3& f) {
|
|
16
|
+
return torch::tensor({f.x, f.y, f.z}, torch::dtype(torch::kFloat32));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
void bind_primitive_ray(py::module_& m) {
|
|
20
|
+
py::class_<Ray>(m, "Ray")
|
|
21
|
+
.def(py::init([](const torch::Tensor& origin, const torch::Tensor& dir) {
|
|
22
|
+
return Ray(tensor_to_float3_ray(origin), tensor_to_float3_ray(dir));
|
|
23
|
+
}), py::arg("origin"), py::arg("direction"))
|
|
24
|
+
.def_property_readonly("origin", [](const Ray& self) { return float3_to_tensor_ray(self.origin); })
|
|
25
|
+
.def_property_readonly("direction", [](const Ray& self) { return float3_to_tensor_ray(self.direction); })
|
|
26
|
+
.def_property_readonly("inv_direction", [](const Ray& self) { return float3_to_tensor_ray(self.inv_direction); })
|
|
27
|
+
.def_property_readonly("t_min", [](const Ray& self) { return self.t_min; })
|
|
28
|
+
.def_property_readonly("t_max", [](const Ray& self) { return self.t_max; })
|
|
29
|
+
.def("at", [](const Ray& self, float t) {
|
|
30
|
+
return float3_to_tensor_ray(self.at(t));
|
|
31
|
+
}, py::arg("t"))
|
|
32
|
+
.def("is_intersect_aabb", [](const Ray& self, const torch::Tensor& aabb_min, const torch::Tensor& aabb_max) {
|
|
33
|
+
float t_hit;
|
|
34
|
+
bool hit = self.is_intersect_aabb(tensor_to_float3_ray(aabb_min), tensor_to_float3_ray(aabb_max), t_hit);
|
|
35
|
+
return py::make_tuple(hit, t_hit);
|
|
36
|
+
}, py::arg("aabb_min"), py::arg("aabb_max"));
|
|
37
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#include <torch/extension.h>
|
|
2
|
+
#include "../../primitive/triangle.h"
|
|
3
|
+
#include "../../check.h"
|
|
4
|
+
#include <pybind11/pybind11.h>
|
|
5
|
+
|
|
6
|
+
namespace py = pybind11;
|
|
7
|
+
|
|
8
|
+
inline float3 tensor_to_float3(const torch::Tensor& t) {
|
|
9
|
+
TORCH_CHECK(t.dim() == 1 && t.size(0) == 3, "Tensor must be 1D with 3 elements");
|
|
10
|
+
auto t_contig = t.contiguous().cpu().to(torch::kFloat32);
|
|
11
|
+
float* ptr = t_contig.data_ptr<float>();
|
|
12
|
+
return make_float3(ptr[0], ptr[1], ptr[2]);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
inline torch::Tensor float3_to_tensor(const float3& f) {
|
|
16
|
+
return torch::tensor({f.x, f.y, f.z}, torch::dtype(torch::kFloat32));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
void bind_primitive_triangle(py::module_& m) {
|
|
20
|
+
py::class_<Triangle>(m, "Triangle")
|
|
21
|
+
.def(py::init([](const torch::Tensor& v0, const torch::Tensor& v1, const torch::Tensor& v2) {
|
|
22
|
+
return Triangle(tensor_to_float3(v0), tensor_to_float3(v1), tensor_to_float3(v2));
|
|
23
|
+
}), py::arg("v0"), py::arg("v1"), py::arg("v2"))
|
|
24
|
+
.def("is_intersect_ray", [](const Triangle& self, const Ray& ray) {
|
|
25
|
+
float t_hit, u, v;
|
|
26
|
+
bool hit = self.is_intersect_ray(ray, t_hit, u, v);
|
|
27
|
+
return py::make_tuple(hit, t_hit, u, v);
|
|
28
|
+
}, py::arg("ray"))
|
|
29
|
+
.def("compute_closest_point", [](const Triangle& self, const torch::Tensor& p) {
|
|
30
|
+
return float3_to_tensor(self.compute_closest_point(tensor_to_float3(p)));
|
|
31
|
+
}, py::arg("p"))
|
|
32
|
+
.def("compute_normal", [](const Triangle& self) {
|
|
33
|
+
return float3_to_tensor(self.compute_normal());
|
|
34
|
+
})
|
|
35
|
+
.def("compute_area", &Triangle::compute_area)
|
|
36
|
+
.def("sample_point", [](const Triangle& self, float r1, float r2) {
|
|
37
|
+
return float3_to_tensor(self.sample_point(r1, r2));
|
|
38
|
+
}, py::arg("r1"), py::arg("r2"))
|
|
39
|
+
.def("compute_aabb", [](const Triangle& self) {
|
|
40
|
+
float3 aabb_min, aabb_max;
|
|
41
|
+
self.compute_aabb(aabb_min, aabb_max);
|
|
42
|
+
return py::make_tuple(float3_to_tensor(aabb_min), float3_to_tensor(aabb_max));
|
|
43
|
+
})
|
|
44
|
+
.def("test_intersection", [](const Triangle& self, const Triangle& other) {
|
|
45
|
+
return self.test_intersection(other);
|
|
46
|
+
}, py::arg("other"))
|
|
47
|
+
.def("is_obtuse", [](const Triangle& self) {
|
|
48
|
+
return self.is_obtuse();
|
|
49
|
+
})
|
|
50
|
+
.def("compute_centroid", [](const Triangle& self) {
|
|
51
|
+
return float3_to_tensor(self.compute_centroid());
|
|
52
|
+
})
|
|
53
|
+
.def("compute_circumcenter", [](const Triangle& self, bool strict_inside) {
|
|
54
|
+
return float3_to_tensor(self.compute_circumcenter(strict_inside));
|
|
55
|
+
}, py::arg("strict_inside") = false)
|
|
56
|
+
.def("test_point_on_tria_plane", [](const Triangle& self, const torch::Tensor& p, float eps) {
|
|
57
|
+
return self.test_point_on_tria_plane(tensor_to_float3(p), eps);
|
|
58
|
+
}, py::arg("p"), py::arg("eps") = 1e-5f)
|
|
59
|
+
.def("test_point_inside_on_tria_plane", [](const Triangle& self, const torch::Tensor& p) {
|
|
60
|
+
return self.test_point_inside_on_tria_plane(tensor_to_float3(p));
|
|
61
|
+
}, py::arg("p"))
|
|
62
|
+
.def("test_point_inside", [](const Triangle& self, const torch::Tensor& p, float eps) {
|
|
63
|
+
return self.test_point_inside(tensor_to_float3(p), eps);
|
|
64
|
+
}, py::arg("p"), py::arg("eps") = 1e-5f)
|
|
65
|
+
.def_property_readonly("v0", [](const Triangle& self) { return float3_to_tensor(self.v0); })
|
|
66
|
+
.def_property_readonly("v1", [](const Triangle& self) { return float3_to_tensor(self.v1); })
|
|
67
|
+
.def_property_readonly("v2", [](const Triangle& self) { return float3_to_tensor(self.v2); });
|
|
68
|
+
}
|