conquer3d 0.2.9__tar.gz → 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. {conquer3d-0.2.9/conquer3d.egg-info → conquer3d-0.3.1}/PKG-INFO +8 -2
  2. {conquer3d-0.2.9 → conquer3d-0.3.1}/README.md +6 -1
  3. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/_C.so +0 -0
  4. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/binds/data_structure/grid.cpp +20 -0
  5. conquer3d-0.3.1/conquer3d/csrc/binds/ops/mc.cpp +118 -0
  6. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/ops/mc.cu +152 -8
  7. conquer3d-0.3.1/conquer3d/csrc/ops/mc.h +39 -0
  8. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/primitive/aabb.h +15 -0
  9. conquer3d-0.3.1/conquer3d/data/collate/__init__.py +0 -0
  10. conquer3d-0.3.1/conquer3d/data/collate/sparse_tensor.py +43 -0
  11. conquer3d-0.3.1/conquer3d/data/dataset/__init__.py +0 -0
  12. conquer3d-0.3.1/conquer3d/data/dataset/base_mesh.py +17 -0
  13. conquer3d-0.3.1/conquer3d/data/dataset/digit3d.py +136 -0
  14. conquer3d-0.3.1/conquer3d/data/transform/__init__.py +0 -0
  15. conquer3d-0.3.1/conquer3d/data_structure/__init__.py +29 -0
  16. conquer3d-0.3.1/conquer3d/data_structure/grid.py +195 -0
  17. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/ops/__init__.py +2 -3
  18. conquer3d-0.3.1/conquer3d/ops/diff_marching_cubes.py +135 -0
  19. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/ops/marching_cubes.py +16 -5
  20. conquer3d-0.3.1/conquer3d/primitive/__init__.py +0 -0
  21. {conquer3d-0.2.9 → conquer3d-0.3.1/conquer3d.egg-info}/PKG-INFO +8 -2
  22. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d.egg-info/SOURCES.txt +9 -1
  23. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d.egg-info/requires.txt +1 -0
  24. {conquer3d-0.2.9 → conquer3d-0.3.1}/pyproject.toml +2 -1
  25. conquer3d-0.2.9/conquer3d/csrc/binds/ops/mc.cpp +0 -47
  26. conquer3d-0.2.9/conquer3d/csrc/ops/mc.h +0 -25
  27. conquer3d-0.2.9/conquer3d/data_structure/__init__.py +0 -13
  28. conquer3d-0.2.9/conquer3d/ops/grid.py +0 -47
  29. {conquer3d-0.2.9 → conquer3d-0.3.1}/LICENSE +0 -0
  30. {conquer3d-0.2.9 → conquer3d-0.3.1}/MANIFEST.in +0 -0
  31. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/_C.pyi +0 -0
  32. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/__init__.py +0 -0
  33. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/creation/__init__.py +0 -0
  34. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/creation/triangle_creation.py +0 -0
  35. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/binds/creation/triangle_creation.cpp +0 -0
  36. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/binds/data_structure/bvh.cpp +0 -0
  37. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/binds/data_structure/gs_bvh.cpp +0 -0
  38. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/binds/data_structure/kdtree.cpp +0 -0
  39. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/binds/data_structure/mesh_bvh.cpp +0 -0
  40. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/binds/data_structure/pgs_bvh.cpp +0 -0
  41. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/binds/data_structure/triangle_mesh.cpp +0 -0
  42. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/binds/ops/chamfer.cpp +0 -0
  43. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/binds/primitive/gs.cpp +0 -0
  44. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/binds/primitive/pgs.cpp +0 -0
  45. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/check.h +0 -0
  46. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/constants.h +0 -0
  47. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/creation/triangle_creation.h +0 -0
  48. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/data_structure/bvh.cu +0 -0
  49. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/data_structure/bvh.h +0 -0
  50. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/data_structure/gs_bvh.h +0 -0
  51. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/data_structure/kdtree.cu +0 -0
  52. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/data_structure/kdtree.h +0 -0
  53. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/data_structure/mesh_bvh.cu +0 -0
  54. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/data_structure/mesh_bvh.h +0 -0
  55. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/data_structure/pgs_bvh.h +0 -0
  56. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/data_structure/triangle_mesh.cu +0 -0
  57. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/data_structure/triangle_mesh.h +0 -0
  58. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/data_structure/zcurve.h +0 -0
  59. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/maths/f2x2.h +0 -0
  60. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/maths/f3x1.h +0 -0
  61. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/maths/f3x3.h +0 -0
  62. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/maths/f3x4.h +0 -0
  63. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/maths/f4x1.h +0 -0
  64. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/maths/f4x4.h +0 -0
  65. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/maths/maths.h +0 -0
  66. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/maths/ops.h +0 -0
  67. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/ops/chamfer.cu +0 -0
  68. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/ops/chamfer.h +0 -0
  69. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/ops/mc_data.h +0 -0
  70. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/primitive/edge.h +0 -0
  71. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/primitive/gs.cu +0 -0
  72. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/primitive/gs.h +0 -0
  73. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/primitive/gs_aabb.cu +0 -0
  74. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/primitive/gs_math.cuh +0 -0
  75. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/primitive/pgs.cu +0 -0
  76. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/primitive/pgs.h +0 -0
  77. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/primitive/pgs_aabb.cu +0 -0
  78. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/primitive/pgs_math.cuh +0 -0
  79. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/primitive/ray.h +0 -0
  80. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/primitive/triangles.h +0 -0
  81. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/csrc/pybind.cpp +0 -0
  82. {conquer3d-0.2.9/conquer3d/primitive → conquer3d-0.3.1/conquer3d/data}/__init__.py +0 -0
  83. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/ops/distance.py +0 -0
  84. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/primitive/gs.py +0 -0
  85. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d/primitive/pgs.py +0 -0
  86. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d.egg-info/dependency_links.txt +0 -0
  87. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d.egg-info/not-zip-safe +0 -0
  88. {conquer3d-0.2.9 → conquer3d-0.3.1}/conquer3d.egg-info/top_level.txt +0 -0
  89. {conquer3d-0.2.9 → conquer3d-0.3.1}/setup.cfg +0 -0
  90. {conquer3d-0.2.9 → conquer3d-0.3.1}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conquer3d
