conquer3d 0.3.1__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.1/conquer3d.egg-info → conquer3d-0.3.3}/PKG-INFO +21 -1
- {conquer3d-0.3.1 → conquer3d-0.3.3}/README.md +20 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/_C.so +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/__init__.py +4 -1
- conquer3d-0.3.3/conquer3d/conversion/__init__.py +13 -0
- {conquer3d-0.3.1/conquer3d/data_structure → conquer3d-0.3.3/conquer3d/conversion}/grid.py +49 -88
- conquer3d-0.3.3/conquer3d/conversion/mesh.py +120 -0
- {conquer3d-0.3.1 → 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.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/mesh_bvh.cu +1 -1
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/triangle_mesh.cu +299 -1
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/triangle_mesh.h +71 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/maths/f3x1.h +14 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/edge.h +7 -0
- conquer3d-0.3.1/conquer3d/csrc/primitive/triangles.h → conquer3d-0.3.3/conquer3d/csrc/primitive/triangle.h +156 -6
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/pybind.cpp +4 -0
- conquer3d-0.3.3/conquer3d/data/collate/mesh.py +40 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/data/dataset/digit3d.py +4 -8
- conquer3d-0.3.3/conquer3d/data/transform/base.py +39 -0
- conquer3d-0.3.3/conquer3d/data/transform/ops.py +62 -0
- conquer3d-0.3.3/conquer3d/data/transform/vertex.py +55 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/data_structure/__init__.py +0 -6
- conquer3d-0.3.3/conquer3d/data_structure/bmesh.py +23 -0
- conquer3d-0.3.3/conquer3d/data_structure/grid.py +65 -0
- conquer3d-0.3.3/conquer3d/primitive/__init__.py +3 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3/conquer3d.egg-info}/PKG-INFO +21 -1
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d.egg-info/SOURCES.txt +11 -1
- {conquer3d-0.3.1 → conquer3d-0.3.3}/pyproject.toml +1 -1
- conquer3d-0.3.1/conquer3d/primitive/__init__.py +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/LICENSE +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/MANIFEST.in +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/_C.pyi +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/creation/__init__.py +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/creation/triangle_creation.py +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/creation/triangle_creation.cpp +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/bvh.cpp +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/grid.cpp +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/gs_bvh.cpp +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/kdtree.cpp +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/mesh_bvh.cpp +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/pgs_bvh.cpp +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/ops/chamfer.cpp +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/ops/mc.cpp +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/primitive/gs.cpp +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/primitive/pgs.cpp +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/check.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/constants.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/creation/triangle_creation.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/bvh.cu +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/bvh.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/gs_bvh.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/kdtree.cu +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/kdtree.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/mesh_bvh.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/pgs_bvh.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/zcurve.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/maths/f2x2.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/maths/f3x3.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/maths/f3x4.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/maths/f4x1.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/maths/f4x4.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/maths/maths.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/maths/ops.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/ops/chamfer.cu +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/ops/chamfer.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/ops/mc.cu +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/ops/mc.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/ops/mc_data.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/aabb.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/gs.cu +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/gs.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/gs_aabb.cu +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/gs_math.cuh +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/pgs.cu +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/pgs.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/pgs_aabb.cu +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/pgs_math.cuh +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/ray.h +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/data/__init__.py +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/data/collate/__init__.py +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/data/collate/sparse_tensor.py +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/data/dataset/__init__.py +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/data/dataset/base_mesh.py +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/data/transform/__init__.py +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/ops/__init__.py +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/ops/diff_marching_cubes.py +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/ops/distance.py +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/ops/marching_cubes.py +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/primitive/gs.py +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/primitive/pgs.py +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d.egg-info/dependency_links.txt +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d.egg-info/not-zip-safe +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d.egg-info/requires.txt +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d.egg-info/top_level.txt +0 -0
- {conquer3d-0.3.1 → conquer3d-0.3.3}/setup.cfg +0 -0
- {conquer3d-0.3.1 → 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
|
|
@@ -63,6 +63,8 @@ pip install pybind11-stubgen
|
|
|
63
63
|
pip install git+https://github.com/KhoiDOO/geocutool.git --no-build-isolation
|
|
64
64
|
|
|
65
65
|
pip install plotly open3d jupyter trimesh point-cloud-utils meshlib
|
|
66
|
+
|
|
67
|
+
pip install rectified-flow-pytorch
|
|
66
68
|
```
|
|
67
69
|
|
|
68
70
|
# Development
|
|
@@ -129,6 +131,24 @@ twine upload dist/* --verbose
|
|
|
129
131
|
}
|
|
130
132
|
```
|
|
131
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
|
+
|
|
132
152
|
## Blog Post
|
|
133
153
|
- [Thinking Parallel, Part I: Collision Detection on the GPU](https://developer.nvidia.com/blog/thinking-parallel-part-i-collision-detection-gpu/)
|
|
134
154
|
- [Thinking Parallel, Part II: Tree Traversal on the GPU](https://developer.nvidia.com/blog/thinking-parallel-part-ii-tree-traversal-gpu/)
|
|
@@ -34,6 +34,8 @@ pip install pybind11-stubgen
|
|
|
34
34
|
pip install git+https://github.com/KhoiDOO/geocutool.git --no-build-isolation
|
|
35
35
|
|
|
36
36
|
pip install plotly open3d jupyter trimesh point-cloud-utils meshlib
|
|
37
|
+
|
|
38
|
+
pip install rectified-flow-pytorch
|
|
37
39
|
```
|
|
38
40
|
|
|
39
41
|
# Development
|
|
@@ -100,6 +102,24 @@ twine upload dist/* --verbose
|
|
|
100
102
|
}
|
|
101
103
|
```
|
|
102
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
|
+
|
|
103
123
|
## Blog Post
|
|
104
124
|
- [Thinking Parallel, Part I: Collision Detection on the GPU](https://developer.nvidia.com/blog/thinking-parallel-part-i-collision-detection-gpu/)
|
|
105
125
|
- [Thinking Parallel, Part II: Tree Traversal on the GPU](https://developer.nvidia.com/blog/thinking-parallel-part-ii-tree-traversal-gpu/)
|
|
Binary file
|
|
@@ -5,5 +5,8 @@ from . import creation
|
|
|
5
5
|
from . import data_structure
|
|
6
6
|
from . import primitive
|
|
7
7
|
from . import ops
|
|
8
|
+
from . import conversion
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
from .primitive import Triangle, Ray
|
|
11
|
+
|
|
12
|
+
__all__ = ['_C', 'creation', 'data_structure', 'primitive', 'ops', 'conversion', 'Triangle', 'Ray']
|
|
@@ -1,68 +1,5 @@
|
|
|
1
1
|
import torch
|
|
2
2
|
from typing import Tuple, List, Union
|
|
3
|
-
from .. import _C
|
|
4
|
-
|
|
5
|
-
def create_voxel_grid(
|
|
6
|
-
grid_min: Union[List[float], Tuple[float, float, float]],
|
|
7
|
-
grid_max: Union[List[float], Tuple[float, float, float]],
|
|
8
|
-
res: Union[List[int], Tuple[int, int, int]],
|
|
9
|
-
device: str = "cuda"
|
|
10
|
-
) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
|
11
|
-
"""
|
|
12
|
-
Creates a structured 3D voxel grid efficiently.
|
|
13
|
-
|
|
14
|
-
Args:
|
|
15
|
-
grid_min (List[float] | Tuple[float, float, float]): The minimum (x, y, z) bounding box coordinates.
|
|
16
|
-
grid_max (List[float] | Tuple[float, float, float]): The maximum (x, y, z) bounding box coordinates.
|
|
17
|
-
res (List[int] | Tuple[int, int, int]): The number of vertices along each axis (rx, ry, rz).
|
|
18
|
-
device (str, optional): Target device for the tensors (e.g., "cuda" or "cpu"). Defaults to "cuda".
|
|
19
|
-
|
|
20
|
-
Returns:
|
|
21
|
-
Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
|
|
22
|
-
- grid_vertices (torch.Tensor): A float32 tensor of shape (N, 3) containing all grid coordinates.
|
|
23
|
-
- voxels (torch.Tensor): An int32 tensor of shape (V, 8) containing corner indices
|
|
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.
|
|
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))
|
|
48
|
-
|
|
49
|
-
def compute_active_voxels(
|
|
50
|
-
voxels: torch.Tensor,
|
|
51
|
-
sdf: torch.Tensor,
|
|
52
|
-
iso: float = 0.0
|
|
53
|
-
) -> torch.Tensor:
|
|
54
|
-
"""
|
|
55
|
-
Computes the indices of active voxels that intersect the isosurface.
|
|
56
|
-
|
|
57
|
-
Args:
|
|
58
|
-
voxels (torch.Tensor): An int32 tensor of shape (V, 8) containing corner indices for each voxel.
|
|
59
|
-
sdf (torch.Tensor): A float32 tensor of shape (N,) containing the SDF values.
|
|
60
|
-
iso (float): The isosurface value. Defaults to 0.0.
|
|
61
|
-
|
|
62
|
-
Returns:
|
|
63
|
-
torch.Tensor: An int64 tensor containing the indices of the active voxels.
|
|
64
|
-
"""
|
|
65
|
-
return _C.compute_active_voxels(voxels.contiguous(), sdf.contiguous(), iso)
|
|
66
3
|
|
|
67
4
|
def voxel2sparse(
|
|
68
5
|
active_indices: torch.Tensor,
|
|
@@ -104,28 +41,6 @@ def voxel2sparse(
|
|
|
104
41
|
return sparse_coords
|
|
105
42
|
|
|
106
43
|
def sparse2voxel(
|
|
107
|
-
sparse_coords: torch.Tensor,
|
|
108
|
-
res: Union[List[int], Tuple[int, int, int]]
|
|
109
|
-
) -> torch.Tensor:
|
|
110
|
-
"""
|
|
111
|
-
Converts a [N, 4] sparse coordinates tensor back to 1D active voxel indices.
|
|
112
|
-
|
|
113
|
-
Args:
|
|
114
|
-
sparse_coords (torch.Tensor): An int32 tensor of shape (N, 4) in the format [batch_idx, x, y, z].
|
|
115
|
-
res (List[int] | Tuple[int, int, int]): The number of vertices along each axis (rx, ry, rz).
|
|
116
|
-
|
|
117
|
-
Returns:
|
|
118
|
-
torch.Tensor: An int64 tensor containing the indices of the active voxels.
|
|
119
|
-
"""
|
|
120
|
-
x = sparse_coords[:, 1].to(torch.int64)
|
|
121
|
-
y = sparse_coords[:, 2].to(torch.int64)
|
|
122
|
-
z = sparse_coords[:, 3].to(torch.int64)
|
|
123
|
-
|
|
124
|
-
rx, ry, rz = res
|
|
125
|
-
active_indices = x * (ry - 1) * (rz - 1) + y * (rz - 1) + z
|
|
126
|
-
return active_indices
|
|
127
|
-
|
|
128
|
-
def sparse2mesh_topology(
|
|
129
44
|
sparse_coords: torch.Tensor,
|
|
130
45
|
sparse_sdfs: torch.Tensor,
|
|
131
46
|
grid_min: Union[List[float], Tuple[float, float, float]],
|
|
@@ -182,9 +97,9 @@ def sparse2mesh_topology(
|
|
|
182
97
|
|
|
183
98
|
# 6. Convert integer coordinates back to global float positions
|
|
184
99
|
rx, ry, rz = res
|
|
185
|
-
x_coords = torch.linspace(grid_min[0], grid_max[0], rx, device=device, dtype=torch.float32)
|
|
186
|
-
y_coords = torch.linspace(grid_min[1], grid_max[1], ry, device=device, dtype=torch.float32)
|
|
187
|
-
z_coords = torch.linspace(grid_min[2], grid_max[2], rz, device=device, dtype=torch.float32)
|
|
100
|
+
x_coords = torch.linspace(grid_min[0], grid_max[0], rx + 1, device=device, dtype=torch.float32)
|
|
101
|
+
y_coords = torch.linspace(grid_min[1], grid_max[1], ry + 1, device=device, dtype=torch.float32)
|
|
102
|
+
z_coords = torch.linspace(grid_min[2], grid_max[2], rz + 1, device=device, dtype=torch.float32)
|
|
188
103
|
|
|
189
104
|
ux = x_coords[unique_corners_int[:, 0]]
|
|
190
105
|
uy = y_coords[unique_corners_int[:, 1]]
|
|
@@ -193,3 +108,49 @@ def sparse2mesh_topology(
|
|
|
193
108
|
unique_vertices = torch.stack([ux, uy, uz], dim=1)
|
|
194
109
|
|
|
195
110
|
return unique_vertices, local_voxels, merged_sdfs
|
|
111
|
+
|
|
112
|
+
def sparse_coo2dense_occ(
|
|
113
|
+
sparse_coords: torch.Tensor,
|
|
114
|
+
batch_size: int,
|
|
115
|
+
res: Union[List[int], Tuple[int, int, int]]
|
|
116
|
+
) -> torch.Tensor:
|
|
117
|
+
"""
|
|
118
|
+
Converts a [N, 4] sparse coordinates tensor into a [B, 1, rx, ry, rz] dense occupancy grid.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
sparse_coords (torch.Tensor): An int32 tensor of shape (N, 4) in the format [batch_idx, x, y, z].
|
|
122
|
+
batch_size (int): The batch size B.
|
|
123
|
+
res (List[int] | Tuple[int, int, int]): The grid resolution (rx, ry, rz).
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
torch.Tensor: A float32 tensor of shape [B, 1, rx, ry, rz] containing 1.0 at active voxels and 0.0 otherwise.
|
|
127
|
+
"""
|
|
128
|
+
rx, ry, rz = res
|
|
129
|
+
dense_occ = torch.zeros((batch_size, 1, rx, ry, rz), dtype=torch.float32, device=sparse_coords.device)
|
|
130
|
+
|
|
131
|
+
b = sparse_coords[:, 0].to(torch.int64)
|
|
132
|
+
x = sparse_coords[:, 1].to(torch.int64)
|
|
133
|
+
y = sparse_coords[:, 2].to(torch.int64)
|
|
134
|
+
z = sparse_coords[:, 3].to(torch.int64)
|
|
135
|
+
|
|
136
|
+
dense_occ[b, 0, x, y, z] = 1.0
|
|
137
|
+
return dense_occ
|
|
138
|
+
|
|
139
|
+
def dense_occ2sparse_coo(
|
|
140
|
+
dense_occ: torch.Tensor,
|
|
141
|
+
threshold: float = 0.0
|
|
142
|
+
) -> torch.Tensor:
|
|
143
|
+
"""
|
|
144
|
+
Converts a [B, C, rx, ry, rz] dense occupancy grid back to a [N, 4] sparse coordinates tensor.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
dense_occ (torch.Tensor): A tensor of shape [B, C, rx, ry, rz].
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
torch.Tensor: An int32 tensor of shape (N, 4) in the format [batch_idx, x, y, z].
|
|
151
|
+
"""
|
|
152
|
+
active_mask = dense_occ > threshold
|
|
153
|
+
indices = torch.argwhere(active_mask)
|
|
154
|
+
# indices has shape [N, 5] for [b, c, x, y, z]. We want [batch_idx, x, y, z]
|
|
155
|
+
sparse_coords = indices[:, [0, 2, 3, 4]].to(torch.int32)
|
|
156
|
+
return sparse_coords
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
from conquer3d.data_structure.grid import create_voxel_grid, compute_active_voxels
|
|
3
|
+
from conquer3d.conversion.grid import voxel2sparse
|
|
4
|
+
from conquer3d.data_structure import TriangleMesh
|
|
5
|
+
from conquer3d.data_structure.bmesh import BTriangleMesh
|
|
6
|
+
from typing import Union, List, Tuple
|
|
7
|
+
|
|
8
|
+
def mesh2voxel(vertices: torch.Tensor, res: Union[List[int], Tuple[int, int, int]], grid_bound: float = None):
|
|
9
|
+
"""
|
|
10
|
+
Computes bounding box of mesh and returns a structured voxel grid.
|
|
11
|
+
"""
|
|
12
|
+
if grid_bound is None:
|
|
13
|
+
grid_min = vertices.min(dim=0)[0].tolist()
|
|
14
|
+
grid_max = vertices.max(dim=0)[0].tolist()
|
|
15
|
+
else:
|
|
16
|
+
grid_min = [-grid_bound, -grid_bound, -grid_bound]
|
|
17
|
+
grid_max = [grid_bound, grid_bound, grid_bound]
|
|
18
|
+
|
|
19
|
+
device_str = str(vertices.device)
|
|
20
|
+
if device_str.startswith('cuda'):
|
|
21
|
+
# Fix format if there's an index like cuda:0
|
|
22
|
+
device_str = "cuda"
|
|
23
|
+
|
|
24
|
+
grid_vertices, voxels, idx_grids = create_voxel_grid(grid_min, grid_max, res, device=device_str)
|
|
25
|
+
|
|
26
|
+
# Ensure they are on the exact same device as vertices (especially if multiple GPUs)
|
|
27
|
+
grid_vertices = grid_vertices.to(vertices.device)
|
|
28
|
+
voxels = voxels.to(vertices.device)
|
|
29
|
+
idx_grids = idx_grids.to(vertices.device)
|
|
30
|
+
|
|
31
|
+
return grid_vertices, voxels, idx_grids, grid_min, grid_max
|
|
32
|
+
|
|
33
|
+
def mesh2voxel_sdf(vertices: torch.Tensor, faces: torch.Tensor, grid_vertices: torch.Tensor):
|
|
34
|
+
"""
|
|
35
|
+
Computes SDF for grid vertices against the mesh using C++ TriangleMesh fast winding numbers.
|
|
36
|
+
"""
|
|
37
|
+
mesh = TriangleMesh(vertices, faces.to(torch.int32))
|
|
38
|
+
|
|
39
|
+
# query_points returns: q_ids, tri_ids, prj_pts, sdf
|
|
40
|
+
_, _, _, sdf = mesh.query_points(
|
|
41
|
+
grid_vertices,
|
|
42
|
+
return_sdf=True,
|
|
43
|
+
return_prj_pts=False,
|
|
44
|
+
sign_mode=0,
|
|
45
|
+
distance_mode=0
|
|
46
|
+
)
|
|
47
|
+
return sdf
|
|
48
|
+
|
|
49
|
+
def mesh2sparse(bmesh: BTriangleMesh, res: Union[List[int], Tuple[int, int, int]], grid_bound: float = 1.2, iso: float = 0.0):
|
|
50
|
+
"""
|
|
51
|
+
Batched processing of BTriangleMesh into sparse tensors.
|
|
52
|
+
"""
|
|
53
|
+
all_coords = []
|
|
54
|
+
all_sdfs = []
|
|
55
|
+
|
|
56
|
+
for b in range(bmesh.batch_size):
|
|
57
|
+
# Extract individual mesh
|
|
58
|
+
v_mask = bmesh.vertbids == b
|
|
59
|
+
f_mask = bmesh.facebids == b
|
|
60
|
+
|
|
61
|
+
v = bmesh.vertices[v_mask]
|
|
62
|
+
f = bmesh.faces[f_mask]
|
|
63
|
+
|
|
64
|
+
if len(v) == 0:
|
|
65
|
+
continue
|
|
66
|
+
|
|
67
|
+
# Voxelize and Compute SDF
|
|
68
|
+
grid_vertices, voxels, idx_grids, _, _ = mesh2voxel(v, res, grid_bound)
|
|
69
|
+
sdf = mesh2voxel_sdf(v, f, grid_vertices)
|
|
70
|
+
|
|
71
|
+
# Sparse conversion
|
|
72
|
+
active_voxels = compute_active_voxels(voxels, sdf, iso)
|
|
73
|
+
sparse_coords, sparse_sdfs = voxel2sparse(active_voxels, voxels, idx_grids, sdf=sdf, batch_idx=b)
|
|
74
|
+
|
|
75
|
+
all_coords.append(sparse_coords)
|
|
76
|
+
all_sdfs.append(sparse_sdfs)
|
|
77
|
+
|
|
78
|
+
if len(all_coords) > 0:
|
|
79
|
+
return torch.cat(all_coords, dim=0), torch.cat(all_sdfs, dim=0)
|
|
80
|
+
else:
|
|
81
|
+
# Fallback for empty batch
|
|
82
|
+
device = bmesh.vertices.device
|
|
83
|
+
return torch.empty((0, 4), dtype=torch.int32, device=device), torch.empty((0, 8), dtype=torch.float32, device=device)
|
|
84
|
+
|
|
85
|
+
def mesh2sparse_with_dense(bmesh: BTriangleMesh, res: Union[List[int], Tuple[int, int, int]], grid_bound: float = 1.2, iso: float = 0.0):
|
|
86
|
+
"""
|
|
87
|
+
Batched processing of BTriangleMesh into sparse tensors, also returning full dense coords.
|
|
88
|
+
"""
|
|
89
|
+
all_coords = []
|
|
90
|
+
all_sdfs = []
|
|
91
|
+
all_dense_coords = []
|
|
92
|
+
all_dense_sdfs = []
|
|
93
|
+
|
|
94
|
+
for b in range(bmesh.batch_size):
|
|
95
|
+
v_mask = bmesh.vertbids == b
|
|
96
|
+
f_mask = bmesh.facebids == b
|
|
97
|
+
|
|
98
|
+
v = bmesh.vertices[v_mask]
|
|
99
|
+
f = bmesh.faces[f_mask]
|
|
100
|
+
|
|
101
|
+
if len(v) == 0:
|
|
102
|
+
continue
|
|
103
|
+
|
|
104
|
+
grid_vertices, voxels, idx_grids, _, _ = mesh2voxel(v, res, grid_bound)
|
|
105
|
+
sdf = mesh2voxel_sdf(v, f, grid_vertices)
|
|
106
|
+
|
|
107
|
+
active_voxels = compute_active_voxels(voxels, sdf, iso)
|
|
108
|
+
sparse_coords, sparse_sdfs = voxel2sparse(active_voxels, voxels, idx_grids, sdf=sdf, batch_idx=b)
|
|
109
|
+
dense_coords, dense_sdfs = voxel2sparse(torch.ones_like(voxels[:, 0], dtype=torch.bool), voxels, idx_grids, sdf=sdf, batch_idx=b)
|
|
110
|
+
|
|
111
|
+
all_coords.append(sparse_coords)
|
|
112
|
+
all_sdfs.append(sparse_sdfs)
|
|
113
|
+
all_dense_coords.append(dense_coords)
|
|
114
|
+
all_dense_sdfs.append(dense_sdfs)
|
|
115
|
+
|
|
116
|
+
if len(all_coords) > 0:
|
|
117
|
+
return torch.cat(all_coords, dim=0), torch.cat(all_sdfs, dim=0), torch.cat(all_dense_coords, dim=0), torch.cat(all_dense_sdfs, dim=0)
|
|
118
|
+
else:
|
|
119
|
+
device = bmesh.vertices.device
|
|
120
|
+
return torch.empty((0, 4), dtype=torch.int32, device=device), torch.empty((0, 8), dtype=torch.float32, device=device), torch.empty((0, 4), dtype=torch.int32, device=device), torch.empty((0, 8), dtype=torch.float32, device=device)
|