murcherful commited on
Commit
5b3fc44
·
1 Parent(s): 1c78eb8
P3-SAM/utils/chamfer3D/chamfer3D.cu DELETED
@@ -1,196 +0,0 @@
1
-
2
- #include <stdio.h>
3
- #include <ATen/ATen.h>
4
-
5
- #include <cuda.h>
6
- #include <cuda_runtime.h>
7
-
8
- #include <vector>
9
-
10
-
11
-
12
- __global__ void NmDistanceKernel(int b,int n,const float * xyz,int m,const float * xyz2,float * result,int * result_i){
13
- const int batch=512;
14
- __shared__ float buf[batch*3];
15
- for (int i=blockIdx.x;i<b;i+=gridDim.x){
16
- for (int k2=0;k2<m;k2+=batch){
17
- int end_k=min(m,k2+batch)-k2;
18
- for (int j=threadIdx.x;j<end_k*3;j+=blockDim.x){
19
- buf[j]=xyz2[(i*m+k2)*3+j];
20
- }
21
- __syncthreads();
22
- for (int j=threadIdx.x+blockIdx.y*blockDim.x;j<n;j+=blockDim.x*gridDim.y){
23
- float x1=xyz[(i*n+j)*3+0];
24
- float y1=xyz[(i*n+j)*3+1];
25
- float z1=xyz[(i*n+j)*3+2];
26
- int best_i=0;
27
- float best=0;
28
- int end_ka=end_k-(end_k&3);
29
- if (end_ka==batch){
30
- for (int k=0;k<batch;k+=4){
31
- {
32
- float x2=buf[k*3+0]-x1;
33
- float y2=buf[k*3+1]-y1;
34
- float z2=buf[k*3+2]-z1;
35
- float d=x2*x2+y2*y2+z2*z2;
36
- if (k==0 || d<best){
37
- best=d;
38
- best_i=k+k2;
39
- }
40
- }
41
- {
42
- float x2=buf[k*3+3]-x1;
43
- float y2=buf[k*3+4]-y1;
44
- float z2=buf[k*3+5]-z1;
45
- float d=x2*x2+y2*y2+z2*z2;
46
- if (d<best){
47
- best=d;
48
- best_i=k+k2+1;
49
- }
50
- }
51
- {
52
- float x2=buf[k*3+6]-x1;
53
- float y2=buf[k*3+7]-y1;
54
- float z2=buf[k*3+8]-z1;
55
- float d=x2*x2+y2*y2+z2*z2;
56
- if (d<best){
57
- best=d;
58
- best_i=k+k2+2;
59
- }
60
- }
61
- {
62
- float x2=buf[k*3+9]-x1;
63
- float y2=buf[k*3+10]-y1;
64
- float z2=buf[k*3+11]-z1;
65
- float d=x2*x2+y2*y2+z2*z2;
66
- if (d<best){
67
- best=d;
68
- best_i=k+k2+3;
69
- }
70
- }
71
- }
72
- }else{
73
- for (int k=0;k<end_ka;k+=4){
74
- {
75
- float x2=buf[k*3+0]-x1;
76
- float y2=buf[k*3+1]-y1;
77
- float z2=buf[k*3+2]-z1;
78
- float d=x2*x2+y2*y2+z2*z2;
79
- if (k==0 || d<best){
80
- best=d;
81
- best_i=k+k2;
82
- }
83
- }
84
- {
85
- float x2=buf[k*3+3]-x1;
86
- float y2=buf[k*3+4]-y1;
87
- float z2=buf[k*3+5]-z1;
88
- float d=x2*x2+y2*y2+z2*z2;
89
- if (d<best){
90
- best=d;
91
- best_i=k+k2+1;
92
- }
93
- }
94
- {
95
- float x2=buf[k*3+6]-x1;
96
- float y2=buf[k*3+7]-y1;
97
- float z2=buf[k*3+8]-z1;
98
- float d=x2*x2+y2*y2+z2*z2;
99
- if (d<best){
100
- best=d;
101
- best_i=k+k2+2;
102
- }
103
- }
104
- {
105
- float x2=buf[k*3+9]-x1;
106
- float y2=buf[k*3+10]-y1;
107
- float z2=buf[k*3+11]-z1;
108
- float d=x2*x2+y2*y2+z2*z2;
109
- if (d<best){
110
- best=d;
111
- best_i=k+k2+3;
112
- }
113
- }
114
- }
115
- }
116
- for (int k=end_ka;k<end_k;k++){
117
- float x2=buf[k*3+0]-x1;
118
- float y2=buf[k*3+1]-y1;
119
- float z2=buf[k*3+2]-z1;
120
- float d=x2*x2+y2*y2+z2*z2;
121
- if (k==0 || d<best){
122
- best=d;
123
- best_i=k+k2;
124
- }
125
- }
126
- if (k2==0 || result[(i*n+j)]>best){
127
- result[(i*n+j)]=best;
128
- result_i[(i*n+j)]=best_i;
129
- }
130
- }
131
- __syncthreads();
132
- }
133
- }
134
- }
135
- // int chamfer_cuda_forward(int b,int n,const float * xyz,int m,const float * xyz2,float * result,int * result_i,float * result2,int * result2_i, cudaStream_t stream){
136
- int chamfer_cuda_forward(at::Tensor xyz1, at::Tensor xyz2, at::Tensor dist1, at::Tensor dist2, at::Tensor idx1, at::Tensor idx2){
137
-
138
- const auto batch_size = xyz1.size(0);
139
- const auto n = xyz1.size(1); //num_points point cloud A
140
- const auto m = xyz2.size(1); //num_points point cloud B
141
-
142
- NmDistanceKernel<<<dim3(32,16,1),512>>>(batch_size, n, xyz1.data<float>(), m, xyz2.data<float>(), dist1.data<float>(), idx1.data<int>());
143
- NmDistanceKernel<<<dim3(32,16,1),512>>>(batch_size, m, xyz2.data<float>(), n, xyz1.data<float>(), dist2.data<float>(), idx2.data<int>());
144
-
145
- cudaError_t err = cudaGetLastError();
146
- if (err != cudaSuccess) {
147
- printf("error in nnd updateOutput: %s\n", cudaGetErrorString(err));
148
- //THError("aborting");
149
- return 0;
150
- }
151
- return 1;
152
-
153
-
154
- }
155
- __global__ void NmDistanceGradKernel(int b,int n,const float * xyz1,int m,const float * xyz2,const float * grad_dist1,const int * idx1,float * grad_xyz1,float * grad_xyz2){
156
- for (int i=blockIdx.x;i<b;i+=gridDim.x){
157
- for (int j=threadIdx.x+blockIdx.y*blockDim.x;j<n;j+=blockDim.x*gridDim.y){
158
- float x1=xyz1[(i*n+j)*3+0];
159
- float y1=xyz1[(i*n+j)*3+1];
160
- float z1=xyz1[(i*n+j)*3+2];
161
- int j2=idx1[i*n+j];
162
- float x2=xyz2[(i*m+j2)*3+0];
163
- float y2=xyz2[(i*m+j2)*3+1];
164
- float z2=xyz2[(i*m+j2)*3+2];
165
- float g=grad_dist1[i*n+j]*2;
166
- atomicAdd(&(grad_xyz1[(i*n+j)*3+0]),g*(x1-x2));
167
- atomicAdd(&(grad_xyz1[(i*n+j)*3+1]),g*(y1-y2));
168
- atomicAdd(&(grad_xyz1[(i*n+j)*3+2]),g*(z1-z2));
169
- atomicAdd(&(grad_xyz2[(i*m+j2)*3+0]),-(g*(x1-x2)));
170
- atomicAdd(&(grad_xyz2[(i*m+j2)*3+1]),-(g*(y1-y2)));
171
- atomicAdd(&(grad_xyz2[(i*m+j2)*3+2]),-(g*(z1-z2)));
172
- }
173
- }
174
- }
175
- // int chamfer_cuda_backward(int b,int n,const float * xyz1,int m,const float * xyz2,const float * grad_dist1,const int * idx1,const float * grad_dist2,const int * idx2,float * grad_xyz1,float * grad_xyz2, cudaStream_t stream){
176
- int chamfer_cuda_backward(at::Tensor xyz1, at::Tensor xyz2, at::Tensor gradxyz1, at::Tensor gradxyz2, at::Tensor graddist1, at::Tensor graddist2, at::Tensor idx1, at::Tensor idx2){
177
- // cudaMemset(grad_xyz1,0,b*n*3*4);
178
- // cudaMemset(grad_xyz2,0,b*m*3*4);
179
-
180
- const auto batch_size = xyz1.size(0);
181
- const auto n = xyz1.size(1); //num_points point cloud A
182
- const auto m = xyz2.size(1); //num_points point cloud B
183
-
184
- NmDistanceGradKernel<<<dim3(1,16,1),256>>>(batch_size,n,xyz1.data<float>(),m,xyz2.data<float>(),graddist1.data<float>(),idx1.data<int>(),gradxyz1.data<float>(),gradxyz2.data<float>());
185
- NmDistanceGradKernel<<<dim3(1,16,1),256>>>(batch_size,m,xyz2.data<float>(),n,xyz1.data<float>(),graddist2.data<float>(),idx2.data<int>(),gradxyz2.data<float>(),gradxyz1.data<float>());
186
-
187
- cudaError_t err = cudaGetLastError();
188
- if (err != cudaSuccess) {
189
- printf("error in nnd get grad: %s\n", cudaGetErrorString(err));
190
- //THError("aborting");
191
- return 0;
192
- }
193
- return 1;
194
-
195
- }
196
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
P3-SAM/utils/chamfer3D/chamfer_cuda.cpp DELETED
@@ -1,29 +0,0 @@
1
- #include <torch/torch.h>
2
- #include <vector>
3
-
4
- /// TMP
5
- // #include "common.h"
6
- /// NOT TMP
7
-
8
- int chamfer_cuda_forward(at::Tensor xyz1, at::Tensor xyz2, at::Tensor dist1, at::Tensor dist2,
9
- at::Tensor idx1, at::Tensor idx2);
10
-
11
- int chamfer_cuda_backward(at::Tensor xyz1, at::Tensor xyz2, at::Tensor gradxyz1,
12
- at::Tensor gradxyz2, at::Tensor graddist1, at::Tensor graddist2,
13
- at::Tensor idx1, at::Tensor idx2);
14
-
15
- int chamfer_forward(at::Tensor xyz1, at::Tensor xyz2, at::Tensor dist1, at::Tensor dist2,
16
- at::Tensor idx1, at::Tensor idx2) {
17
- return chamfer_cuda_forward(xyz1, xyz2, dist1, dist2, idx1, idx2);
18
- }
19
-
20
- int chamfer_backward(at::Tensor xyz1, at::Tensor xyz2, at::Tensor gradxyz1, at::Tensor gradxyz2,
21
- at::Tensor graddist1, at::Tensor graddist2, at::Tensor idx1, at::Tensor idx2) {
22
-
23
- return chamfer_cuda_backward(xyz1, xyz2, gradxyz1, gradxyz2, graddist1, graddist2, idx1, idx2);
24
- }
25
-
26
- PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
27
- m.def("forward", &chamfer_forward, "chamfer forward (CUDA)");
28
- m.def("backward", &chamfer_backward, "chamfer backward (CUDA)");
29
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
P3-SAM/utils/chamfer3D/dist_chamfer_3D.py DELETED
@@ -1,81 +0,0 @@
1
- from torch import nn
2
- from torch.autograd import Function
3
- import torch
4
- import importlib
5
- import os
6
- chamfer_found = importlib.find_loader("chamfer_3D") is not None
7
- if not chamfer_found:
8
- ## Cool trick from https://github.com/chrdiller
9
- print("Jitting Chamfer 3D")
10
- cur_path = os.path.dirname(os.path.abspath(__file__))
11
- build_path = cur_path.replace('chamfer3D', 'tmp')
12
- os.makedirs(build_path, exist_ok=True)
13
-
14
- from torch.utils.cpp_extension import load
15
- chamfer_3D = load(name="chamfer_3D",
16
- sources=[
17
- "/".join(os.path.abspath(__file__).split('/')[:-1] + ["chamfer_cuda.cpp"]),
18
- "/".join(os.path.abspath(__file__).split('/')[:-1] + ["chamfer3D.cu"]),
19
- ], build_directory=build_path)
20
- print("Loaded JIT 3D CUDA chamfer distance")
21
-
22
- else:
23
- import chamfer_3D
24
- print("Loaded compiled 3D CUDA chamfer distance")
25
-
26
-
27
- # Chamfer's distance module @thibaultgroueix
28
- # GPU tensors only
29
- class chamfer_3DFunction(Function):
30
- @staticmethod
31
- def forward(ctx, xyz1, xyz2):
32
- batchsize, n, dim = xyz1.size()
33
- assert dim==3, "Wrong last dimension for the chamfer distance 's input! Check with .size()"
34
- _, m, dim = xyz2.size()
35
- assert dim==3, "Wrong last dimension for the chamfer distance 's input! Check with .size()"
36
- device = xyz1.device
37
-
38
- device = xyz1.device
39
-
40
- dist1 = torch.zeros(batchsize, n)
41
- dist2 = torch.zeros(batchsize, m)
42
-
43
- idx1 = torch.zeros(batchsize, n).type(torch.IntTensor)
44
- idx2 = torch.zeros(batchsize, m).type(torch.IntTensor)
45
-
46
- dist1 = dist1.to(device)
47
- dist2 = dist2.to(device)
48
- idx1 = idx1.to(device)
49
- idx2 = idx2.to(device)
50
- torch.cuda.set_device(device)
51
-
52
- chamfer_3D.forward(xyz1, xyz2, dist1, dist2, idx1, idx2)
53
- ctx.save_for_backward(xyz1, xyz2, idx1, idx2)
54
- return dist1, dist2, idx1, idx2
55
-
56
- @staticmethod
57
- def backward(ctx, graddist1, graddist2, gradidx1, gradidx2):
58
- xyz1, xyz2, idx1, idx2 = ctx.saved_tensors
59
- graddist1 = graddist1.contiguous()
60
- graddist2 = graddist2.contiguous()
61
- device = graddist1.device
62
-
63
- gradxyz1 = torch.zeros(xyz1.size())
64
- gradxyz2 = torch.zeros(xyz2.size())
65
-
66
- gradxyz1 = gradxyz1.to(device)
67
- gradxyz2 = gradxyz2.to(device)
68
- chamfer_3D.backward(
69
- xyz1, xyz2, gradxyz1, gradxyz2, graddist1, graddist2, idx1, idx2
70
- )
71
- return gradxyz1, gradxyz2
72
-
73
-
74
- class chamfer_3DDist(nn.Module):
75
- def __init__(self):
76
- super(chamfer_3DDist, self).__init__()
77
-
78
- def forward(self, input1, input2):
79
- input1 = input1.contiguous()
80
- input2 = input2.contiguous()
81
- return chamfer_3DFunction.apply(input1, input2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
P3-SAM/utils/chamfer3D/setup.py DELETED
@@ -1,14 +0,0 @@
1
- from setuptools import setup
2
- from torch.utils.cpp_extension import BuildExtension, CUDAExtension
3
-
4
- setup(
5
- name='chamfer_3D',
6
- ext_modules=[
7
- CUDAExtension('chamfer_3D', [
8
- "/".join(__file__.split('/')[:-1] + ['chamfer_cuda.cpp']),
9
- "/".join(__file__.split('/')[:-1] + ['chamfer3D.cu']),
10
- ]),
11
- ],
12
- cmdclass={
13
- 'build_ext': BuildExtension
14
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app.py CHANGED
@@ -11,13 +11,11 @@ import spaces
11
 
12
  sys.path.append('P3-SAM')
13
  from demo.auto_mask import AutoMask
14
- # from demo.auto_mask_no_postprocess import AutoMask as AutoMaskNoPostProcess
15
  sys.path.append('XPart')
16
  from partgen.partformer_pipeline import PartFormerPipeline
17
  from partgen.utils.misc import get_config_from_file
18
 
19
  automask = AutoMask()
20
- # automask_no_postprocess = AutoMaskNoPostProcess(automask_instance=automask)
21
 
22
  def _load_pipeline():
23
  pl.seed_everything(2026, workers=True)
@@ -41,17 +39,21 @@ _PIPELINE = _load_pipeline()
41
  output_path = 'P3-SAM/results/gradio'
42
  os.makedirs(output_path, exist_ok=True)
43
 
 
 
 
 
 
44
  @spaces.GPU
45
- def segment(mesh_path, connectivity=True, postprocess=True, postprocess_threshold=0.95, seed=42):
46
  if mesh_path is None:
47
  gr.Warning("No Input Mesh")
48
- gr_state[0] = (None, None)
 
 
49
  return None, None
50
  mesh = trimesh.load(mesh_path, force='mesh', process=False)
51
- if connectivity:
52
- aabb, face_ids, mesh = automask.predict_aabb(mesh, seed=seed, is_parallel=False, post_process=postprocess, threshold=postprocess_threshold)
53
- else:
54
- aabb, face_ids, mesh = automask_no_postprocess.predict_aabb(mesh, seed=seed, is_parallel=False, post_process=False)
55
  color_map = {}
56
  unique_ids = np.unique(face_ids)
57
  for i in unique_ids:
@@ -76,7 +78,7 @@ def segment(mesh_path, connectivity=True, postprocess=True, postprocess_threshol
76
  gr_state = [(aabb, mesh_path)]
77
  return file_path, face_id_save_path, gr_state
78
 
79
- @spaces.GPU
80
  def generate(mesh_path, seed=42, gr_state=None):
81
  if mesh_path is None:
82
  gr.Warning("No Input Mesh")
@@ -114,6 +116,7 @@ with gr.Blocks() as demo:
114
  # ☯️ Hunyuan3D Part:P3-SAM&XPart
115
  This demo allows you to generate parts given a 3D model using Hunyuan3D-Part.
116
  First segment the 3D model using P3-SAM and then generate parts using XPart.
 
117
  '''
118
  )
119
  with gr.Row():
@@ -133,7 +136,6 @@ Input a mesh and push the "Segment" button to get the segmentation results.
133
  p3sam_input = gr.Model3D(clear_color=[0.0, 0.0, 0.0, 0.0], label="Input Mesh")
134
  p3sam_output = gr.Model3D(clear_color=[0.0, 0.0, 0.0, 0.0], label="Segmentation Result")
135
  p3sam_face_id_output = gr.File(label='Face ID')
136
- p3sam_conectivity = gr.Checkbox(value=True, label="Connectivity")
137
  p3sam_postprocess = gr.Checkbox(value=True, label="Post-processing")
138
  p3sam_postprocess_threshold = gr.Number(value=0.95, label="Post-processing Threshold")
139
  p3sam_seed = gr.Number(value=42, label="Random Seed")
@@ -183,7 +185,7 @@ Input a mesh, segment it using P3-SAM on the left, and push the "Generate" butto
183
  xpart_output_exploded = gr.Model3D(clear_color=[0.0, 0.0, 0.0, 0.0], label="Exploded Object")
184
  xpart_seed = gr.Number(value=42, label="Random Seed")
185
  gr_state = gr.State(value=[(None, None)])
186
- p3sam_button.click(segment, inputs=[p3sam_input, p3sam_conectivity, p3sam_postprocess, p3sam_postprocess_threshold, p3sam_seed], outputs=[p3sam_output, p3sam_face_id_output, gr_state])
187
  xpart_button.click(generate, inputs=[p3sam_input, xpart_seed, gr_state], outputs=[xpart_output, xpart_output_bbox, xpart_output_exploded])
188
 
189
 
 
11
 
12
  sys.path.append('P3-SAM')
13
  from demo.auto_mask import AutoMask
 
14
  sys.path.append('XPart')
15
  from partgen.partformer_pipeline import PartFormerPipeline
16
  from partgen.utils.misc import get_config_from_file
17
 
18
  automask = AutoMask()
 
19
 
20
  def _load_pipeline():
21
  pl.seed_everything(2026, workers=True)
 
39
  output_path = 'P3-SAM/results/gradio'
40
  os.makedirs(output_path, exist_ok=True)
41
 
42
+ def is_supported_3d_file(filename):
43
+ # 获取文件扩展名(小写),并去除开头的点
44
+ ext = os.path.splitext(filename)[1].lower()
45
+ return ext in ['.glb', '.ply', '.obj']
46
+
47
  @spaces.GPU
48
+ def segment(mesh_path, postprocess=True, postprocess_threshold=0.95, seed=42):
49
  if mesh_path is None:
50
  gr.Warning("No Input Mesh")
51
+ return None, None
52
+ if not is_supported_3d_file(mesh_path):
53
+ gr.Warning("Only support glb ply obj.")
54
  return None, None
55
  mesh = trimesh.load(mesh_path, force='mesh', process=False)
56
+ aabb, face_ids, mesh = automask.predict_aabb(mesh, seed=seed, is_parallel=False, post_process=postprocess, threshold=postprocess_threshold)
 
 
 
57
  color_map = {}
58
  unique_ids = np.unique(face_ids)
59
  for i in unique_ids:
 
78
  gr_state = [(aabb, mesh_path)]
79
  return file_path, face_id_save_path, gr_state
80
 
81
+ @spaces.GPU(duration=150)
82
  def generate(mesh_path, seed=42, gr_state=None):
83
  if mesh_path is None:
84
  gr.Warning("No Input Mesh")
 
116
  # ☯️ Hunyuan3D Part:P3-SAM&XPart
117
  This demo allows you to generate parts given a 3D model using Hunyuan3D-Part.
118
  First segment the 3D model using P3-SAM and then generate parts using XPart.
119
+ Please upload glb ply or obj 3D model files.
120
  '''
121
  )
122
  with gr.Row():
 
136
  p3sam_input = gr.Model3D(clear_color=[0.0, 0.0, 0.0, 0.0], label="Input Mesh")
137
  p3sam_output = gr.Model3D(clear_color=[0.0, 0.0, 0.0, 0.0], label="Segmentation Result")
138
  p3sam_face_id_output = gr.File(label='Face ID')
 
139
  p3sam_postprocess = gr.Checkbox(value=True, label="Post-processing")
140
  p3sam_postprocess_threshold = gr.Number(value=0.95, label="Post-processing Threshold")
141
  p3sam_seed = gr.Number(value=42, label="Random Seed")
 
185
  xpart_output_exploded = gr.Model3D(clear_color=[0.0, 0.0, 0.0, 0.0], label="Exploded Object")
186
  xpart_seed = gr.Number(value=42, label="Random Seed")
187
  gr_state = gr.State(value=[(None, None)])
188
+ p3sam_button.click(segment, inputs=[p3sam_input, p3sam_postprocess, p3sam_postprocess_threshold, p3sam_seed], outputs=[p3sam_output, p3sam_face_id_output, gr_state])
189
  xpart_button.click(generate, inputs=[p3sam_input, xpart_seed, gr_state], outputs=[xpart_output, xpart_output_bbox, xpart_output_exploded])
190
 
191