3
- Version: 0.2.9
3
+ Version: 0.3.1
4
4
  Summary: Geometric Cuda Tool Box
5
5
  Author-email: Do Hoang Khoi <khoido8899@gmail.com>
6
6
  License-Expression: MIT
@@ -13,6 +13,7 @@ Requires-Python: >=3.9
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
15
  Requires-Dist: torch>=2.0.0
16
+ Requires-Dist: gdown
16
17
  Provides-Extra: cuda
17
18
  Requires-Dist: cuda-toolkit==12.8.2; extra == "cuda"
18
19
  Provides-Extra: dev
@@ -51,12 +52,17 @@ conda activate geocutool
51
52
 
52
53
  conda install nvidia::cuda-toolkit==12.8.2 -y
53
54
 
55
+ pip install setuptools wheel ninja
54
56
  pip install torch==2.8.0 torchvision==0.23.0 torchaudio==2.8.0 --index-url https://download.pytorch.org/whl/cu128
55
57
 
58
+ pip install git+https://github.com/mit-han-lab/torchsparse.git
59
+
60
+ pip install kaolin==0.18.0 -f https://nvidia-kaolin.s3.us-east-2.amazonaws.com/torch-2.8.0_cu128.html
61
+
56
62
  pip install pybind11-stubgen
57
63
  pip install git+https://github.com/KhoiDOO/geocutool.git --no-build-isolation
58
64
 
59
- pip install plotly open3d jupyter trimesh point-cloud-utils
65
+ pip install plotly open3d jupyter trimesh point-cloud-utils meshlib
60
66
  ```
61
67
 
62
68
  # Development
@@ -23,12 +23,17 @@ conda activate geocutool
23
23
 
24
24
  conda install nvidia::cuda-toolkit==12.8.2 -y
25
25
 
26
+ pip install setuptools wheel ninja
26
27
  pip install torch==2.8.0 torchvision==0.23.0 torchaudio==2.8.0 --index-url https://download.pytorch.org/whl/cu128
27
28
 
29
+ pip install git+https://github.com/mit-han-lab/torchsparse.git
30
+
31
+ pip install kaolin==0.18.0 -f https://nvidia-kaolin.s3.us-east-2.amazonaws.com/torch-2.8.0_cu128.html
32
+
28
33
  pip install pybind11-stubgen
29
34
  pip install git+https://github.com/KhoiDOO/geocutool.git --no-build-isolation
30
35
 
31
- pip install plotly open3d jupyter trimesh point-cloud-utils
36
+ pip install plotly open3d jupyter trimesh point-cloud-utils meshlib
32
37
  ```
