conquer3d 0.2.8__tar.gz → 0.2.9__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.8/conquer3d.egg-info → conquer3d-0.2.9}/PKG-INFO +2 -2
- {conquer3d-0.2.8 → conquer3d-0.2.9}/README.md +1 -1
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/_C.so +0 -0
- conquer3d-0.2.9/conquer3d/csrc/binds/data_structure/grid.cpp +129 -0
- conquer3d-0.2.9/conquer3d/csrc/binds/ops/chamfer.cpp +42 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/binds/ops/mc.cpp +12 -2
- conquer3d-0.2.9/conquer3d/csrc/ops/chamfer.cu +73 -0
- conquer3d-0.2.9/conquer3d/csrc/ops/chamfer.h +18 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/ops/mc.cu +42 -12
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/ops/mc.h +3 -2
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/pybind.cpp +2 -0
- conquer3d-0.2.9/conquer3d/ops/__init__.py +11 -0
- conquer3d-0.2.9/conquer3d/ops/distance.py +28 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/ops/grid.py +23 -2
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/ops/marching_cubes.py +16 -5
- {conquer3d-0.2.8 → conquer3d-0.2.9/conquer3d.egg-info}/PKG-INFO +2 -2
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d.egg-info/SOURCES.txt +4 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/pyproject.toml +1 -1
- conquer3d-0.2.8/conquer3d/csrc/binds/data_structure/grid.cpp +0 -66
- conquer3d-0.2.8/conquer3d/ops/__init__.py +0 -7
- {conquer3d-0.2.8 → conquer3d-0.2.9}/LICENSE +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/MANIFEST.in +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/_C.pyi +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/__init__.py +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/creation/__init__.py +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/creation/triangle_creation.py +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/binds/creation/triangle_creation.cpp +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/binds/data_structure/bvh.cpp +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/binds/data_structure/gs_bvh.cpp +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/binds/data_structure/kdtree.cpp +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/binds/data_structure/mesh_bvh.cpp +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/binds/data_structure/pgs_bvh.cpp +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/binds/data_structure/triangle_mesh.cpp +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/binds/primitive/gs.cpp +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/binds/primitive/pgs.cpp +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/check.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/constants.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/creation/triangle_creation.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/data_structure/bvh.cu +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/data_structure/bvh.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/data_structure/gs_bvh.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/data_structure/kdtree.cu +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/data_structure/kdtree.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/data_structure/mesh_bvh.cu +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/data_structure/mesh_bvh.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/data_structure/pgs_bvh.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/data_structure/triangle_mesh.cu +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/data_structure/triangle_mesh.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/data_structure/zcurve.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/maths/f2x2.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/maths/f3x1.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/maths/f3x3.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/maths/f3x4.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/maths/f4x1.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/maths/f4x4.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/maths/maths.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/maths/ops.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/ops/mc_data.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/primitive/aabb.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/primitive/edge.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/primitive/gs.cu +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/primitive/gs.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/primitive/gs_aabb.cu +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/primitive/gs_math.cuh +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/primitive/pgs.cu +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/primitive/pgs.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/primitive/pgs_aabb.cu +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/primitive/pgs_math.cuh +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/primitive/ray.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/csrc/primitive/triangles.h +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/data_structure/__init__.py +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/primitive/__init__.py +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/primitive/gs.py +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d/primitive/pgs.py +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d.egg-info/dependency_links.txt +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d.egg-info/not-zip-safe +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d.egg-info/requires.txt +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/conquer3d.egg-info/top_level.txt +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/setup.cfg +0 -0
- {conquer3d-0.2.8 → conquer3d-0.2.9}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: conquer3d
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: Geometric Cuda Tool Box
|
|
5
5
|
Author-email: Do Hoang Khoi <khoido8899@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -56,7 +56,7 @@ pip install torch==2.8.0 torchvision==0.23.0 torchaudio==2.8.0 --index-url https
|
|
|
56
56
|
pip install pybind11-stubgen
|
|
57
57
|
pip install git+https://github.com/KhoiDOO/geocutool.git --no-build-isolation
|
|
58
58
|
|
|
59
|
-
pip install plotly open3d jupyter trimesh
|
|
59
|
+
pip install plotly open3d jupyter trimesh point-cloud-utils
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
# Development
|
|
@@ -28,7 +28,7 @@ pip install torch==2.8.0 torchvision==0.23.0 torchaudio==2.8.0 --index-url https
|
|
|
28
28
|
pip install pybind11-stubgen
|
|
29
29
|
pip install git+https://github.com/KhoiDOO/geocutool.git --no-build-isolation
|
|
30
30
|
|
|
31
|
-
pip install plotly open3d jupyter trimesh
|
|
31
|
+
pip install plotly open3d jupyter trimesh point-cloud-utils
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
# Development
|
|
Binary file
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#include <torch/extension.h>
|
|
2
|
+
#include <pybind11/pybind11.h>
|
|
3
|
+
#include <pybind11/stl.h>
|
|
4
|
+
#include <tuple>
|
|
5
|
+
#include <string>
|
|
6
|
+
#include <vector>
|
|
7
|
+
|
|
8
|
+
namespace py = pybind11;
|
|
9
|
+
|
|
10
|
+
std::tuple<torch::Tensor, torch::Tensor, torch::Tensor> create_voxel_grid(
|
|
11
|
+
std::vector<float> grid_min,
|
|
12
|
+
std::vector<float> grid_max,
|
|
13
|
+
std::vector<int64_t> res,
|
|
14
|
+
std::string device_str
|
|
15
|
+
) {
|
|
16
|
+
TORCH_CHECK(grid_min.size() == 3, "grid_min must have 3 elements.");
|
|
17
|
+
TORCH_CHECK(grid_max.size() == 3, "grid_max must have 3 elements.");
|
|
18
|
+
TORCH_CHECK(res.size() == 3, "res must have 3 elements.");
|
|
19
|
+
|
|
20
|
+
c10::Device device(device_str);
|
|
21
|
+
auto options = torch::TensorOptions().device(device).dtype(torch::kFloat32);
|
|
22
|
+
|
|
23
|
+
int64_t rx = res[0];
|
|
24
|
+
int64_t ry = res[1];
|
|
25
|
+
int64_t rz = res[2];
|
|
26
|
+
|
|
27
|
+
auto x = torch::linspace(grid_min[0], grid_max[0], rx, options);
|
|
28
|
+
auto y = torch::linspace(grid_min[1], grid_max[1], ry, options);
|
|
29
|
+
auto z = torch::linspace(grid_min[2], grid_max[2], rz, options);
|
|
30
|
+
|
|
31
|
+
auto grids = torch::meshgrid({x, y, z}, "ij");
|
|
32
|
+
auto grid_x = grids[0].flatten();
|
|
33
|
+
auto grid_y = grids[1].flatten();
|
|
34
|
+
auto grid_z = grids[2].flatten();
|
|
35
|
+
|
|
36
|
+
auto grid_vertices = torch::stack({grid_x, grid_y, grid_z}, 1).contiguous();
|
|
37
|
+
|
|
38
|
+
auto options_int = options.dtype(torch::kInt64);
|
|
39
|
+
auto i = torch::arange(rx - 1, options_int);
|
|
40
|
+
auto j = torch::arange(ry - 1, options_int);
|
|
41
|
+
auto k = torch::arange(rz - 1, options_int);
|
|
42
|
+
|
|
43
|
+
auto idx_grids = torch::meshgrid({i, j, k}, "ij");
|
|
44
|
+
auto vi = idx_grids[0];
|
|
45
|
+
auto vj = idx_grids[1];
|
|
46
|
+
auto vk = idx_grids[2];
|
|
47
|
+
|
|
48
|
+
// Voxel connectivity indexing mapping matching mc.cu
|
|
49
|
+
auto v0 = vi * ry * rz + vj * rz + vk;
|
|
50
|
+
auto v1 = (vi + 1) * ry * rz + vj * rz + vk;
|
|
51
|
+
auto v2 = (vi + 1) * ry * rz + (vj + 1) * rz + vk;
|
|
52
|
+
auto v3 = vi * ry * rz + (vj + 1) * rz + vk;
|
|
53
|
+
auto v4 = vi * ry * rz + vj * rz + (vk + 1);
|
|
54
|
+
auto v5 = (vi + 1) * ry * rz + vj * rz + (vk + 1);
|
|
55
|
+
auto v6 = (vi + 1) * ry * rz + (vj + 1) * rz + (vk + 1);
|
|
56
|
+
auto v7 = vi * ry * rz + (vj + 1) * rz + (vk + 1);
|
|
57
|
+
|
|
58
|
+
auto voxels = torch::stack({v0, v1, v2, v3, v4, v5, v6, v7}, -1).view({-1, 8}).contiguous().to(torch::kInt32);
|
|
59
|
+
|
|
60
|
+
auto i_v = torch::arange(rx, options_int);
|
|
61
|
+
auto j_v = torch::arange(ry, options_int);
|
|
62
|
+
auto k_v = torch::arange(rz, options_int);
|
|
63
|
+
auto idx_grids_v = torch::meshgrid({i_v, j_v, k_v}, "ij");
|
|
64
|
+
auto out_idx_grids = torch::stack({idx_grids_v[0].flatten(), idx_grids_v[1].flatten(), idx_grids_v[2].flatten()}, -1).contiguous();
|
|
65
|
+
|
|
66
|
+
return std::make_tuple(grid_vertices, voxels, out_idx_grids);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
torch::Tensor compute_grid_normal(torch::Tensor sdf, torch::Tensor grid_vertices, torch::Tensor idx_grids, std::vector<int64_t> res) {
|
|
70
|
+
TORCH_CHECK(res.size() == 3, "res must have 3 elements.");
|
|
71
|
+
|
|
72
|
+
auto i = idx_grids.select(1, 0);
|
|
73
|
+
auto j = idx_grids.select(1, 1);
|
|
74
|
+
auto k = idx_grids.select(1, 2);
|
|
75
|
+
|
|
76
|
+
auto rx = res[0];
|
|
77
|
+
auto ry = res[1];
|
|
78
|
+
auto rz = res[2];
|
|
79
|
+
|
|
80
|
+
auto i_prev = torch::clamp(i - 1, 0, rx - 1);
|
|
81
|
+
auto i_next = torch::clamp(i + 1, 0, rx - 1);
|
|
82
|
+
|
|
83
|
+
auto j_prev = torch::clamp(j - 1, 0, ry - 1);
|
|
84
|
+
auto j_next = torch::clamp(j + 1, 0, ry - 1);
|
|
85
|
+
|
|
86
|
+
auto k_prev = torch::clamp(k - 1, 0, rz - 1);
|
|
87
|
+
auto k_next = torch::clamp(k + 1, 0, rz - 1);
|
|
88
|
+
|
|
89
|
+
auto idx_x_prev = i_prev * ry * rz + j * rz + k;
|
|
90
|
+
auto idx_x_next = i_next * ry * rz + j * rz + k;
|
|
91
|
+
|
|
92
|
+
auto idx_y_prev = i * ry * rz + j_prev * rz + k;
|
|
93
|
+
auto idx_y_next = i * ry * rz + j_next * rz + k;
|
|
94
|
+
|
|
95
|
+
auto idx_z_prev = i * ry * rz + j * rz + k_prev;
|
|
96
|
+
auto idx_z_next = i * ry * rz + j * rz + k_next;
|
|
97
|
+
|
|
98
|
+
auto sdf_flat = sdf.flatten();
|
|
99
|
+
|
|
100
|
+
auto diff_x = sdf_flat.index_select(0, idx_x_next) - sdf_flat.index_select(0, idx_x_prev);
|
|
101
|
+
auto diff_y = sdf_flat.index_select(0, idx_y_next) - sdf_flat.index_select(0, idx_y_prev);
|
|
102
|
+
auto diff_z = sdf_flat.index_select(0, idx_z_next) - sdf_flat.index_select(0, idx_z_prev);
|
|
103
|
+
|
|
104
|
+
auto vx = grid_vertices.select(1, 0);
|
|
105
|
+
auto vy = grid_vertices.select(1, 1);
|
|
106
|
+
auto vz = grid_vertices.select(1, 2);
|
|
107
|
+
|
|
108
|
+
auto dx = vx.index_select(0, idx_x_next) - vx.index_select(0, idx_x_prev);
|
|
109
|
+
auto dy = vy.index_select(0, idx_y_next) - vy.index_select(0, idx_y_prev);
|
|
110
|
+
auto dz = vz.index_select(0, idx_z_next) - vz.index_select(0, idx_z_prev);
|
|
111
|
+
|
|
112
|
+
dx = torch::where(dx == 0, torch::tensor(1e-5f, dx.options()), dx);
|
|
113
|
+
dy = torch::where(dy == 0, torch::tensor(1e-5f, dy.options()), dy);
|
|
114
|
+
dz = torch::where(dz == 0, torch::tensor(1e-5f, dz.options()), dz);
|
|
115
|
+
|
|
116
|
+
auto grad_x = diff_x / dx;
|
|
117
|
+
auto grad_y = diff_y / dy;
|
|
118
|
+
auto grad_z = diff_z / dz;
|
|
119
|
+
|
|
120
|
+
auto normals = torch::stack({grad_x, grad_y, grad_z}, 1);
|
|
121
|
+
return torch::nn::functional::normalize(normals, torch::nn::functional::NormalizeFuncOptions().p(2).dim(1));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
void bind_ds_grid(py::module_& m) {
|
|
125
|
+
m.def("create_voxel_grid", &create_voxel_grid, "Creates a structured 3D voxel grid.",
|
|
126
|
+
py::arg("grid_min"), py::arg("grid_max"), py::arg("res"), py::arg("device_str") = "cuda");
|
|
127
|
+
m.def("compute_grid_normal", &compute_grid_normal, "Computes surface normals for a grid.",
|
|
128
|
+
py::arg("sdf"), py::arg("grid_vertices"), py::arg("idx_grids"), py::arg("res"));
|
|
129
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#include <torch/extension.h>
|
|
2
|
+
#include <pybind11/pybind11.h>
|
|
3
|
+
#include "../../ops/chamfer.h"
|
|
4
|
+
#include "../../check.h"
|
|
5
|
+
|
|
6
|
+
namespace py = pybind11;
|
|
7
|
+
|
|
8
|
+
std::tuple<torch::Tensor, torch::Tensor> one_sided_chamfer_distance_wrapper(
|
|
9
|
+
torch::Tensor query_points,
|
|
10
|
+
torch::Tensor reference_points
|
|
11
|
+
) {
|
|
12
|
+
CHECK_INPUT(query_points);
|
|
13
|
+
CHECK_INPUT(reference_points);
|
|
14
|
+
|
|
15
|
+
uint32_t num_query_points = query_points.size(0);
|
|
16
|
+
uint32_t num_reference_points = reference_points.size(0);
|
|
17
|
+
|
|
18
|
+
const float3* __restrict__ p_query_points = (float3*)query_points.data_ptr<float>();
|
|
19
|
+
const float3* __restrict__ p_reference_points = (float3*)reference_points.data_ptr<float>();
|
|
20
|
+
|
|
21
|
+
torch::Tensor distances = torch::empty({num_query_points}, query_points.options());
|
|
22
|
+
torch::Tensor indices = torch::empty({num_query_points}, query_points.options().dtype(torch::kInt64));
|
|
23
|
+
|
|
24
|
+
float* __restrict__ p_distances = distances.data_ptr<float>();
|
|
25
|
+
int64_t* __restrict__ p_indices = indices.data_ptr<int64_t>();
|
|
26
|
+
|
|
27
|
+
one_sided_chamfer_distance(
|
|
28
|
+
num_query_points,
|
|
29
|
+
p_query_points,
|
|
30
|
+
num_reference_points,
|
|
31
|
+
p_reference_points,
|
|
32
|
+
p_distances,
|
|
33
|
+
p_indices
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
return std::make_tuple(distances, indices);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
void bind_ops_chamfer(py::module_& m) {
|
|
40
|
+
m.def("one_sided_chamfer_distance", &one_sided_chamfer_distance_wrapper, "One Sided Chamfer Distance",
|
|
41
|
+
py::arg("query_points"), py::arg("reference_points"));
|
|
42
|
+
}
|
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
namespace py = pybind11;
|
|
7
7
|
|
|
8
|
-
std::tuple<torch::Tensor, torch::Tensor
|
|
8
|
+
std::tuple<torch::Tensor, torch::Tensor, std::optional<torch::Tensor>> marching_cubes_wrapper(
|
|
9
9
|
torch::Tensor grid_vertices,
|
|
10
10
|
torch::Tensor voxels,
|
|
11
11
|
torch::Tensor voxel_values,
|
|
12
|
+
std::optional<torch::Tensor> grid_normals,
|
|
12
13
|
float iso
|
|
13
14
|
) {
|
|
14
15
|
CHECK_INPUT(grid_vertices);
|
|
@@ -21,11 +22,18 @@ std::tuple<torch::Tensor, torch::Tensor> marching_cubes_wrapper(
|
|
|
21
22
|
const uint32_t* __restrict__ p_voxels = (uint32_t*)voxels.data_ptr<int32_t>();
|
|
22
23
|
const float* __restrict__ p_voxel_values = voxel_values.data_ptr<float>();
|
|
23
24
|
|
|
25
|
+
const float3* __restrict__ p_grid_normals = nullptr;
|
|
26
|
+
if (grid_normals.has_value()) {
|
|
27
|
+
CHECK_INPUT(grid_normals.value());
|
|
28
|
+
p_grid_normals = (float3*)grid_normals.value().data_ptr<float>();
|
|
29
|
+
}
|
|
30
|
+
|
|
24
31
|
return mc::marching_cubes(
|
|
25
32
|
num_voxels,
|
|
26
33
|
p_grid_vertices,
|
|
27
34
|
p_voxels,
|
|
28
35
|
p_voxel_values,
|
|
36
|
+
p_grid_normals,
|
|
29
37
|
iso,
|
|
30
38
|
grid_vertices.options(),
|
|
31
39
|
voxels.options()
|
|
@@ -33,5 +41,7 @@ std::tuple<torch::Tensor, torch::Tensor> marching_cubes_wrapper(
|
|
|
33
41
|
}
|
|
34
42
|
|
|
35
43
|
void bind_ops_mc(py::module_& m) {
|
|
36
|
-
m.def("marching_cubes", &marching_cubes_wrapper, "Marching Cubes"
|
|
44
|
+
m.def("marching_cubes", &marching_cubes_wrapper, "Marching Cubes",
|
|
45
|
+
py::arg("grid_vertices"), py::arg("voxels"), py::arg("voxel_values"),
|
|
46
|
+
py::arg("grid_normals") = std::nullopt, py::arg("iso") = 0.0f);
|
|
37
47
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#include "../data_structure/kdtree.h"
|
|
2
|
+
|
|
3
|
+
#include <cstdint>
|
|
4
|
+
#include <thrust/device_vector.h>
|
|
5
|
+
#include <thrust/sequence.h>
|
|
6
|
+
|
|
7
|
+
__global__ void one_sided_chamfer_distance_kernel(
|
|
8
|
+
const uint32_t num_query_points,
|
|
9
|
+
const float3 *__restrict__ query_points,
|
|
10
|
+
const uint32_t num_reference_points,
|
|
11
|
+
const float3 *__restrict__ tree_points,
|
|
12
|
+
const int64_t *__restrict__ tree_inds,
|
|
13
|
+
float *__restrict__ distances,
|
|
14
|
+
int64_t *__restrict__ indices)
|
|
15
|
+
{
|
|
16
|
+
uint32_t idx = blockIdx.x * blockDim.x + threadIdx.x;
|
|
17
|
+
if (idx >= num_query_points)
|
|
18
|
+
return;
|
|
19
|
+
|
|
20
|
+
float3 query_point = query_points[idx];
|
|
21
|
+
|
|
22
|
+
float best_dists[MAX_K];
|
|
23
|
+
int64_t best_inds[MAX_K];
|
|
24
|
+
|
|
25
|
+
#pragma unroll
|
|
26
|
+
for (int i = 0; i < MAX_K; i++)
|
|
27
|
+
{
|
|
28
|
+
best_dists[i] = FLT_MAX;
|
|
29
|
+
best_inds[i] = -1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
kdtree::query_kdtree_loop(
|
|
33
|
+
query_point,
|
|
34
|
+
num_reference_points,
|
|
35
|
+
tree_points,
|
|
36
|
+
tree_inds,
|
|
37
|
+
1,
|
|
38
|
+
best_dists,
|
|
39
|
+
best_inds);
|
|
40
|
+
|
|
41
|
+
distances[idx] = best_dists[0];
|
|
42
|
+
indices[idx] = best_inds[0];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
void one_sided_chamfer_distance(
|
|
46
|
+
const uint32_t num_query_points,
|
|
47
|
+
const float3 *__restrict__ query_points,
|
|
48
|
+
const uint32_t num_reference_points,
|
|
49
|
+
const float3 *__restrict__ reference_points,
|
|
50
|
+
float *__restrict__ distances,
|
|
51
|
+
int64_t *__restrict__ indices)
|
|
52
|
+
{
|
|
53
|
+
thrust::device_vector<float3> cloned_ref_points(reference_points, reference_points + num_reference_points);
|
|
54
|
+
thrust::device_vector<int64_t> reference_indices(num_reference_points);
|
|
55
|
+
thrust::sequence(reference_indices.begin(), reference_indices.end());
|
|
56
|
+
|
|
57
|
+
kdtree::build(
|
|
58
|
+
num_reference_points,
|
|
59
|
+
thrust::raw_pointer_cast(cloned_ref_points.data()),
|
|
60
|
+
thrust::raw_pointer_cast(reference_indices.data()));
|
|
61
|
+
|
|
62
|
+
uint32_t threads = NTHREADS;
|
|
63
|
+
uint32_t blocks = (num_query_points + threads - 1) / threads;
|
|
64
|
+
|
|
65
|
+
one_sided_chamfer_distance_kernel<<<blocks, threads>>>(
|
|
66
|
+
num_query_points,
|
|
67
|
+
query_points,
|
|
68
|
+
num_reference_points,
|
|
69
|
+
thrust::raw_pointer_cast(cloned_ref_points.data()),
|
|
70
|
+
thrust::raw_pointer_cast(reference_indices.data()),
|
|
71
|
+
distances,
|
|
72
|
+
indices);
|
|
73
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#ifndef CHAMFER_H
|
|
2
|
+
#define CHAMFER_H
|
|
3
|
+
|
|
4
|
+
#include "../constants.h"
|
|
5
|
+
#include "../maths/maths.h"
|
|
6
|
+
|
|
7
|
+
#include <cuda_runtime.h>
|
|
8
|
+
|
|
9
|
+
void one_sided_chamfer_distance(
|
|
10
|
+
const uint32_t num_query_points,
|
|
11
|
+
const float3* __restrict__ query_points,
|
|
12
|
+
const uint32_t num_reference_points,
|
|
13
|
+
const float3* __restrict__ reference_points,
|
|
14
|
+
float* __restrict__ distances,
|
|
15
|
+
int64_t* __restrict__ indices
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
#endif // CHAMFER_H
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#include "mc.h"
|
|
2
|
-
|
|
2
|
+
#include "../maths/maths.h"
|
|
3
3
|
#include <cuda_runtime.h>
|
|
4
4
|
#include <thrust/sort.h>
|
|
5
5
|
#include <thrust/scan.h>
|
|
@@ -25,7 +25,7 @@ namespace mc
|
|
|
25
25
|
struct num_triangles_functor
|
|
26
26
|
{
|
|
27
27
|
__device__ uint32_t operator()(const uint8_t code) const {
|
|
28
|
-
return trinumTable[code + 1] - trinumTable[code];
|
|
28
|
+
return (trinumTable[code + 1] - trinumTable[code]) / 3;
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
31
|
|
|
@@ -175,8 +175,10 @@ namespace mc
|
|
|
175
175
|
const Edge* unique_edges,
|
|
176
176
|
const float3* grid_vertices,
|
|
177
177
|
const float* values,
|
|
178
|
+
const float3* grid_normals,
|
|
178
179
|
const float iso,
|
|
179
|
-
float3* out_verts
|
|
180
|
+
float3* out_verts,
|
|
181
|
+
float3* out_normals
|
|
180
182
|
)
|
|
181
183
|
{
|
|
182
184
|
uint32_t v_idx = blockIdx.x * blockDim.x + threadIdx.x;
|
|
@@ -196,28 +198,42 @@ namespace mc
|
|
|
196
198
|
|
|
197
199
|
// 3. Interpolate (Differentiable formula)
|
|
198
200
|
float3 p;
|
|
201
|
+
float3 n;
|
|
202
|
+
bool has_normals = grid_normals != nullptr;
|
|
203
|
+
float3 n0 = has_normals ? grid_normals[v0_idx] : make_float3(0, 0, 0);
|
|
204
|
+
float3 n1 = has_normals ? grid_normals[v1_idx] : make_float3(0, 0, 0);
|
|
199
205
|
|
|
200
206
|
if (fabsf(iso - val0) < EPS)
|
|
201
207
|
{
|
|
202
208
|
p = p0;
|
|
209
|
+
if (has_normals) n = n0;
|
|
203
210
|
}
|
|
204
211
|
else if (fabsf(iso - val1) < EPS)
|
|
205
212
|
{
|
|
206
213
|
p = p1;
|
|
214
|
+
if (has_normals) n = n1;
|
|
207
215
|
}
|
|
208
216
|
else if (fabsf(val0 - val1) < EPS)
|
|
209
217
|
{
|
|
210
218
|
p = p0;
|
|
219
|
+
if (has_normals) n = n0;
|
|
211
220
|
}
|
|
212
221
|
else
|
|
213
222
|
{
|
|
214
223
|
float t = (val1 != val0) ? fmaxf(0.0f, fminf(1.0f, (iso - val0) / (val1 - val0))) : 0.5f;
|
|
215
|
-
|
|
216
|
-
p
|
|
217
|
-
|
|
224
|
+
|
|
225
|
+
p = p0 + (p1 - p0) * t;
|
|
226
|
+
|
|
227
|
+
if (has_normals) {
|
|
228
|
+
n = n0 + (n1 - n0) * t;
|
|
229
|
+
n = maths::normalize(n);
|
|
230
|
+
}
|
|
218
231
|
}
|
|
219
232
|
|
|
220
233
|
out_verts[v_idx] = p;
|
|
234
|
+
if (has_normals) {
|
|
235
|
+
out_normals[v_idx] = n;
|
|
236
|
+
}
|
|
221
237
|
}
|
|
222
238
|
|
|
223
239
|
void compute_active_voxels(
|
|
@@ -340,15 +356,17 @@ namespace mc
|
|
|
340
356
|
const Edge* unique_edges,
|
|
341
357
|
const float3* grid_vertices,
|
|
342
358
|
const float* values,
|
|
359
|
+
const float3* grid_normals,
|
|
343
360
|
const float iso,
|
|
344
|
-
float3* out_verts
|
|
361
|
+
float3* out_verts,
|
|
362
|
+
float3* out_normals
|
|
345
363
|
)
|
|
346
364
|
{
|
|
347
365
|
if (num_unique_edges == 0) return;
|
|
348
366
|
int block_size = NTHREADS;
|
|
349
367
|
int grid_size = (num_unique_edges + block_size - 1) / block_size;
|
|
350
368
|
interpolate_vertices_kernel<<<grid_size, block_size>>>(
|
|
351
|
-
num_unique_edges, unique_edges, grid_vertices, values, iso, out_verts);
|
|
369
|
+
num_unique_edges, unique_edges, grid_vertices, values, grid_normals, iso, out_verts, out_normals);
|
|
352
370
|
}
|
|
353
371
|
|
|
354
372
|
void compute_number_triangles(
|
|
@@ -417,11 +435,12 @@ namespace mc
|
|
|
417
435
|
num_active_voxels, used_voxel_codes, voxel_edge_to_vert_idx, voxel_triangle_prefix_sums, out_triangles);
|
|
418
436
|
}
|
|
419
437
|
|
|
420
|
-
std::tuple<torch::Tensor, torch::Tensor
|
|
438
|
+
std::tuple<torch::Tensor, torch::Tensor, std::optional<torch::Tensor>> marching_cubes(
|
|
421
439
|
const uint32_t num_voxels,
|
|
422
440
|
const float3* __restrict__ grid_vertices,
|
|
423
441
|
const uint32_t* __restrict__ voxels,
|
|
424
442
|
const float* __restrict__ voxel_values,
|
|
443
|
+
const float3* __restrict__ grid_normals,
|
|
425
444
|
const float iso,
|
|
426
445
|
torch::TensorOptions vert_options,
|
|
427
446
|
torch::TensorOptions tri_options
|
|
@@ -437,9 +456,12 @@ namespace mc
|
|
|
437
456
|
|
|
438
457
|
if (num_active_voxels == 0) {
|
|
439
458
|
CHECK_CUDA_INTERNAL(cudaFree(voxel_codes));
|
|
459
|
+
std::optional<torch::Tensor> out_n = std::nullopt;
|
|
460
|
+
if (grid_normals != nullptr) out_n = torch::empty({0, 3}, vert_options);
|
|
440
461
|
return std::make_tuple(
|
|
441
462
|
torch::empty({0, 3}, vert_options),
|
|
442
|
-
torch::empty({0, 3}, tri_options)
|
|
463
|
+
torch::empty({0, 3}, tri_options),
|
|
464
|
+
out_n
|
|
443
465
|
);
|
|
444
466
|
}
|
|
445
467
|
|
|
@@ -463,7 +485,15 @@ namespace mc
|
|
|
463
485
|
torch::Tensor out_vertices = torch::empty({out_num_vertices, 3}, vert_options);
|
|
464
486
|
float3* __restrict__ p_out_vertices = (float3*)out_vertices.data_ptr<float>();
|
|
465
487
|
|
|
466
|
-
|
|
488
|
+
std::optional<torch::Tensor> out_normals_opt = std::nullopt;
|
|
489
|
+
float3* __restrict__ p_out_normals = nullptr;
|
|
490
|
+
if (grid_normals != nullptr) {
|
|
491
|
+
torch::Tensor out_normals = torch::empty({out_num_vertices, 3}, vert_options);
|
|
492
|
+
p_out_normals = (float3*)out_normals.data_ptr<float>();
|
|
493
|
+
out_normals_opt = out_normals;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
interpolate_vertices(out_num_vertices, unique_edges, grid_vertices, voxel_values, grid_normals, iso, p_out_vertices, p_out_normals);
|
|
467
497
|
|
|
468
498
|
uint32_t out_num_triangles;
|
|
469
499
|
uint32_t *__restrict__ voxel_triangle_prefix_sums;
|
|
@@ -484,6 +514,6 @@ namespace mc
|
|
|
484
514
|
CHECK_CUDA_INTERNAL(cudaFree(voxel_edge_to_vert_idx));
|
|
485
515
|
CHECK_CUDA_INTERNAL(cudaFree(voxel_triangle_prefix_sums));
|
|
486
516
|
|
|
487
|
-
return std::make_tuple(out_vertices, out_triangles);
|
|
517
|
+
return std::make_tuple(out_vertices, out_triangles, out_normals_opt);
|
|
488
518
|
}
|
|
489
519
|
}
|
|
@@ -7,14 +7,15 @@
|
|
|
7
7
|
#include "../constants.h"
|
|
8
8
|
#include "../primitive/edge.h"
|
|
9
9
|
|
|
10
|
-
#include <
|
|
10
|
+
#include <optional>
|
|
11
11
|
|
|
12
12
|
namespace mc{
|
|
13
|
-
std::tuple<torch::Tensor, torch::Tensor
|
|
13
|
+
std::tuple<torch::Tensor, torch::Tensor, std::optional<torch::Tensor>> marching_cubes(
|
|
14
14
|
const uint32_t num_voxels,
|
|
15
15
|
const float3* __restrict__ grid_vertices,
|
|
16
16
|
const uint32_t* __restrict__ voxels,
|
|
17
17
|
const float* __restrict__ voxel_values,
|
|
18
|
+
const float3* __restrict__ grid_normals,
|
|
18
19
|
const float iso,
|
|
19
20
|
torch::TensorOptions vert_options,
|
|
20
21
|
torch::TensorOptions tri_options
|
|
@@ -17,6 +17,7 @@ void bind_ds_grid(py::module_& m);
|
|
|
17
17
|
void bind_creation_triangle_creation(py::module_& m);
|
|
18
18
|
|
|
19
19
|
void bind_ops_mc(py::module_& m);
|
|
20
|
+
void bind_ops_chamfer(py::module_& m);
|
|
20
21
|
|
|
21
22
|
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
|
|
22
23
|
m.doc() = "Geocutool Python bindings";
|
|
@@ -35,4 +36,5 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
|
|
|
35
36
|
bind_creation_triangle_creation(m);
|
|
36
37
|
|
|
37
38
|
bind_ops_mc(m);
|
|
39
|
+
bind_ops_chamfer(m);
|
|
38
40
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from .marching_cubes import marching_cubes
|
|
2
|
+
from .grid import create_voxel_grid, compute_grid_normal
|
|
3
|
+
from .distance import one_sided_chamfer_distance, chamfer_distance
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"marching_cubes",
|
|
7
|
+
"create_voxel_grid",
|
|
8
|
+
"compute_grid_normal",
|
|
9
|
+
"one_sided_chamfer_distance",
|
|
10
|
+
"chamfer_distance"
|
|
11
|
+
]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
import conquer3d._C as _C
|
|
3
|
+
|
|
4
|
+
def one_sided_chamfer_distance(query_points: torch.Tensor, reference_points: torch.Tensor, squared: bool = True):
|
|
5
|
+
assert query_points.is_cuda and reference_points.is_cuda, "Points must be on CUDA"
|
|
6
|
+
assert query_points.dtype == torch.float32 and reference_points.dtype == torch.float32, "Points must be float32"
|
|
7
|
+
assert query_points.shape[1] == 3 and reference_points.shape[1] == 3, "Points must be 3D"
|
|
8
|
+
|
|
9
|
+
query_points_c = query_points.contiguous()
|
|
10
|
+
reference_points_c = reference_points.contiguous()
|
|
11
|
+
|
|
12
|
+
distances, indices = _C.one_sided_chamfer_distance(query_points_c, reference_points_c)
|
|
13
|
+
|
|
14
|
+
if not squared:
|
|
15
|
+
# clamp to avoid NaN from floating point inaccuracies
|
|
16
|
+
distances = torch.sqrt(torch.clamp(distances, min=1e-12))
|
|
17
|
+
|
|
18
|
+
return distances, indices
|
|
19
|
+
|
|
20
|
+
def chamfer_distance(x: torch.Tensor, y: torch.Tensor, squared: bool = True, return_indices: bool = False):
|
|
21
|
+
dist_x_to_y, idx_x_to_y = one_sided_chamfer_distance(x, y, squared=squared)
|
|
22
|
+
dist_y_to_x, idx_y_to_x = one_sided_chamfer_distance(y, x, squared=squared)
|
|
23
|
+
|
|
24
|
+
loss = dist_x_to_y.mean() + dist_y_to_x.mean()
|
|
25
|
+
|
|
26
|
+
if return_indices:
|
|
27
|
+
return loss, idx_x_to_y, idx_y_to_x
|
|
28
|
+
return loss
|
|
@@ -7,7 +7,7 @@ def create_voxel_grid(
|
|
|
7
7
|
grid_max: Union[List[float], Tuple[float, float, float]],
|
|
8
8
|
res: Union[List[int], Tuple[int, int, int]],
|
|
9
9
|
device: str = "cuda"
|
|
10
|
-
) -> Tuple[torch.Tensor, torch.Tensor]:
|
|
10
|
+
) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
|
11
11
|
"""
|
|
12
12
|
Creates a structured 3D voxel grid efficiently.
|
|
13
13
|
|
|
@@ -18,9 +18,30 @@ def create_voxel_grid(
|
|
|
18
18
|
device (str, optional): Target device for the tensors (e.g., "cuda" or "cpu"). Defaults to "cuda".
|
|
19
19
|
|
|
20
20
|
Returns:
|
|
21
|
-
Tuple[torch.Tensor, torch.Tensor]:
|
|
21
|
+
Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
|
22
22
|
- grid_vertices (torch.Tensor): A float32 tensor of shape (N, 3) containing all grid coordinates.
|
|
23
23
|
- voxels (torch.Tensor): An int32 tensor of shape (V, 8) containing corner indices
|
|
24
24
|
for each voxel, mapped identically to the Marching Cubes convention.
|
|
25
|
+
- idx_grids (torch.Tensor): An int64 tensor of shape (N, 3) containing the (i, j, k) 3D coordinate indices for each vertex.
|
|
25
26
|
"""
|
|
26
27
|
return _C.create_voxel_grid(list(grid_min), list(grid_max), list(res), device)
|
|
28
|
+
|
|
29
|
+
def compute_grid_normal(
|
|
30
|
+
sdf: torch.Tensor,
|
|
31
|
+
grid_vertices: torch.Tensor,
|
|
32
|
+
idx_grids: torch.Tensor,
|
|
33
|
+
res: Union[List[int], Tuple[int, int, int]]
|
|
34
|
+
) -> torch.Tensor:
|
|
35
|
+
"""
|
|
36
|
+
Computes smooth normals (gradients) for a voxel grid using central differences.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
sdf (torch.Tensor): A float32 tensor of shape (N,) containing the SDF values.
|
|
40
|
+
grid_vertices (torch.Tensor): A float32 tensor of shape (N, 3) containing the grid coordinates.
|
|
41
|
+
idx_grids (torch.Tensor): An int64 tensor of shape (N, 3) containing the (i, j, k) indices, returned by create_voxel_grid.
|
|
42
|
+
res (List[int] | Tuple[int, int, int]): The number of vertices along each axis (rx, ry, rz).
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
torch.Tensor: A float32 tensor of shape (N, 3) containing the normalized gradient vectors.
|
|
46
|
+
"""
|
|
47
|
+
return _C.compute_grid_normal(sdf.contiguous(), grid_vertices.contiguous(), idx_grids.contiguous(), list(res))
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import torch
|
|
2
|
-
from typing import Tuple
|
|
2
|
+
from typing import Tuple, Optional
|
|
3
3
|
|
|
4
4
|
# Explicitly import the compiled CMake target
|
|
5
5
|
from .._C import marching_cubes as marching_cubes_func
|
|
@@ -8,8 +8,9 @@ def marching_cubes(
|
|
|
8
8
|
grid_vertices: torch.Tensor,
|
|
9
9
|
voxels: torch.Tensor,
|
|
10
10
|
voxel_values: torch.Tensor,
|
|
11
|
+
grid_normals: Optional[torch.Tensor] = None,
|
|
11
12
|
iso: float = 0.0
|
|
12
|
-
) -> Tuple[torch.Tensor, torch.Tensor]:
|
|
13
|
+
) -> Tuple[torch.Tensor, torch.Tensor, Optional[torch.Tensor]]:
|
|
13
14
|
"""
|
|
14
15
|
Executes the Marching Cubes algorithm to extract an isosurface from a voxel grid.
|
|
15
16
|
|
|
@@ -17,12 +18,14 @@ def marching_cubes(
|
|
|
17
18
|
grid_vertices (torch.Tensor): (V, 3) tensor of global vertex positions.
|
|
18
19
|
voxels (torch.Tensor): (N, 8) tensor of voxel corner indices mapping to `grid_vertices`.
|
|
19
20
|
voxel_values (torch.Tensor): (V,) tensor of SDF/scalar values at each vertex.
|
|
21
|
+
grid_normals (torch.Tensor, optional): (V, 3) optional tensor of SDF normals at each vertex. Defaults to None.
|
|
20
22
|
iso (float, optional): The isosurface extraction threshold. Defaults to 0.0.
|
|
21
23
|
|
|
22
24
|
Returns:
|
|
23
|
-
Tuple[torch.Tensor, torch.Tensor]:
|
|
25
|
+
Tuple[torch.Tensor, torch.Tensor, Optional[torch.Tensor]]:
|
|
24
26
|
- vertices (torch.Tensor): (M, 3) tensor of extracted mesh vertices.
|
|
25
27
|
- triangles (torch.Tensor): (T, 3) tensor of extracted mesh triangle indices.
|
|
28
|
+
- normals (torch.Tensor, optional): (M, 3) tensor of extracted mesh vertex normals, if `grid_normals` was provided.
|
|
26
29
|
"""
|
|
27
30
|
if not all(t.is_cuda for t in [grid_vertices, voxels, voxel_values]):
|
|
28
31
|
raise ValueError("All input tensors must be CUDA tensors.")
|
|
@@ -30,13 +33,21 @@ def marching_cubes(
|
|
|
30
33
|
grid_vertices_c = grid_vertices.contiguous().to(torch.float32)
|
|
31
34
|
voxels_c = voxels.contiguous().to(torch.int32)
|
|
32
35
|
voxel_values_c = voxel_values.contiguous().to(torch.float32)
|
|
36
|
+
|
|
37
|
+
grid_normals_c = None
|
|
38
|
+
if grid_normals is not None:
|
|
39
|
+
if not grid_normals.is_cuda:
|
|
40
|
+
raise ValueError("grid_normals must be a CUDA tensor.")
|
|
41
|
+
grid_normals_c = grid_normals.contiguous().to(torch.float32)
|
|
42
|
+
|
|
33
43
|
iso_c = float(iso)
|
|
34
44
|
|
|
35
|
-
vertices, triangles = marching_cubes_func(
|
|
45
|
+
vertices, triangles, out_normals = marching_cubes_func(
|
|
36
46
|
grid_vertices_c,
|
|
37
47
|
voxels_c,
|
|
38
48
|
voxel_values_c,
|
|
49
|
+
grid_normals_c,
|
|
39
50
|
iso_c
|
|
40
51
|
)
|
|
41
52
|
|
|
42
|
-
return vertices, triangles
|
|
53
|
+
return vertices, triangles, out_normals
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: conquer3d
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: Geometric Cuda Tool Box
|
|
5
5
|
Author-email: Do Hoang Khoi <khoido8899@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -56,7 +56,7 @@ pip install torch==2.8.0 torchvision==0.23.0 torchaudio==2.8.0 --index-url https
|
|
|
56
56
|
pip install pybind11-stubgen
|
|
57
57
|
pip install git+https://github.com/KhoiDOO/geocutool.git --no-build-isolation
|
|
58
58
|
|
|
59
|
-
pip install plotly open3d jupyter trimesh
|
|
59
|
+
pip install plotly open3d jupyter trimesh point-cloud-utils
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
# Development
|
|
@@ -25,6 +25,7 @@ conquer3d/csrc/binds/data_structure/kdtree.cpp
|
|
|
25
25
|
conquer3d/csrc/binds/data_structure/mesh_bvh.cpp
|
|
26
26
|
conquer3d/csrc/binds/data_structure/pgs_bvh.cpp
|
|
27
27
|
conquer3d/csrc/binds/data_structure/triangle_mesh.cpp
|
|
28
|
+
conquer3d/csrc/binds/ops/chamfer.cpp
|
|
28
29
|
conquer3d/csrc/binds/ops/mc.cpp
|
|
29
30
|
conquer3d/csrc/binds/primitive/gs.cpp
|
|
30
31
|
conquer3d/csrc/binds/primitive/pgs.cpp
|
|
@@ -48,6 +49,8 @@ conquer3d/csrc/maths/f4x1.h
|
|
|
48
49
|
conquer3d/csrc/maths/f4x4.h
|
|
49
50
|
conquer3d/csrc/maths/maths.h
|
|
50
51
|
conquer3d/csrc/maths/ops.h
|
|
52
|
+
conquer3d/csrc/ops/chamfer.cu
|
|
53
|
+
conquer3d/csrc/ops/chamfer.h
|
|
51
54
|
conquer3d/csrc/ops/mc.cu
|
|
52
55
|
conquer3d/csrc/ops/mc.h
|
|
53
56
|
conquer3d/csrc/ops/mc_data.h
|
|
@@ -65,6 +68,7 @@ conquer3d/csrc/primitive/ray.h
|
|
|
65
68
|
conquer3d/csrc/primitive/triangles.h
|
|
66
69
|
conquer3d/data_structure/__init__.py
|
|
67
70
|
conquer3d/ops/__init__.py
|
|
71
|
+
conquer3d/ops/distance.py
|
|
68
72
|
conquer3d/ops/grid.py
|
|
69
73
|
conquer3d/ops/marching_cubes.py
|
|
70
74
|
conquer3d/primitive/__init__.py
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
#include <torch/extension.h>
|
|
2
|
-
#include <pybind11/pybind11.h>
|
|
3
|
-
#include <pybind11/stl.h>
|
|
4
|
-
#include <tuple>
|
|
5
|
-
#include <string>
|
|
6
|
-
#include <vector>
|
|
7
|
-
|
|
8
|
-
namespace py = pybind11;
|
|
9
|
-
|
|
10
|
-
std::tuple<torch::Tensor, torch::Tensor> create_voxel_grid(
|
|
11
|
-
std::vector<float> grid_min,
|
|
12
|
-
std::vector<float> grid_max,
|
|
13
|
-
std::vector<int64_t> res,
|
|
14
|
-
std::string device_str
|
|
15
|
-
) {
|
|
16
|
-
TORCH_CHECK(grid_min.size() == 3, "grid_min must have 3 elements.");
|
|
17
|
-
TORCH_CHECK(grid_max.size() == 3, "grid_max must have 3 elements.");
|
|
18
|
-
TORCH_CHECK(res.size() == 3, "res must have 3 elements.");
|
|
19
|
-
|
|
20
|
-
c10::Device device(device_str);
|
|
21
|
-
auto options = torch::TensorOptions().device(device).dtype(torch::kFloat32);
|
|
22
|
-
|
|
23
|
-
int64_t rx = res[0];
|
|
24
|
-
int64_t ry = res[1];
|
|
25
|
-
int64_t rz = res[2];
|
|
26
|
-
|
|
27
|
-
auto x = torch::linspace(grid_min[0], grid_max[0], rx, options);
|
|
28
|
-
auto y = torch::linspace(grid_min[1], grid_max[1], ry, options);
|
|
29
|
-
auto z = torch::linspace(grid_min[2], grid_max[2], rz, options);
|
|
30
|
-
|
|
31
|
-
auto grids = torch::meshgrid({x, y, z}, "ij");
|
|
32
|
-
auto grid_x = grids[0].flatten();
|
|
33
|
-
auto grid_y = grids[1].flatten();
|
|
34
|
-
auto grid_z = grids[2].flatten();
|
|
35
|
-
|
|
36
|
-
auto grid_vertices = torch::stack({grid_x, grid_y, grid_z}, 1).contiguous();
|
|
37
|
-
|
|
38
|
-
auto options_int = options.dtype(torch::kInt64);
|
|
39
|
-
auto i = torch::arange(rx - 1, options_int);
|
|
40
|
-
auto j = torch::arange(ry - 1, options_int);
|
|
41
|
-
auto k = torch::arange(rz - 1, options_int);
|
|
42
|
-
|
|
43
|
-
auto idx_grids = torch::meshgrid({i, j, k}, "ij");
|
|
44
|
-
auto vi = idx_grids[0];
|
|
45
|
-
auto vj = idx_grids[1];
|
|
46
|
-
auto vk = idx_grids[2];
|
|
47
|
-
|
|
48
|
-
// Voxel connectivity indexing mapping matching mc.cu
|
|
49
|
-
auto v0 = vi * ry * rz + vj * rz + vk;
|
|
50
|
-
auto v1 = (vi + 1) * ry * rz + vj * rz + vk;
|
|
51
|
-
auto v2 = (vi + 1) * ry * rz + (vj + 1) * rz + vk;
|
|
52
|
-
auto v3 = vi * ry * rz + (vj + 1) * rz + vk;
|
|
53
|
-
auto v4 = vi * ry * rz + vj * rz + (vk + 1);
|
|
54
|
-
auto v5 = (vi + 1) * ry * rz + vj * rz + (vk + 1);
|
|
55
|
-
auto v6 = (vi + 1) * ry * rz + (vj + 1) * rz + (vk + 1);
|
|
56
|
-
auto v7 = vi * ry * rz + (vj + 1) * rz + (vk + 1);
|
|
57
|
-
|
|
58
|
-
auto voxels = torch::stack({v0, v1, v2, v3, v4, v5, v6, v7}, -1).view({-1, 8}).contiguous().to(torch::kInt32);
|
|
59
|
-
|
|
60
|
-
return std::make_tuple(grid_vertices, voxels);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
void bind_ds_grid(py::module_& m) {
|
|
64
|
-
m.def("create_voxel_grid", &create_voxel_grid, "Creates a structured 3D voxel grid.",
|
|
65
|
-
py::arg("grid_min"), py::arg("grid_max"), py::arg("res"), py::arg("device_str") = "cuda");
|
|
66
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|