33
38
 
34
39
  # Development
@@ -121,9 +121,29 @@ torch::Tensor compute_grid_normal(torch::Tensor sdf, torch::Tensor grid_vertices
121
121
  return torch::nn::functional::normalize(normals, torch::nn::functional::NormalizeFuncOptions().p(2).dim(1));
122
122
  }
123
123
 
124
+ torch::Tensor compute_active_voxels(torch::Tensor voxels, torch::Tensor sdf, float iso) {
125
+ TORCH_CHECK(voxels.device() == sdf.device(), "voxels and sdf must be on the same device.");
126
+ TORCH_CHECK(voxels.dtype() == torch::kInt32, "voxels must be int32.");
127
+ TORCH_CHECK(sdf.dtype() == torch::kFloat32, "sdf must be float32.");
128
+
129
+ auto voxels_flat = voxels.flatten().to(torch::kInt64);
130
+ auto voxel_sdfs = sdf.index_select(0, voxels_flat).view({-1, 8});
131
+
132
+ auto below_iso = voxel_sdfs < iso;
133
+ auto any_below = below_iso.any(1);
134
+ auto any_above = (~below_iso).any(1);
135
+
136
+ auto active_mask = any_below & any_above;
137
+ auto active_indices = torch::nonzero(active_mask).squeeze(1);
138
+
139
+ return active_indices;
140
+ }
141
+
124
142
  void bind_ds_grid(py::module_& m) {
125
143
  m.def("create_voxel_grid", &create_voxel_grid, "Creates a structured 3D voxel grid.",
126
144
  py::arg("grid_min"), py::arg("grid_max"), py::arg("res"), py::arg("device_str") = "cuda");
127
145
  m.def("compute_grid_normal", &compute_grid_normal, "Computes surface normals for a grid.",
128
146
  py::arg("sdf"), py::arg("grid_vertices"), py::arg("idx_grids"), py::arg("res"));
147
+ m.def("compute_active_voxels", &compute_active_voxels, "Computes active voxels intersecting the surface",
148
+ py::arg("voxels"), py::arg("sdf"), py::arg("iso"));
129
149
  }
@@ -0,0 +1,118 @@
1
+ #include <torch/extension.h>
2
+ #include <pybind11/pybind11.h>
3
+ #include "../../ops/mc.h"
4
+ #include "../../check.h"
5
+
6
+ namespace py = pybind11;
7
+
8
+ std::tuple<torch::Tensor, torch::Tensor, std::optional<torch::Tensor>, std::optional<torch::Tensor>, std::optional<torch::Tensor>> marching_cubes_wrapper(
9
+ torch::Tensor grid_vertices,
10
+ torch::Tensor voxels,
11
+ torch::Tensor voxel_values,
12
+ std::optional<torch::Tensor> grid_normals,
13
+ std::optional<torch::Tensor> grid_colors,
14
+ float iso,
15
+ bool return_unique_edges
16
+ ) {
17
+ CHECK_INPUT(grid_vertices);
18
+ CHECK_INPUT(voxels);
19
+ CHECK_INPUT(voxel_values);
20
+
21
+ uint32_t num_voxels = voxels.size(0);
22
+
23
+ const float3* __restrict__ p_grid_vertices = (float3*)grid_vertices.data_ptr<float>();
24
+ const uint32_t* __restrict__ p_voxels = (uint32_t*)voxels.data_ptr<int32_t>();
25
+ const float* __restrict__ p_voxel_values = voxel_values.data_ptr<float>();
26
+
27
+ const float3* __restrict__ p_grid_normals = nullptr;
28
+ if (grid_normals.has_value()) {
29
+ CHECK_INPUT(grid_normals.value());
30
+ p_grid_normals = (float3*)grid_normals.value().data_ptr<float>();
31
+ }
32
+
33
+ const float3* __restrict__ p_grid_colors = nullptr;
34
+ if (grid_colors.has_value()) {
35
+ CHECK_INPUT(grid_colors.value());
36
+ p_grid_colors = (float3*)grid_colors.value().data_ptr<float>();
37
+ }
38
+
39
+ return mc::marching_cubes(
40
+ num_voxels,
41
+ p_grid_vertices,
42
+ p_voxels,
43
+ p_voxel_values,
44
+ p_grid_normals,
45
+ p_grid_colors,
46
+ iso,
47
+ grid_vertices.options(),
48
+ voxels.options(),
49
+ return_unique_edges
50
+ );
51
+ }
52
+
53
+ void marching_cubes_backward_wrapper(
54
+ torch::Tensor unique_edges,
55
+ torch::Tensor grid_vertices,
56
+ std::optional<torch::Tensor> grid_colors,
57
+ torch::Tensor values,
58
+ torch::Tensor adj_verts,
59
+ std::optional<torch::Tensor> adj_colors,
60
+ torch::Tensor adj_values,
61
+ std::optional<torch::Tensor> adj_grid_colors,
62
+ float iso
63
+ ) {
64
+ CHECK_INPUT(unique_edges);
65
+ CHECK_INPUT(grid_vertices);
66
+ CHECK_INPUT(values);
67
+ CHECK_INPUT(adj_verts);
68
+ CHECK_INPUT(adj_values);
69
+
70
+ uint32_t n_verts = unique_edges.size(0);
71
+
72
+ const Edge* p_unique_edges = (const Edge*)unique_edges.data_ptr<int32_t>();
73
+ const float3* p_grid_vertices = (const float3*)grid_vertices.data_ptr<float>();
74
+ const float* p_values = values.data_ptr<float>();
75
+ const float3* p_adj_verts = (const float3*)adj_verts.data_ptr<float>();
76
+ float* p_adj_values = adj_values.data_ptr<float>();
77
+
78
+ const float3* p_grid_colors = nullptr;
79
+ if (grid_colors.has_value()) {
80
+ CHECK_INPUT(grid_colors.value());
81
+ p_grid_colors = (const float3*)grid_colors.value().data_ptr<float>();
82
+ }
83
+
84
+ const float3* p_adj_colors = nullptr;
85
+ if (adj_colors.has_value()) {
86
+ CHECK_INPUT(adj_colors.value());
87
+ p_adj_colors = (const float3*)adj_colors.value().data_ptr<float>();
88
+ }
89
+
90
+ float3* p_adj_grid_colors = nullptr;
91
+ if (adj_grid_colors.has_value()) {
92
+ CHECK_INPUT(adj_grid_colors.value());
93
+ p_adj_grid_colors = (float3*)adj_grid_colors.value().data_ptr<float>();
94
+ }
95
+
96
+ mc::backward(
97
+ n_verts,
98
+ p_unique_edges,
99
+ p_grid_vertices,
100
+ p_grid_colors,
101
+ p_values,
102
+ p_adj_verts,
103
+ p_adj_colors,
104
+ p_adj_values,
105
+ p_adj_grid_colors,
106
+ iso
107
+ );
108
+ }
109
+
110
+ void bind_ops_mc(py::module_& m) {
111
+ m.def("marching_cubes", &marching_cubes_wrapper, "Marching Cubes",
112
+ py::arg("grid_vertices"), py::arg("voxels"), py::arg("voxel_values"),
113
+ py::arg("grid_normals") = std::nullopt, py::arg("grid_colors") = std::nullopt, py::arg("iso") = 0.0f, py::arg("return_unique_edges") = false);
114
+
115
+ m.def("marching_cubes_backward", &marching_cubes_backward_wrapper, "Marching Cubes Backward",
116
+ py::arg("unique_edges"), py::arg("grid_vertices"), py::arg("grid_colors"), py::arg("values"),
117
+ py::arg("adj_verts"), py::arg("adj_colors"), py::arg("adj_values"), py::arg("adj_grid_colors"), py::arg("iso"));
118
+ }
@@ -176,9 +176,11 @@ namespace mc
176
176
  const float3* grid_vertices,
177
177
  const float* values,
178
178
  const float3* grid_normals,
179
+ const float3* grid_colors,
179
180
  const float iso,
180
181
  float3* out_verts,
181
- float3* out_normals
182
+ float3* out_normals,
183
+ float3* out_colors
182
184
  )
183
185
  {
184
186
  uint32_t v_idx = blockIdx.x * blockDim.x + threadIdx.x;
@@ -199,24 +201,31 @@ namespace mc
199
201
  // 3. Interpolate (Differentiable formula)
200
202
  float3 p;
201
203
  float3 n;
204
+ float3 c;
202
205
  bool has_normals = grid_normals != nullptr;
206
+ bool has_colors = grid_colors != nullptr;
203
207
  float3 n0 = has_normals ? grid_normals[v0_idx] : make_float3(0, 0, 0);
204
208
  float3 n1 = has_normals ? grid_normals[v1_idx] : make_float3(0, 0, 0);
209
+ float3 c0 = has_colors ? grid_colors[v0_idx] : make_float3(0, 0, 0);
210
+ float3 c1 = has_colors ? grid_colors[v1_idx] : make_float3(0, 0, 0);
205
211
 
206
212
  if (fabsf(iso - val0) < EPS)
207
213
  {
208
214
  p = p0;
209
215
  if (has_normals) n = n0;
216
+ if (has_colors) c = c0;
210
217
  }
211
218
  else if (fabsf(iso - val1) < EPS)
212
219
  {
213
220
  p = p1;
214
221
  if (has_normals) n = n1;
222
+ if (has_colors) c = c1;
215
223
  }
216
224
  else if (fabsf(val0 - val1) < EPS)
217
225
  {
218
226
  p = p0;
219
227
  if (has_normals) n = n0;
228
+ if (has_colors) c = c0;
220
229
  }
221
230
  else
222
231
  {
@@ -228,12 +237,18 @@ namespace mc
228
237
  n = n0 + (n1 - n0) * t;
229
238
  n = maths::normalize(n);
230
239
  }
240
+ if (has_colors) {
241
+ c = c0 + (c1 - c0) * t;
242
+ }
231
243
  }
232
244
 
233
245
  out_verts[v_idx] = p;
234
246
  if (has_normals) {
235
247
  out_normals[v_idx] = n;
236
248
  }
249
+ if (has_colors) {
250
+ out_colors[v_idx] = c;
251
+ }
237
252
  }
238
253
 
239
254
  void compute_active_voxels(
@@ -357,16 +372,18 @@ namespace mc
357
372
  const float3* grid_vertices,
358
373
  const float* values,
359
374
  const float3* grid_normals,
375
+ const float3* grid_colors,
360
376
  const float iso,
361
377
  float3* out_verts,
362
- float3* out_normals
378
+ float3* out_normals,
379
+ float3* out_colors
363
380
  )
364
381
  {
365
382
  if (num_unique_edges == 0) return;
366
383
  int block_size = NTHREADS;
367
384
  int grid_size = (num_unique_edges + block_size - 1) / block_size;
368
385
  interpolate_vertices_kernel<<<grid_size, block_size>>>(
369
- num_unique_edges, unique_edges, grid_vertices, values, grid_normals, iso, out_verts, out_normals);
386
+ num_unique_edges, unique_edges, grid_vertices, values, grid_normals, grid_colors, iso, out_verts, out_normals, out_colors);
370
387
  }
371
388
 
372
389
  void compute_number_triangles(
@@ -435,15 +452,17 @@ namespace mc
435
452
  num_active_voxels, used_voxel_codes, voxel_edge_to_vert_idx, voxel_triangle_prefix_sums, out_triangles);
436
453
  }
437
454
 
438
- std::tuple<torch::Tensor, torch::Tensor, std::optional<torch::Tensor>> marching_cubes(
455
+ std::tuple<torch::Tensor, torch::Tensor, std::optional<torch::Tensor>, std::optional<torch::Tensor>, std::optional<torch::Tensor>> marching_cubes(
439
456
  const uint32_t num_voxels,
440
457
  const float3* __restrict__ grid_vertices,
441
458
  const uint32_t* __restrict__ voxels,
442
459
  const float* __restrict__ voxel_values,
443
460
  const float3* __restrict__ grid_normals,
461
+ const float3* __restrict__ grid_colors,
444
462
  const float iso,
445
463
  torch::TensorOptions vert_options,
446
- torch::TensorOptions tri_options
464
+ torch::TensorOptions tri_options,
465
+ bool return_unique_edges
447
466
  )
448
467
  {
449
468
  uint8_t *__restrict__ voxel_codes;
@@ -457,11 +476,15 @@ namespace mc
457
476
  if (num_active_voxels == 0) {
458
477
  CHECK_CUDA_INTERNAL(cudaFree(voxel_codes));
459
478
  std::optional<torch::Tensor> out_n = std::nullopt;
479
+ std::optional<torch::Tensor> out_c = std::nullopt;
460
480
  if (grid_normals != nullptr) out_n = torch::empty({0, 3}, vert_options);
481
+ if (grid_colors != nullptr) out_c = torch::empty({0, 3}, vert_options);
461
482
  return std::make_tuple(
462
483
  torch::empty({0, 3}, vert_options),
463
484
  torch::empty({0, 3}, tri_options),
464
- out_n
485
+ out_n,
486
+ out_c,
487
+ std::nullopt
465
488
  );
466
489
  }
467
490
 
@@ -493,7 +516,15 @@ namespace mc
493
516
  out_normals_opt = out_normals;
494
517
  }
495
518
 
496
- interpolate_vertices(out_num_vertices, unique_edges, grid_vertices, voxel_values, grid_normals, iso, p_out_vertices, p_out_normals);
519
+ std::optional<torch::Tensor> out_colors_opt = std::nullopt;
520
+ float3* __restrict__ p_out_colors = nullptr;
521
+ if (grid_colors != nullptr) {
522
+ torch::Tensor out_colors = torch::empty({out_num_vertices, 3}, vert_options);
523
+ p_out_colors = (float3*)out_colors.data_ptr<float>();
524
+ out_colors_opt = out_colors;
525
+ }
526
+
527
+ interpolate_vertices(out_num_vertices, unique_edges, grid_vertices, voxel_values, grid_normals, grid_colors, iso, p_out_vertices, p_out_normals, p_out_colors);
497
528
 
498
529
  uint32_t out_num_triangles;
499
530
  uint32_t *__restrict__ voxel_triangle_prefix_sums;
@@ -505,6 +536,13 @@ namespace mc
505
536
 
506
537
  assemble_triangles(num_active_voxels, used_voxel_codes, voxel_edge_to_vert_idx, voxel_triangle_prefix_sums, p_out_triangles);
507
538
 
539
+ std::optional<torch::Tensor> out_unique_edges_opt = std::nullopt;
540
+ if (return_unique_edges) {
541
+ torch::Tensor out_unique_edges = torch::empty({out_num_vertices, 2}, torch::dtype(torch::kInt32).device(vert_options.device()));
542
+ CHECK_CUDA_INTERNAL(cudaMemcpy(out_unique_edges.data_ptr(), unique_edges, out_num_vertices * sizeof(Edge), cudaMemcpyDeviceToDevice));
543
+ out_unique_edges_opt = out_unique_edges;
544
+ }
545
+
508
546
  // Cleanup
509
547
  CHECK_CUDA_INTERNAL(cudaFree(voxel_codes));
510
548
  CHECK_CUDA_INTERNAL(cudaFree(used_voxel_index));
@@ -514,6 +552,112 @@ namespace mc
514
552
  CHECK_CUDA_INTERNAL(cudaFree(voxel_edge_to_vert_idx));
515
553
  CHECK_CUDA_INTERNAL(cudaFree(voxel_triangle_prefix_sums));
516
554
 
517
- return std::make_tuple(out_vertices, out_triangles, out_normals_opt);
555
+ return std::make_tuple(out_vertices, out_triangles, out_normals_opt, out_colors_opt, out_unique_edges_opt);
556
+ }
557
+
558
+ __global__ void backward_dmc_kernel(
559
+ const uint32_t n_verts,
560
+ const Edge *unique_edges,
561
+ const float *grid_values,
562
+ const float3 *grid_coords,
563
+ const float3 *grid_colors,
564
+ const float3 *adj_verts,
565
+ const float3 *adj_colors,
566
+ const float iso,
567
+ float *adj_values,
568
+ float3 *adj_grid_colors,
569
+ bool with_colors)
570
+ {
571
+ uint32_t v_idx = blockIdx.x * blockDim.x + threadIdx.x;
572
+ if (v_idx >= n_verts)
573
+ return;
574
+
575
+ Edge edge_sig = unique_edges[v_idx];
576
+ uint32_t v0_idx = edge_sig.v0;
577
+ uint32_t v1_idx = edge_sig.v1;
578
+
579
+ float v0_val = grid_values[v0_idx];
580
+ float v1_val = grid_values[v1_idx];
581
+ float3 p0 = grid_coords[v0_idx];
582
+ float3 p1 = grid_coords[v1_idx];
583
+
584
+ float3 grad_p_out = adj_verts[v_idx];
585
+
586
+ float3 c0, c1, grad_c_out;
587
+ if (with_colors)
588
+ {
589
+ c0 = grid_colors[v0_idx];
590
+ c1 = grid_colors[v1_idx];
591
+ grad_c_out = adj_colors[v_idx];
592
+ }
593
+
594
+ float diff = v1_val - v0_val;
595
+
596
+ if (with_colors)
597
+ {
598
+ float t = 0.5f;
599
+ if (fabsf(iso - v0_val) < EPS)
600
+ t = 0.0f;
601
+ else if (fabsf(iso - v1_val) < EPS)
602
+ t = 1.0f;
603
+ else if (fabsf(diff) >= EPS)
604
+ {
605
+ t = fmaxf(0.0f, fminf(1.0f, (iso - v0_val) / diff));
606
+ }
607
+
608
+ float t0 = 1.0f - t;
609
+ float t1 = t;
610
+
611
+ atomicAdd(&(adj_grid_colors[v0_idx].x), grad_c_out.x * t0);
612
+ atomicAdd(&(adj_grid_colors[v0_idx].y), grad_c_out.y * t0);
613
+ atomicAdd(&(adj_grid_colors[v0_idx].z), grad_c_out.z * t0);
614
+
615
+ atomicAdd(&(adj_grid_colors[v1_idx].x), grad_c_out.x * t1);
616
+ atomicAdd(&(adj_grid_colors[v1_idx].y), grad_c_out.y * t1);
617
+ atomicAdd(&(adj_grid_colors[v1_idx].z), grad_c_out.z * t1);
618
+ }
619
+
620
+ if (diff * diff < 1e-14f)
621
+ return;
622
+
623
+ float dot_prod = (p1.x - p0.x) * grad_p_out.x + (p1.y - p0.y) * grad_p_out.y + (p1.z - p0.z) * grad_p_out.z;
624
+ float common = dot_prod / (diff * diff);
625
+ float grad_v0 = common * (iso - v1_val);
626
+ float grad_v1 = common * (v0_val - iso);
627
+
628
+ atomicAdd(&adj_values[v0_idx], grad_v0);
629
+ atomicAdd(&adj_values[v1_idx], grad_v1);
630
+ }
631
+
632
+ void backward(
633
+ const uint32_t n_verts,
634
+ const Edge *unique_edges,
635
+ const float3 *grid_vertices,
636
+ const float3 *grid_colors,
637
+ const float *values,
638
+ const float3 *adj_verts,
639
+ const float3 *adj_colors,
640
+ float *adj_values,
641
+ float3 *adj_grid_colors,
642
+ const float iso)
643
+ {
644
+ if (n_verts == 0) return;
645
+
646
+ bool with_colors = (grid_colors != nullptr && adj_colors != nullptr && adj_grid_colors != nullptr);
647
+ int block_size = NTHREADS;
648
+ int grid_size = (n_verts + block_size - 1) / block_size;
649
+
650
+ backward_dmc_kernel<<<grid_size, block_size>>>(
651
+ n_verts,
652
+ unique_edges,
653
+ values,
654
+ grid_vertices,
655
+ grid_colors,
656
+ adj_verts,
657
+ adj_colors,
658
+ iso,
659
+ adj_values,
660
+ adj_grid_colors,
661
+ with_colors);
518
662
  }
519
663
  }
@@ -0,0 +1,39 @@
1
+ #ifndef MC_H
2
+ #define MC_H
3
+
4
+ #include <torch/extension.h>
5
+ #include "mc_data.h"
6
+ #include "../check.h"
7
+ #include "../constants.h"
8
+ #include "../primitive/edge.h"
9
+
10
+ #include <optional>
11
+
12
+ namespace mc{
13
+ std::tuple<torch::Tensor, torch::Tensor, std::optional<torch::Tensor>, std::optional<torch::Tensor>, std::optional<torch::Tensor>> marching_cubes(
14
+ const uint32_t num_voxels,
15
+ const float3* __restrict__ grid_vertices,
16
+ const uint32_t* __restrict__ voxels,
17
+ const float* __restrict__ voxel_values,
18
+ const float3* __restrict__ grid_normals,
19
+ const float3* __restrict__ grid_colors,
20
+ const float iso,
21
+ torch::TensorOptions vert_options,
22
+ torch::TensorOptions tri_options,
23
+ bool return_unique_edges = false
24
+ );
25
+ void backward(
26
+ const uint32_t n_verts,
27
+ const Edge *unique_edges,
28
+ const float3 *grid_vertices,
29
+ const float3 *grid_colors,
30
+ const float *values,
31
+ const float3 *adj_verts,
32
+ const float3 *adj_colors,
33
+ float *adj_values,
34
+ float3 *adj_grid_colors,
35
+ const float iso
36
+ );
37
+ }
38
+
39
+ #endif // MC_H
@@ -167,6 +167,21 @@ namespace aabb
167
167
  (target_aabb_max.y) >= query_aabb_max.y &&
168
168
  (target_aabb_max.z) >= query_aabb_max.z);
169
169
  }
170
+
171
+ __device__ __forceinline__ bool test_point_inside_aabb(
172
+ const float3 &point,
173
+ const float3 &aabb_min,
174
+ const float3 &aabb_max
175
+ )
176
+ {
177
+ return (
178
+ aabb_min.x <= point.x &&
179
+ aabb_min.y <= point.y &&
180
+ aabb_min.z <= point.z &&
181
+ (aabb_max.x) >= point.x &&
182
+ (aabb_max.y) >= point.y &&
183
+ (aabb_max.z) >= point.z);
184
+ }
170
185
  }
171
186
 
172
187
  #endif // AABB_H
File without changes
@@ -0,0 +1,43 @@
1
+ import torch
2
+
3
+ def sparse_collate_fn(batch):
4
+ """
5
+ Collate function for sparse tensor dataloaders (e.g., MinkowskiEngine, spconv, torchsparse).
6
+ Takes a batch of samples where each sample is (idx_grids, features, ...).
7
+ Appends the batch index to the idx_grids to create (batch_idx, x, y, z).
8
+
9
+ Args:
10
+ batch (list): A list of tuples (idx_grids, features, label)
11
+
12
+ Returns:
13
+ tuple: (batched_coords, batched_features, batched_labels)
14
+ batched_coords (torch.Tensor): Shape (Total_N, 4)
15
+ batched_features (torch.Tensor): Shape (Total_N, ...)
16
+ batched_labels (torch.Tensor): Shape (Batch_Size,)
17
+ """
18
+ batched_coords = []
19
+ batched_features = []
20
+ batched_labels = []
21
+
22
+ for batch_idx, item in enumerate(batch):
23
+ idx_grids, features, label = item
24
+
25
+ # Create a batch index column of shape [N, 1]
26
+ b_col = torch.full((idx_grids.shape[0], 1), batch_idx, dtype=idx_grids.dtype, device=idx_grids.device)
27
+
28
+ # Concatenate to get [N, 4] formatted as (batch_idx, x, y, z)
29
+ coords_with_batch = torch.cat([b_col, idx_grids], dim=1)
30
+
31
+ batched_coords.append(coords_with_batch)
32
+ batched_features.append(features)
33
+ batched_labels.append(label)
34
+
35
+ batched_coords = torch.cat(batched_coords, dim=0)
36
+ batched_features = torch.cat(batched_features, dim=0)
37
+
38
+ if isinstance(batched_labels[0], torch.Tensor):
39
+ batched_labels = torch.stack(batched_labels, dim=0)
40
+ else:
41
+ batched_labels = torch.tensor(batched_labels)
42
+
43
+ return batched_coords, batched_features, batched_labels
File without changes
@@ -0,0 +1,17 @@
1
+ from torch.utils.data import Dataset
2
+ from typing import Callable, Optional
3
+
4
+ class BaseMeshDataset(Dataset):
5
+ """
6
+ Base PyTorch Dataset class for Mesh datasets.
7
+ """
8
+ def __init__(self, root: str, transform: Optional[Callable] = None):
9
+ super().__init__()
10
+ self.root = root
11
+ self.transform = transform
12
+
13
+ def __len__(self) -> int:
14
+ raise NotImplementedError("Subclasses must implement __len__")
15
+
16
+ def __getitem__(self, idx: int):
17
+ raise NotImplementedError("Subclasses must implement __getitem__")