MorPhLingXD commited on
Commit
86ef168
·
1 Parent(s): d07a311

Update files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitignore +5 -1
  2. README.md +176 -10
  3. TRELLIS/trellis/pipelines/trellis_image_to_3d.py +1 -4
  4. TRELLIS/trellis/utils/postprocessing_utils.py +15 -6
  5. add_disk.py +2 -2
  6. app.py +371 -357
  7. assets/disk.png +2 -2
  8. assets/teaser.png +2 -2
  9. configs/default.yaml +20 -3
  10. configs/partnet_target.json +1 -1
  11. datasets/PartNet/100214/02_pure.png +0 -3
  12. datasets/PartNet/100214/02_seg.png +0 -3
  13. datasets/PartNet/100214/03_pure.png +0 -3
  14. datasets/PartNet/100214/03_seg.png +0 -3
  15. datasets/PartNet/100214/04_pure.png +0 -3
  16. datasets/PartNet/100214/04_seg.png +0 -3
  17. datasets/PartNet/100214/05_pure.png +0 -3
  18. datasets/PartNet/100214/05_seg.png +0 -3
  19. datasets/PartNet/100214/gt_mesh/00.glb +0 -3
  20. datasets/PartNet/100214/gt_mesh/01.glb +0 -3
  21. datasets/PartNet/100214/gt_mesh/02.glb +0 -3
  22. datasets/PartNet/100214/gt_mesh/03.glb +0 -3
  23. datasets/PartNet/100214/gt_mesh/04.glb +0 -3
  24. datasets/PartNet/100214/gt_mesh/05.glb +0 -3
  25. datasets/PartNet/100214/joint_info.json +0 -21
  26. datasets/PartNet/100214/joints.json +0 -16
  27. datasets/PartNet/100214/mobility.urdf +0 -470
  28. datasets/PartNet/100350/00_pure.png +0 -3
  29. datasets/PartNet/100350/00_seg.png +0 -3
  30. datasets/PartNet/100350/01_pure.png +0 -3
  31. datasets/PartNet/100350/01_seg.png +0 -3
  32. datasets/PartNet/100350/02_pure.png +0 -3
  33. datasets/PartNet/100350/02_seg.png +0 -3
  34. datasets/PartNet/100350/03_pure.png +0 -3
  35. datasets/PartNet/100350/03_seg.png +0 -3
  36. datasets/PartNet/100350/04_pure.png +0 -3
  37. datasets/PartNet/100350/04_seg.png +0 -3
  38. datasets/PartNet/100350/05_pure.png +0 -3
  39. datasets/PartNet/100350/05_seg.png +0 -3
  40. datasets/PartNet/100350/gt_mesh/00.glb +0 -3
  41. datasets/PartNet/100350/gt_mesh/01.glb +0 -3
  42. datasets/PartNet/100350/gt_mesh/02.glb +0 -3
  43. datasets/PartNet/100350/gt_mesh/03.glb +0 -3
  44. datasets/PartNet/100350/gt_mesh/04.glb +0 -3
  45. datasets/PartNet/100350/gt_mesh/05.glb +0 -3
  46. datasets/PartNet/100350/joint_info.json +0 -21
  47. datasets/PartNet/100350/joints.json +0 -14
  48. datasets/PartNet/100350/mobility.urdf +0 -904
  49. datasets/PartNet/101363/00_pure.png +0 -3
  50. datasets/PartNet/101363/00_seg.png +0 -3
.gitignore CHANGED
@@ -3,7 +3,11 @@
3
  *.pth
4
  *.ckpt
5
 
 
 
 
6
  tmp/
7
- debug/
 
8
  outputs/
9
  evaluations/
 
3
  *.pth
4
  *.ckpt
5
 
6
+ **/__pycache__/
7
+ .gradio/
8
+
9
  tmp/
10
+ debug/
11
+ datasets/PartNet
12
  outputs/
13
  evaluations/
README.md CHANGED
@@ -1,10 +1,176 @@
1
- ---
2
- title: FreeArt3D
3
- emoji: 🧩
4
- colorFrom: blue
5
- colorTo: purple
6
- sdk: gradio
7
- sdk_version: "5.34.2"
8
- app_file: app.py
9
- pinned: false
10
- ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <h1 align="center">FreeArt3D: Training-Free Articulated Object Generation using 3D Diffusion</h1>
2
+ <h3 align="center">SIGGRAPH Asia 2025</h3>
3
+
4
+ <p align="center"><a href="https://czzzzh.github.io/FreeArt3D/FreeArt3D.pdf"><img src='https://img.shields.io/badge/arXiv-Paper-red?logo=arxiv&logoColor=white' alt='arXiv'></a>
5
+ <a href="https://czzzzh.github.io/FreeArt3D"><img src='https://img.shields.io/badge/Project_Page-Website-green?logo=googlechrome&logoColor=white' alt='Project Page'></a>
6
+ <a href="https://huggingface.co/spaces/MorPhLingXD/FreeArt3D"><img src='https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Live_Demo-blue'></a>
7
+ </p>
8
+
9
+
10
+ Official Implementation for ***FreeArt3D: Training-Free Articulated Object Generation using 3D Diffusion***
11
+
12
+ <p align="center"><img src="assets/teaser.png" width="100%"></p>
13
+
14
+
15
+
16
+ ## 🔔 Updates
17
+ [10/29/2025] We released our code, dataset and results!
18
+
19
+
20
+
21
+
22
+ ## 🚧 TODO List
23
+ - [ ] Release test data on Objaverse dataset
24
+
25
+
26
+
27
+ ## 🚀 Quick Start
28
+ 1. Setup the environment
29
+
30
+ ```bash
31
+ conda create -n fa3d python=3.10
32
+ conda activate fa3d
33
+ bash setup.sh
34
+ ```
35
+
36
+ **Note:** If you need to use different torch or cudatoolkit version (for correctly building other libraries), please also install the compatible version of [kaolin](https://github.com/NVIDIAGameWorks/kaolin)
37
+
38
+ 2. Download the checkpoint of [GIM-DKM](https://github.com/xuelunshen/gim) from [Google Drive](https://drive.google.com/file/d/1iYmEctoA-a3sds9VQPwVJIJbs0v6oztb/view?usp=sharing), and put it to `gim/weights`
39
+
40
+ 3. Generate the articulated **cabinet** from the input images in `examples/cabinet`
41
+
42
+ ```bash
43
+ python run_two_parts.py
44
+ ```
45
+
46
+ ​ Then check `outputs/cabinet/sds_output/part_meshes` and `outputs/cabinet/sds_output/states` for the articulated mesh results!
47
+
48
+ ​ You can also check `outputs/cabinet/output.urdf` for the **URDF** format output, and we provide a script to parse it in `pipelines/urdf.py`
49
+
50
+ 4. Try other examples by simply changing the input directory and the joint type.
51
+
52
+ ```bash
53
+ python run_two_parts.py --input_dir examples/cabinet2 --joint_type revolute
54
+ python run_two_parts.py --input_dir examples/cabinet3
55
+ ```
56
+
57
+
58
+
59
+
60
+
61
+ ## 💻 PartNet-Mobility Articulation
62
+
63
+ 1. Download the **preprocessed PartNet-Mobility dataset** from [Google Drive](https://drive.google.com/file/d/1MGvp_Sm7lkn87ZXH3I1uSGNTJ_-hD4eA/view?usp=drive_link) (including **144** objects in **12** categories, the objects have been rendered with disks) and put it to the `datasets` directory. The folder structure should be
64
+
65
+ ```bash
66
+ FreeArt3D
67
+ |--datasets
68
+ |-- PartNet
69
+ |-- 100214
70
+ └-- ...
71
+ ```
72
+
73
+ 2. Then run the same script with specified input directory and the PartNet option
74
+
75
+ ```bash
76
+ python run_two_parts.py --input_dir datasets/PartNet/100214 --partnet # You can use any other object id included in the dataset
77
+ ```
78
+
79
+ 3. *(Optional)* Evaluate the metric of results
80
+
81
+ We provide the script to evaluate different metrics for the PartNet-Mobility results. Note that this is a general evaluation script so you can use it to evaluate other objects if you have ground-truth for them (simply changing the **test_id**)
82
+
83
+ ```bash
84
+ python evaluate_partnet.py --test_id 100214
85
+ ```
86
+
87
+ 4. *(Optional)* Preprocess the PartNet-Mobility dataset
88
+
89
+ If you want to test our method on the objects **not in** our processed dataset, you can use the following scripts the process meshes from the [original PartNet-Mobility dataset](https://sapien.ucsd.edu/downloads). Note that you need to manually filter out the joints you want to use. You can check `configs/partnet_target.json` and `partnet.json` for the format. Here we provide the steps to **preprocess** and **render** the objects according to the object ids in `partnet.json`
90
+
91
+ ```bash
92
+ python preprocess_partnet_joint.py
93
+ blenderproc run preprocess_partnet_mesh.py
94
+ python render_partnet_mesh.py
95
+ ```
96
+
97
+ The scripts will generate **.glb** meshes at different qpos in `datasets/PartNet/{$test_id}/gt_mesh` and the renderings **with** **disk** in `datasets/PartNet/{$test_id}`, which is the same as the ones in the downloaded preprocessed dataset.
98
+
99
+ 5. *(Optional)* Download the PartNet-Mobility results
100
+
101
+ We provide the [PartNet-Mobility results](https://drive.google.com/drive/folders/1cthxRlejeTbU3AJC0OmRBeBx0pQr6gef?usp=sharing) run at our end with our latest version of the code for reference. The results are reproducible with the code, but you might get results with minor difference (we have fixed the random seed but some CUDA implementations (e.g. [tiny-cuda-nn](https://github.com/NVlabs/tiny-cuda-nn)) are non-deterministic)
102
+
103
+
104
+
105
+ ## 🚪 Multi-joint Articulation
106
+
107
+ 1. Download the **processed multi-joint dataset** from [Google Drive](https://drive.google.com/file/d/1-Bl5X5XahyMzY9NvrMqsVUzCYthzU11w/view?usp=drive_link) (the objects have been rendered with disks for **each joint**) and put it to the `datasets`directory. The folder structure should be
108
+
109
+ ```bash
110
+ FreeArt3D
111
+ |--datasets
112
+ |-- multi-joint
113
+ |-- 46180
114
+ |-- ...
115
+ └-- meta.json
116
+ ```
117
+
118
+ **Note:** This small dataset includes objects from both **PartNet-Mobility** and **Objaverse**. A meta file records the types of joints for each object.
119
+
120
+ 2. Run the script for multi-joint articulation
121
+
122
+ ```bash
123
+ python run_multi_parts.py --input_dir datasets/multi_joint/46180 # You can use any other object id included in the dataset
124
+ ```
125
+
126
+
127
+
128
+ ## 🌟 Use your own images
129
+
130
+ If you want to use your own images, you need to segment them first using tools such as SAM. Here is a [webtool](https://huggingface.co/spaces/Xenova/segment-anything-webgpu) you can refer to
131
+
132
+ <img src="assets\sam.png" alt="sam" style="zoom: 33%;" />
133
+
134
+ After segmentation, if your image wasn't segmented out with a **"carpet"**, you can manually add a **virtual disk** with a GUI tool we provided
135
+
136
+ ```bash
137
+ python add_disk.py --input_dir examples/cabinet3_no_disk
138
+ ```
139
+
140
+ This tool can help you add a virtual disk for every input image efficiently. It also supports rescaling the objects to a suitable size for better articulation.
141
+
142
+
143
+
144
+
145
+ ## 🤗 Demo
146
+ We have deployed our live demo at [huggingface space](https://huggingface.co/spaces/MorPhLingXD/FreeArt3D). However, due to the long running time of our method, it's also recommended running the demo on your local machine:
147
+
148
+ ```bash
149
+ python app.py
150
+ ```
151
+
152
+
153
+
154
+ ## 🍀 Acknowledgement
155
+
156
+ We acknowledge the following repositories for borrowing the codes:
157
+
158
+ **TRELLIS:** https://github.com/microsoft/TRELLIS
159
+
160
+ **GIM:** https://github.com/xuelunshen/gim
161
+
162
+
163
+
164
+ ## 📜 Citation
165
+
166
+ If you find this repository useful in your project, welcome to cite our work :)
167
+
168
+ ```
169
+ [BibTex]
170
+ @InProceedings{chen2025freeart3d,
171
+ title = {FreeArt3D: Training-Free Articulated Object Generation using 3D Diffusion},
172
+ author = {Chen, Chuhao and Liu, Isabella and Wei, Xinyue and Su, Hao and Liu, Minghua},
173
+ booktitle = {SIGGRAPH Asia 2025 Conference Papers},
174
+ year = {2025}
175
+ }
176
+ ```
TRELLIS/trellis/pipelines/trellis_image_to_3d.py CHANGED
@@ -346,10 +346,7 @@ class TrellisImageTo3DPipeline(Pipeline):
346
 
347
  # Decode occupancy latent
348
  decoder = self.models['sparse_structure_decoder']
349
- decoded = decoder(z_s)
350
-
351
- # visualize_dense_voxels(noise[0].permute(1, 2, 3, 0)[..., :3], 16, 'noise_low')
352
- # visualize_dense_voxels(z_s[0].permute(1, 2, 3, 0)[..., :3], 16, 'denoised_low')
353
  coords = torch.argwhere(decoded > 0)[:, [0, 2, 3, 4]].int()
354
  return coords
355
 
 
346
 
347
  # Decode occupancy latent
348
  decoder = self.models['sparse_structure_decoder']
349
+ decoded = decoder(z_s)
 
 
 
350
  coords = torch.argwhere(decoded > 0)[:, [0, 2, 3, 4]].int()
351
  return coords
352
 
TRELLIS/trellis/utils/postprocessing_utils.py CHANGED
@@ -318,22 +318,30 @@ def bake_texture(
318
  texture = torch.zeros((texture_size * texture_size, 3), dtype=torch.float32).cuda()
319
  texture_weights = torch.zeros((texture_size * texture_size), dtype=torch.float32).cuda()
320
  rastctx = utils3d.torch.RastContext(backend='cuda')
 
 
321
  for observation, view, projection in tqdm(zip(observations, views, projections), total=len(observations), disable=not verbose, desc='Texture baking (fast)'):
322
- with torch.no_grad():
 
323
  rast = utils3d.torch.rasterize_triangle_faces(
324
  rastctx, vertices[None], faces, observation.shape[1], observation.shape[0], uv=uvs[None], view=view, projection=projection
325
  )
326
  uv_map = rast['uv'][0].detach().flip(0)
327
  mask = rast['mask'][0].detach().bool() & masks[0]
328
 
329
- # nearest neighbor interpolation
330
  uv_map = (uv_map * texture_size).floor().long()
331
  obs = observation[mask]
332
  uv_map = uv_map[mask]
333
  idx = uv_map[:, 0] + (texture_size - uv_map[:, 1] - 1) * texture_size
 
 
 
 
 
334
  texture = texture.scatter_add(0, idx.view(-1, 1).expand(-1, 3), obs)
335
  texture_weights = texture_weights.scatter_add(0, idx, torch.ones((obs.shape[0]), dtype=torch.float32, device=texture.device))
336
-
337
  mask = texture_weights > 0
338
  texture[mask] /= texture_weights[mask][:, None]
339
  texture = np.clip(texture.reshape(texture_size, texture_size, 3).cpu().numpy() * 255, 0, 255).astype(np.uint8)
@@ -404,6 +412,7 @@ def to_glb(
404
  fill_holes_max_size: float = 0.04,
405
  texture_size: int = 1024,
406
  debug: bool = False,
 
407
  verbose: bool = True,
408
  ) -> trimesh.Trimesh:
409
  """
@@ -443,15 +452,15 @@ def to_glb(
443
  observations, extrinsics, intrinsics = render_multiview(app_rep, resolution=1024, nviews=100)
444
  masks = [np.any(observation > 0, axis=-1) for observation in observations]
445
  extrinsics = [extrinsics[i].cpu().numpy() for i in range(len(extrinsics))]
446
- intrinsics = [intrinsics[i].cpu().numpy() for i in range(len(intrinsics))]
447
  texture = bake_texture(
448
  vertices, faces, uvs,
449
  observations, masks, extrinsics, intrinsics,
450
- texture_size=texture_size, mode='opt',
451
  lambda_tv=0.01,
452
  verbose=verbose
453
  )
454
- texture = Image.fromarray(texture)
455
 
456
  # rotate mesh (from z-up to y-up)
457
  vertices = vertices @ np.array([[1, 0, 0], [0, 0, -1], [0, 1, 0]])
 
318
  texture = torch.zeros((texture_size * texture_size, 3), dtype=torch.float32).cuda()
319
  texture_weights = torch.zeros((texture_size * texture_size), dtype=torch.float32).cuda()
320
  rastctx = utils3d.torch.RastContext(backend='cuda')
321
+
322
+ i = 0
323
  for observation, view, projection in tqdm(zip(observations, views, projections), total=len(observations), disable=not verbose, desc='Texture baking (fast)'):
324
+
325
+ with torch.no_grad():
326
  rast = utils3d.torch.rasterize_triangle_faces(
327
  rastctx, vertices[None], faces, observation.shape[1], observation.shape[0], uv=uvs[None], view=view, projection=projection
328
  )
329
  uv_map = rast['uv'][0].detach().flip(0)
330
  mask = rast['mask'][0].detach().bool() & masks[0]
331
 
332
+ # nearest neighbor interpolation
333
  uv_map = (uv_map * texture_size).floor().long()
334
  obs = observation[mask]
335
  uv_map = uv_map[mask]
336
  idx = uv_map[:, 0] + (texture_size - uv_map[:, 1] - 1) * texture_size
337
+
338
+ # Fix a bug that some indices are out of range
339
+ idx_mask = idx < texture_size * texture_size
340
+ idx = idx[idx_mask]
341
+ obs = obs[idx_mask]
342
  texture = texture.scatter_add(0, idx.view(-1, 1).expand(-1, 3), obs)
343
  texture_weights = texture_weights.scatter_add(0, idx, torch.ones((obs.shape[0]), dtype=torch.float32, device=texture.device))
344
+
345
  mask = texture_weights > 0
346
  texture[mask] /= texture_weights[mask][:, None]
347
  texture = np.clip(texture.reshape(texture_size, texture_size, 3).cpu().numpy() * 255, 0, 255).astype(np.uint8)
 
412
  fill_holes_max_size: float = 0.04,
413
  texture_size: int = 1024,
414
  debug: bool = False,
415
+ baking_mode: Literal['fast', 'opt'] = 'opt',
416
  verbose: bool = True,
417
  ) -> trimesh.Trimesh:
418
  """
 
452
  observations, extrinsics, intrinsics = render_multiview(app_rep, resolution=1024, nviews=100)
453
  masks = [np.any(observation > 0, axis=-1) for observation in observations]
454
  extrinsics = [extrinsics[i].cpu().numpy() for i in range(len(extrinsics))]
455
+ intrinsics = [intrinsics[i].cpu().numpy() for i in range(len(intrinsics))]
456
  texture = bake_texture(
457
  vertices, faces, uvs,
458
  observations, masks, extrinsics, intrinsics,
459
+ texture_size=texture_size, mode=baking_mode,
460
  lambda_tv=0.01,
461
  verbose=verbose
462
  )
463
+ texture = Image.fromarray(texture)
464
 
465
  # rotate mesh (from z-up to y-up)
466
  vertices = vertices @ np.array([[1, 0, 0], [0, 0, -1], [0, 1, 0]])
add_disk.py CHANGED
@@ -212,13 +212,13 @@ class EditorApp:
212
  print(f"Failed: {fg_path} -> {e}", file=sys.stderr)
213
  fail += 1
214
 
215
- messagebox.showinfo("Batch Done", f"Saved {ok} image(s) to {output_dir}. {fail} failed.")
216
 
217
  def main():
218
 
219
  parser = argparse.ArgumentParser()
220
  parser.add_argument('--disk_path', type=str, default='assets/disk.png')
221
- parser.add_argument('--input_dir', type=str, default='examples/cabinet4_no_disk')
222
  args = parser.parse_args()
223
 
224
  bg_path = args.disk_path
 
212
  print(f"Failed: {fg_path} -> {e}", file=sys.stderr)
213
  fail += 1
214
 
215
+ messagebox.showinfo("Batch Done", f"Saved {ok} image(s) to {output_dir}")
216
 
217
  def main():
218
 
219
  parser = argparse.ArgumentParser()
220
  parser.add_argument('--disk_path', type=str, default='assets/disk.png')
221
+ parser.add_argument('--input_dir', type=str, default='examples/cabinet3_no_disk')
222
  args = parser.parse_args()
223
 
224
  bg_path = args.disk_path
app.py CHANGED
@@ -1,89 +1,65 @@
1
  import os
2
  import shutil
3
- import json
4
- import numpy as np
5
- import subprocess
6
  import gradio as gr
7
  import spaces
8
-
9
- from huggingface_hub import snapshot_download
10
  from gradio_litmodel3d import LitModel3D
 
 
 
 
11
  from typing import *
12
  from omegaconf import OmegaConf
13
 
14
- LOCAL_RUN = True
15
- if not LOCAL_RUN:
16
- subprocess.run(["bash", "setup.sh"], check=True)
17
-
18
  partnet_dir = f'datasets/PartNet'
19
  real_world_dir = f'examples'
20
  multi_joint_dir = f'datasets/multi_joint'
21
-
22
  with open(f"configs/partnet.json") as f:
23
  data_info = json.load(f)
24
- cfg = OmegaConf.load('configs/default.yaml')
25
-
26
- # Ensure datasets/PartNet is available when running on Spaces (or locally if missing)
27
- def _ensure_partnet_dataset():
28
-
29
- if os.path.isdir(partnet_dir) and len(os.listdir(partnet_dir)) > 0:
30
- return
31
- HF_TOKEN = os.getenv("HF_TOKEN")
32
- snapshot_download(
33
- repo_id="MorPhLingXD/FreeArt3D",
34
- repo_type="dataset",
35
- local_dir="datasets",
36
- token=HF_TOKEN,
37
- )
38
-
39
- _ensure_partnet_dataset()
40
 
41
  labels = {
42
  'Cabinet (real-world)': 'cabinet',
43
  'Cabinet2 (real-world)': 'cabinet2',
44
- 'Box (100214)': '100214',
45
  'Dishwasher (12614)': '12614',
46
- 'Laptop (11405)': '11405',
47
- 'Lighter (100350)': '100350',
48
- 'Microwave (7263)': '7263',
49
- 'Oven (102044)': '102044',
50
- 'Refrigerator (10655)': '10655',
51
- 'Safe (101363)': '101363',
52
- 'Stapler (103299)': '103299',
53
  'StorageFurniture (47183)': '47183',
54
- 'Table (22301)': '22301',
55
- 'WashingMachine (103775)': '103775',
56
  }
57
-
58
- MAX_SEED = np.iinfo(np.int32).max
59
  TMP_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tmp')
60
  os.makedirs(TMP_DIR, exist_ok=True)
61
-
62
- def _clear_3d():
63
- return (gr.update(value=None), gr.update(value=None), gr.update(value=None))
64
-
65
- def start_session(req: gr.Request):
66
- user_dir = os.path.join(TMP_DIR, str(req.session_hash))
67
- os.makedirs(user_dir, exist_ok=True)
68
 
69
  def end_session(req: gr.Request):
70
- user_dir = os.path.join(TMP_DIR, str(req.session_hash))
71
- shutil.rmtree(user_dir, ignore_errors=True)
72
 
73
  def get_available_ids():
74
  """Get list of available object IDs for the dropdown"""
75
- # real_world_ids = ['cabinet', 'cabinet2', 'cabinet3']
76
- # # multi_joint_ids = [filename for filename in os.listdir(multi_joint_dir) if \
77
- # # os.path.isdir(os.path.join(multi_joint_dir, filename))]
78
- # partnet_mobility_ids = list(data_info['total_obj_ids'])
79
- # # total_list = real_world_ids + multi_joint_ids + partnet_mobility_ids
80
- # total_list = real_world_ids + partnet_mobility_ids # TODO: Support multi-joints
81
  total_list = list(labels.keys())
82
  return total_list
83
 
84
- def load_renderings_with_id(id_input: str) -> Tuple[List[str], str]:
85
 
86
  selected_id = labels[id_input]
 
 
 
87
  rendering_paths = []
88
  if 'cabinet' in selected_id:
89
  base_dir = real_world_dir
@@ -91,6 +67,7 @@ def load_renderings_with_id(id_input: str) -> Tuple[List[str], str]:
91
  base_dir = partnet_dir
92
  else:
93
  base_dir = multi_joint_dir
 
94
  for i in range(cfg.train_num_state):
95
  rendering_paths.append(f'{base_dir}/{selected_id}/{i:02d}_seg.png')
96
  return rendering_paths, selected_id
@@ -100,6 +77,7 @@ def handle_mesh_upload(files):
100
  if not files or len(files) == 0:
101
  return gr.Dropdown(choices=[], value=None), None
102
  choices = [f"Mesh State {i:02d} - {os.path.basename(file.name)}" for i, file in enumerate(files)]
 
103
  return gr.Dropdown(choices=choices, value=choices[0] if choices else None), files[0].name
104
 
105
  def switch_mesh_view(selected_file, files):
@@ -124,66 +102,118 @@ def switch_mesh_view(selected_file, files):
124
 
125
  return None
126
 
127
- def process_and_update_gallery(mesh_files, mesh_source_flag, current_gallery):
128
  mesh_paths = [f.name for f in mesh_files] if mesh_files else []
129
  cfg.train_num_state = len(mesh_paths)
130
- from pipelines.render import run_rendering
131
- rendering_paths = run_rendering(mesh_paths, output_dir=TMP_DIR)
132
- # rendering_paths is assumed to be a list of image file paths
133
- if not rendering_paths:
134
- return current_gallery or []
135
- if current_gallery:
136
- return current_gallery + rendering_paths
137
  return rendering_paths
138
 
139
- def handle_image_gallery_upload(gallery_value, req: gr.Request):
140
- """Normalize directly uploaded images in the Gallery by saving them to a per-session folder
141
- and returning entries that point to stable file paths compatible with downstream processing.
142
- """
143
- try:
144
- session_dir = os.path.join(TMP_DIR, str(req.session_hash), 'uploaded_images')
145
- except Exception:
146
- session_dir = os.path.join(TMP_DIR, 'uploaded_images')
147
- os.makedirs(session_dir, exist_ok=True)
148
-
149
- normalized_items = []
150
- if not gallery_value:
151
- return []
152
-
153
- for idx, item in enumerate(gallery_value):
154
- candidate = item
155
- if isinstance(item, (list, tuple)) and len(item) > 0:
156
- candidate = item[0]
157
-
158
- saved_path = None
159
- if isinstance(candidate, str) and os.path.exists(candidate):
160
- # Copy to per-session folder for stability and cache isolation
161
- base = os.path.basename(candidate)
162
- stem, ext = os.path.splitext(base)
163
- dest = os.path.join(session_dir, f"{stem}_{idx:02d}{ext or '.png'}")
164
  try:
165
- if os.path.abspath(candidate) != os.path.abspath(dest):
166
- shutil.copy(candidate, dest)
167
- else:
168
- dest = candidate
169
- saved_path = dest
170
  except Exception:
171
- saved_path = candidate
172
- else:
173
- # Unrecognized type; keep as-is
174
- saved_path = None
175
-
176
- if saved_path is not None:
177
- normalized_items.append([saved_path, None])
178
- else:
179
- normalized_items.append(item)
180
 
181
- return normalized_items
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
 
183
- def save_gallery_to_renderings(gallery_value, selected_id):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  """Persist gallery images into outputs/<selected_id>/renderings with SDS-expected names.
185
  Ensures there are cfg.train_num_state frames by padding with the last image if needed.
186
- Also writes the required 'renderings_pure_joint_00_state_{T-1}.png' using the last frame.
187
  """
188
  try:
189
  image_paths = []
@@ -196,160 +226,50 @@ def save_gallery_to_renderings(gallery_value, selected_id):
196
  return
197
 
198
  cfg.train_num_state = len(image_paths)
199
- base_dir = f'outputs/{selected_id}'
200
  if "uploaded" in base_dir:
201
  os.system(f"rm -rf {base_dir}/*")
 
202
  rendering_dir = f'{base_dir}/renderings'
203
  os.makedirs(rendering_dir, exist_ok=True)
204
 
205
  # Normalize count to T frames
206
  for i in range(cfg.train_num_state):
207
  src = image_paths[i] if i < len(image_paths) else image_paths[-1]
208
- dst = f'{rendering_dir}/renderings_joint_00_state_{i:02d}.png'
209
  shutil.copy(src, dst)
210
 
211
  # Write the 'pure' image as the last uploaded (or last padded) frame
212
- pure_src = image_paths[-1]
213
- pure_dst = f'{rendering_dir}/renderings_pure_joint_00_state_{(cfg.train_num_state - 1):02d}.png'
 
 
 
214
  shutil.copy(pure_src, pure_dst)
215
  except Exception as e:
216
  print(f"[Gallery->Renderings] Failed to persist images: {e}")
217
  return
218
 
219
- @spaces.GPU(duration=300)
220
- def recon_trellis_meshes(input_image_gallery, selected_id):
 
 
 
221
  # Carefully extract file paths from Gradio Gallery elements, which may be dicts, file objects, or strings.
222
  image_paths = [img[0] for img in input_image_gallery]
223
- from pipelines.recon import run_recon
224
- recon_voxel_paths, recon_mesh_paths = run_recon(image_paths, output_dir=f"outputs/{selected_id}/recon")
225
- return recon_voxel_paths, recon_mesh_paths
226
-
227
- @spaces.GPU(duration=180)
228
- def estimate_initial_joints(input_image_gallery, selected_id, joint_type_user):
229
- image_paths = [img[0] for img in input_image_gallery]
230
- if isinstance(joint_type_user, str) and joint_type_user in ("revolute", "prismatic"):
231
- joint_type = joint_type_user
232
- else:
233
- joint_type = 'prismatic' if (selected_id in data_info['prismatic']['obj_ids']) else 'revolute'
234
- from pipelines.estimate import run_estimate
235
- matching_examples, info_dict = run_estimate(image_paths, output_dir=f"outputs/{selected_id}",
236
- joint_type=joint_type)
237
  return matching_examples, info_dict
238
 
239
- def meta_to_fields_ui(info_dict):
240
- """Convert meta info dict to UI field values (textboxes x/y/z, slider)."""
241
- def to_str(v):
242
- if isinstance(v, np.ndarray):
243
- v = v.tolist()
244
- if isinstance(v, (list, dict, tuple)):
245
- try:
246
- return json.dumps(v)
247
- except Exception:
248
- return str(v)
249
- return "" if v is None else str(v)
250
-
251
- # Extract axis components
252
- axis_val = info_dict.get("joint_axis", "")
253
- if isinstance(axis_val, np.ndarray):
254
- axis_val = axis_val.tolist()
255
- if isinstance(axis_val, (list, tuple)) and len(axis_val) >= 3:
256
- ax_x, ax_y, ax_z = axis_val[0], axis_val[1], axis_val[2]
257
- else:
258
- ax_x = ax_y = ax_z = ""
259
- ax_x_str = to_str(ax_x)
260
- ax_y_str = to_str(ax_y)
261
- ax_z_str = to_str(ax_z)
262
-
263
- # Extract position components
264
- pos_val = info_dict.get("joint_position", "")
265
- if isinstance(pos_val, np.ndarray):
266
- pos_val = pos_val.tolist()
267
- if isinstance(pos_val, (list, tuple)) and len(pos_val) >= 3:
268
- px, py, pz = pos_val[0], pos_val[1], pos_val[2]
269
- else:
270
- px = py = pz = ""
271
- px_str = to_str(px)
272
- py_str = to_str(py)
273
- pz_str = to_str(pz)
274
-
275
- # Extract scalar scale value for slider
276
- scale_val = -info_dict.get("joint_scale", 1.0)
277
- qpos_str = to_str(info_dict.get("joint_qpos", ""))
278
-
279
- return (
280
- ax_x_str,
281
- ax_y_str,
282
- ax_z_str,
283
- px_str,
284
- py_str,
285
- pz_str,
286
- scale_val,
287
- qpos_str,
288
- )
289
-
290
- def fields_to_meta_ui(
291
- axis_x: str,
292
- axis_y: str,
293
- axis_z: str,
294
- pos_x: str,
295
- pos_y: str,
296
- pos_z: str,
297
- scale_value: float,
298
- joint_qpos: str,
299
- ):
300
- """Convert new UI fields (x/y/z textboxes, slider) to meta info dict."""
301
- def parse_float(text: Any):
302
- try:
303
- return float(text)
304
- except Exception:
305
- return None
306
-
307
- def parse_val(text: str):
308
- if text is None:
309
- return ""
310
- t = str(text).strip()
311
- if t == "":
312
- return ""
313
- try:
314
- return json.loads(t)
315
- except Exception:
316
- if "," in t:
317
- parts = [p.strip() for p in t.split(",")]
318
- try:
319
- return [float(p) for p in parts]
320
- except Exception:
321
- return parts
322
- try:
323
- return float(t)
324
- except Exception:
325
- return t
326
-
327
- axis_vals = [parse_float(axis_x), parse_float(axis_y), parse_float(axis_z)]
328
- if all(v is not None for v in axis_vals):
329
- joint_axis = axis_vals
330
- else:
331
- joint_axis = ""
332
-
333
- pos_vals = [parse_float(pos_x), parse_float(pos_y), parse_float(pos_z)]
334
- if all(v is not None for v in pos_vals):
335
- joint_position = pos_vals
336
- else:
337
- joint_position = ""
338
-
339
- try:
340
- joint_scale = -float(scale_value)
341
- except Exception:
342
- joint_scale = -1.0
343
-
344
- return {
345
- "joint_axis": joint_axis,
346
- "joint_position": joint_position,
347
- "joint_scale": joint_scale,
348
- "joint_qpos": parse_val(joint_qpos),
349
- }
350
-
351
- @spaces.GPU(duration=600)
352
- def articulated_generation_sds(selected_id):
353
 
354
  if 'cabinet' in selected_id:
355
  input_dir = real_world_dir
@@ -358,19 +278,122 @@ def articulated_generation_sds(selected_id):
358
  else:
359
  input_dir = multi_joint_dir
360
 
361
- base_dir = f'outputs/{selected_id}'
362
  rendering_dir = f'{base_dir}/renderings'
363
 
364
  os.makedirs(rendering_dir, exist_ok=True)
365
  if os.path.exists(f'{input_dir}/{selected_id}/05_seg.png'):
366
  for i in range(6):
367
- shutil.copy(f'{input_dir}/{selected_id}/{i:02d}_seg.png', f'{rendering_dir}/renderings_joint_00_state_{i:02d}.png')
368
- shutil.copy(f'{input_dir}/{selected_id}/05_pure.png', f'{rendering_dir}/renderings_pure_joint_00_state_05.png')
369
-
370
- from pipelines.sds import run_sds
371
  full_mesh, fixed_part, articulated_part = run_sds(base_dir, 1, cfg)
372
  return full_mesh, fixed_part, articulated_part
373
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374
  with gr.Blocks(delete_cache=(600, 600), css="""
375
  .gallery-container {
376
  overflow-x: auto !important;
@@ -416,22 +439,25 @@ with gr.Blocks(delete_cache=(600, 600), css="""
416
  gr.Markdown("""
417
  ## FreeArt3D Demo
418
  ### You can use the following three methods to generate articulated 3D models.
419
- 1. Choose a PartNet-Mobility object ID and click "Submit ObjectID" to load the pre-rendered input images.
420
- 2. Upload multiple mesh files (e.g., .obj, .ply, .stl, .glb, .gltf) and render the input images with the disk.
421
- 3. Upload multiple input images directly.
 
 
 
422
  """)
423
 
424
  with gr.Row(equal_height=True):
425
- with gr.Tab("Load by Object ID"):
426
  with gr.Row():
427
  id_input = gr.Dropdown(
428
  choices=get_available_ids(),
429
- value='cabinet',
430
- label="Object ID",
431
- info='Select a real-world object ID or an object ID from the PartNet-Mobility dataset. (e.g., Box (100214))',
432
  )
433
  with gr.Row():
434
- id_input_btn = gr.Button("Submit Object ID", variant="primary")
435
  with gr.Tab("Upload Mesh Files"):
436
  with gr.Row(equal_height=True):
437
  with gr.Column():
@@ -440,25 +466,32 @@ with gr.Blocks(delete_cache=(600, 600), css="""
440
  with gr.Column():
441
  mesh_viewer = LitModel3D(label="Selected Mesh", exposure=10.0, height=300)
442
  with gr.Row():
443
- mesh_processing_btn = gr.Button("Process Meshes", variant="secondary")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
444
 
445
  with gr.Row(equal_height=True):
446
  with gr.Column():
447
- input_image_gallery = gr.Gallery(label="Input Images", show_label=True, elem_id="gallery", height=300, columns=3, allow_preview=True, elem_classes=["gallery-container"])
448
- input_image_confirm_btn = gr.Button("Confirm Images", variant="secondary")
449
  with gr.Column():
450
- voxel_gallery = gr.Gallery(label="Reconstructed Voxels", show_label=True, elem_id="gallery", height=360, interactive=False, columns=3, allow_preview=True, elem_classes=["gallery-container"])
451
  with gr.Column():
452
- recon_mesh_gallery = gr.Gallery(label="Reconstructed Meshes", show_label=True, elem_id="gallery", height=360, interactive=False, columns=3, allow_preview=True, elem_classes=["gallery-container"])
453
-
454
- with gr.Row():
455
- joint_type_in = gr.Dropdown(label="joint_type", choices=["revolute", "prismatic"], value=None)
456
-
457
- with gr.Row():
458
- estimate_btn = gr.Button("Estimate Initial Joints", variant="secondary")
459
-
460
  with gr.Row():
461
- matching_examples = gr.Gallery(label="Matching Examples", show_label=True, elem_id="gallery", height=400, interactive=False, columns=5, allow_preview=True, elem_classes=["gallery-container"])
462
 
463
  with gr.Row():
464
  meta_info = gr.State(
@@ -470,54 +503,98 @@ with gr.Blocks(delete_cache=(600, 600), css="""
470
  }
471
  )
472
  with gr.Accordion("Joint Information", open=True):
473
- with gr.Row():
474
- axis_x_in = gr.Textbox(label="Joint Axis X", placeholder="", interactive=False)
475
- axis_y_in = gr.Textbox(label="Joint Axis Y", placeholder="", interactive=False)
476
- axis_z_in = gr.Textbox(label="Joint Axis Z", placeholder="", interactive=False)
477
- with gr.Row():
478
- pos_x_in = gr.Textbox(label="Joint Pivot X", placeholder="", interactive=False)
479
- pos_y_in = gr.Textbox(label="Joint Pivot Y", placeholder="", interactive=False)
480
- pos_z_in = gr.Textbox(label="Joint Pivot Z", placeholder="", interactive=False)
481
- joint_scale_in = gr.Slider(label="Max Scale", minimum=0.0, maximum=5.0, step=0.01, value=1.0, interactive=False)
482
- joint_qpos_in = gr.Textbox(label="qpos", placeholder="", interactive=False)
483
-
484
- with gr.Row():
485
- sds_btn = gr.Button("Generate Articulated Object", variant="primary")
486
-
487
- with gr.Row():
488
  with gr.Column():
489
  full_mesh = LitModel3D(label="Full Mesh", exposure=10.0, height=300)
490
  with gr.Column():
491
  fixed_part = LitModel3D(label="Fixed Part", exposure=10.0, height=300)
492
  with gr.Column():
493
  articulated_part = LitModel3D(label="Articulated Part", exposure=10.0, height=300)
 
 
 
 
 
 
 
494
 
495
- mesh_source_flag = gr.State(value="uploaded") # default to uploaded
496
- selected_id_state = gr.State(value="uploaded")
 
 
 
 
 
 
 
497
 
498
  # Handlers
499
- demo.load(start_session)
500
  demo.unload(end_session)
501
-
502
  id_input_btn.click(
503
- load_renderings_with_id,
504
- inputs=id_input,
505
- outputs=[input_image_gallery, selected_id_state]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
506
  )
507
 
 
 
 
 
 
 
508
  # Handle mesh file uploads
509
  mesh_files.change(
510
  handle_mesh_upload,
511
  inputs=mesh_files,
512
  outputs=[mesh_selector, mesh_viewer]
513
  )
514
-
515
- # Set flag to 'uploaded' when uploading files
516
- mesh_files.change(
517
- lambda *_: "uploaded",
518
- inputs=None,
519
- outputs=mesh_source_flag
520
- )
521
 
522
  # Handle dropdown selection for mesh view
523
  mesh_selector.change(
@@ -526,75 +603,12 @@ with gr.Blocks(delete_cache=(600, 600), css="""
526
  outputs=mesh_viewer
527
  )
528
 
529
- # Handle Process button click
530
- mesh_processing_btn.click(
531
- process_and_update_gallery,
532
- inputs=[mesh_files, mesh_source_flag, input_image_gallery],
533
- outputs=input_image_gallery
534
- )
535
-
536
  # Ensure downstream uses the generic 'uploaded' namespace for output paths
537
- input_image_gallery.change(
538
  lambda *_: "uploaded",
539
  inputs=None,
540
  outputs=selected_id_state
541
  )
542
-
543
- input_image_confirm_btn.click(
544
- save_gallery_to_renderings,
545
- inputs=[input_image_gallery, selected_id_state],
546
- outputs=None
547
- ).then(
548
- recon_trellis_meshes,
549
- inputs=[input_image_gallery, selected_id_state],
550
- outputs=[voxel_gallery, recon_mesh_gallery]
551
- )
552
-
553
- estimate_btn.click(
554
- estimate_initial_joints,
555
- inputs=[input_image_gallery, selected_id_state, joint_type_in],
556
- outputs=[matching_examples, meta_info]
557
- ).then(
558
- meta_to_fields_ui,
559
- inputs=meta_info,
560
- outputs=[
561
- axis_x_in,
562
- axis_y_in,
563
- axis_z_in,
564
- pos_x_in,
565
- pos_y_in,
566
- pos_z_in,
567
- joint_scale_in,
568
- joint_qpos_in
569
- ]
570
- ).then(
571
- lambda x: x,
572
- inputs=meta_info,
573
- outputs=meta_info
574
- )
575
-
576
- sds_btn.click(
577
- fields_to_meta_ui,
578
- inputs=[
579
- axis_x_in,
580
- axis_y_in,
581
- axis_z_in,
582
- pos_x_in,
583
- pos_y_in,
584
- pos_z_in,
585
- joint_scale_in,
586
- joint_qpos_in,
587
- ],
588
- outputs=meta_info
589
- ).then(
590
- _clear_3d,
591
- inputs=None,
592
- outputs=[full_mesh, fixed_part, articulated_part]
593
- ).then(
594
- articulated_generation_sds,
595
- inputs=selected_id_state,
596
- outputs=[full_mesh, fixed_part, articulated_part]
597
- )
598
 
599
  # Launch the Gradio app
600
  if __name__ == "__main__":
 
1
  import os
2
  import shutil
3
+ import json
4
+ import numpy as np
 
5
  import gradio as gr
6
  import spaces
7
+ import time
8
+
9
  from gradio_litmodel3d import LitModel3D
10
+ from pipelines.render import run_rendering
11
+ from pipelines.recon import run_recon
12
+ from pipelines.estimate import run_estimate
13
+ from pipelines.sds import run_sds
14
  from typing import *
15
  from omegaconf import OmegaConf
16
 
 
 
 
 
17
  partnet_dir = f'datasets/PartNet'
18
  real_world_dir = f'examples'
19
  multi_joint_dir = f'datasets/multi_joint'
20
+
21
  with open(f"configs/partnet.json") as f:
22
  data_info = json.load(f)
23
+ cfg = OmegaConf.load('configs/default.yaml')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
  labels = {
26
  'Cabinet (real-world)': 'cabinet',
27
  'Cabinet2 (real-world)': 'cabinet2',
28
+ 'Box (100247)': '100247',
29
  'Dishwasher (12614)': '12614',
30
+ 'Laptop (10270)': '10270',
31
+ 'Lighter (100309)': '100309',
32
+ 'Microwave (7320)': '7320',
33
+ 'Oven (102001)': '102001',
34
+ 'Refrigerator (11231)': '11231',
35
+ 'Safe (102301)': '102301',
36
+ 'Stapler (103111)': '103111',
37
  'StorageFurniture (47183)': '47183',
38
+ 'Table (20411)': '20411',
39
+ 'WashingMachine (100283)': '100283',
40
  }
41
+
 
42
  TMP_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tmp')
43
  os.makedirs(TMP_DIR, exist_ok=True)
44
+
45
+ def start_session(req: gr.Request):
46
+ return req.session_hash
 
 
 
 
47
 
48
  def end_session(req: gr.Request):
49
+ pass
 
50
 
51
  def get_available_ids():
52
  """Get list of available object IDs for the dropdown"""
53
+ # TODO: Support multi-joints
 
 
 
 
 
54
  total_list = list(labels.keys())
55
  return total_list
56
 
57
+ def load_renderings_with_id(id_input: str, session_hash: str) -> Tuple[List[str], str]:
58
 
59
  selected_id = labels[id_input]
60
+ print(f'[Selected Object] {selected_id}')
61
+ cfg.train_num_state = 6
62
+
63
  rendering_paths = []
64
  if 'cabinet' in selected_id:
65
  base_dir = real_world_dir
 
67
  base_dir = partnet_dir
68
  else:
69
  base_dir = multi_joint_dir
70
+
71
  for i in range(cfg.train_num_state):
72
  rendering_paths.append(f'{base_dir}/{selected_id}/{i:02d}_seg.png')
73
  return rendering_paths, selected_id
 
77
  if not files or len(files) == 0:
78
  return gr.Dropdown(choices=[], value=None), None
79
  choices = [f"Mesh State {i:02d} - {os.path.basename(file.name)}" for i, file in enumerate(files)]
80
+ # yield gr.update(), gr.update(None)
81
  return gr.Dropdown(choices=choices, value=choices[0] if choices else None), files[0].name
82
 
83
  def switch_mesh_view(selected_file, files):
 
102
 
103
  return None
104
 
105
+ def process_and_update_gallery(mesh_files, session_hash):
106
  mesh_paths = [f.name for f in mesh_files] if mesh_files else []
107
  cfg.train_num_state = len(mesh_paths)
108
+ rendering_paths = run_rendering(mesh_paths, output_dir=f'{TMP_DIR}/{session_hash}')
 
 
 
 
 
 
109
  return rendering_paths
110
 
111
+ def format_meta_info_text(info_dict):
112
+ """Format joint meta info into 4 rich-text lines (larger font; bold title for Joint Axis)."""
113
+ def to_str(v):
114
+ if isinstance(v, np.ndarray):
115
+ v = v.tolist()
116
+ if isinstance(v, (list, dict, tuple)):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  try:
118
+ return json.dumps(v)
 
 
 
 
119
  except Exception:
120
+ return str(v)
121
+ return "" if v is None else str(v)
 
 
 
 
 
 
 
122
 
123
+ axis_val = info_dict.get("joint_axis", "")
124
+ pos_val = info_dict.get("joint_position", "")
125
+ scale_val = info_dict.get("joint_scale", "")
126
+ qpos_val = info_dict.get("joint_qpos", "")
127
+
128
+ axis_str = to_str(axis_val)
129
+ pos_str = to_str(pos_val)
130
+ scale_str = to_str(-scale_val)
131
+ qpos_str = to_str(qpos_val)
132
+
133
+ # Use inline HTML for size and emphasis; rendered by gr.Markdown
134
+ return (
135
+ "<div style=\"font-size: 18px; line-height: 1.5;\">"
136
+ f"<div><strong>Joint Axis:</strong> {axis_str}</div>"
137
+ f"<div><strong>Joint Pivot:</strong> {pos_str}</div>"
138
+ f"<div><strong>Max Scale:</strong> {scale_str}</div>"
139
+ f"<div><strong>qpos:</strong> {qpos_str}</div>"
140
+ "</div>"
141
+ )
142
 
143
+ def image_gallery_state_change(p_state):
144
+ base_dir = f'outputs/{p_state.get("sel_id")}_{p_state.get("session_hash")}'
145
+ if p_state.get("step") == "running":
146
+ while True:
147
+ with open(f'{base_dir}/state_list.json', 'r') as f:
148
+ state_list = json.load(f)
149
+ if state_list[0] == "done":
150
+ break
151
+ time.sleep(0.5)
152
+ return gr.update(), gr.update(), \
153
+ gr.update(), gr.update(), \
154
+ gr.update(), gr.update(), \
155
+ gr.update(), gr.update(), gr.update(), \
156
+ gr.update(), gr.update(), gr.update()
157
+ if p_state.get("step") == "done":
158
+ return p_state.get("gallery", gr.update()), p_state.get("sel_id", gr.update()), \
159
+ p_state.get("cached_path", gr.update())[0], \
160
+ p_state.get("cached_path", gr.update())[1], \
161
+ p_state.get("cached_path", gr.update())[2], \
162
+ gr.update(value=None), gr.update(value=None), \
163
+ gr.update(value=None), gr.update(value=None), \
164
+ gr.update(value=None), gr.update(value=None), gr.update(value=None)
165
+ return gr.update(), gr.update(), \
166
+ gr.update(), gr.update(), \
167
+ gr.update(), gr.update(), \
168
+ gr.update(), gr.update(), gr.update(), \
169
+ gr.update(), gr.update(), gr.update()
170
+
171
+ def recon_state_change(p_state):
172
+ base_dir = f'outputs/{p_state.get("sel_id")}_{p_state.get("session_hash")}'
173
+ if p_state.get("step") == "running":
174
+ while True:
175
+ with open(f'{base_dir}/state_list.json', 'r') as f:
176
+ state_list = json.load(f)
177
+ if state_list[1] == "done":
178
+ break
179
+ time.sleep(0.5)
180
+ return gr.update(), gr.update()
181
+ if p_state.get("step") == "done":
182
+ return p_state.get("vox", gr.update()), p_state.get("recon", gr.update())
183
+ return gr.update(), gr.update()
184
+
185
+ def estimate_state_change(p_state):
186
+ base_dir = f'outputs/{p_state.get("sel_id")}_{p_state.get("session_hash")}'
187
+ if p_state.get("step") == "running":
188
+ while True:
189
+ with open(f'{base_dir}/state_list.json', 'r') as f:
190
+ state_list = json.load(f)
191
+ if state_list[2] == "done":
192
+ break
193
+ time.sleep(0.5)
194
+ return gr.update(), gr.update()
195
+ if p_state.get("step") == "done":
196
+ return p_state.get("match", gr.update()), p_state.get("html", gr.update())
197
+ return gr.update(), gr.update()
198
+
199
+ def sds_state_change(p_state):
200
+ base_dir = f'outputs/{p_state.get("sel_id")}_{p_state.get("session_hash")}'
201
+ if p_state.get("step") == "running":
202
+ while True:
203
+ with open(f'{base_dir}/state_list.json', 'r') as f:
204
+ state_list = json.load(f)
205
+ if state_list[3] == "done":
206
+ break
207
+ time.sleep(0.5)
208
+ return gr.update(), gr.update(), gr.update()
209
+ if p_state.get("step") == "done":
210
+ return p_state.get("full", gr.update()), p_state.get("fixed", gr.update()), p_state.get("art", gr.update())
211
+ return gr.update(), gr.update(), gr.update()
212
+
213
+ def save_gallery_to_renderings(gallery_value, selected_id, session_hash):
214
  """Persist gallery images into outputs/<selected_id>/renderings with SDS-expected names.
215
  Ensures there are cfg.train_num_state frames by padding with the last image if needed.
216
+ Also writes the required 'rendering_pure_joint_00_state_{T-1}.png' using the last frame.
217
  """
218
  try:
219
  image_paths = []
 
226
  return
227
 
228
  cfg.train_num_state = len(image_paths)
229
+ base_dir = f'outputs/{selected_id}_{session_hash}'
230
  if "uploaded" in base_dir:
231
  os.system(f"rm -rf {base_dir}/*")
232
+
233
  rendering_dir = f'{base_dir}/renderings'
234
  os.makedirs(rendering_dir, exist_ok=True)
235
 
236
  # Normalize count to T frames
237
  for i in range(cfg.train_num_state):
238
  src = image_paths[i] if i < len(image_paths) else image_paths[-1]
239
+ dst = f'{rendering_dir}/rendering_joint_00_state_{i:02d}.png'
240
  shutil.copy(src, dst)
241
 
242
  # Write the 'pure' image as the last uploaded (or last padded) frame
243
+ if os.path.exists(image_paths[-1].replace('_seg.png', '_pure.png')):
244
+ pure_src = image_paths[-1].replace('_seg.png', '_pure.png')
245
+ else:
246
+ pure_src = image_paths[-1]
247
+ pure_dst = f'{rendering_dir}/rendering_pure_joint_00_state_{(cfg.train_num_state - 1):02d}.png'
248
  shutil.copy(pure_src, pure_dst)
249
  except Exception as e:
250
  print(f"[Gallery->Renderings] Failed to persist images: {e}")
251
  return
252
 
253
+ @spaces.GPU(duration=200)
254
+ def run_recon_trellis(image_paths, output_dir):
255
+ return run_recon(image_paths, output_dir=output_dir, app=True)
256
+
257
+ def recon_trellis_meshes(input_image_gallery, output_dir):
258
  # Carefully extract file paths from Gradio Gallery elements, which may be dicts, file objects, or strings.
259
  image_paths = [img[0] for img in input_image_gallery]
260
+ glb_paths, rendering_dir, recon_voxel_paths = run_recon_trellis(image_paths, output_dir=output_dir)
261
+ recon_mesh_paths = run_rendering(glb_paths, rendering_dir, recon=True)
262
+ return recon_voxel_paths, recon_mesh_paths
263
+
264
+ @spaces.GPU(duration=120)
265
+ def estimate_initial_joints(input_image_gallery, joint_type, output_dir):
266
+ image_paths = [img[0] for img in input_image_gallery]
267
+ print(image_paths)
268
+ matching_examples, info_dict = run_estimate(image_paths, output_dir=output_dir, cfg=cfg, joint_type=joint_type)
 
 
 
 
 
269
  return matching_examples, info_dict
270
 
271
+ @spaces.GPU(duration=800)
272
+ def articulated_generation_sds(selected_id, session_hash):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
 
274
  if 'cabinet' in selected_id:
275
  input_dir = real_world_dir
 
278
  else:
279
  input_dir = multi_joint_dir
280
 
281
+ base_dir = f'outputs/{selected_id}_{session_hash}'
282
  rendering_dir = f'{base_dir}/renderings'
283
 
284
  os.makedirs(rendering_dir, exist_ok=True)
285
  if os.path.exists(f'{input_dir}/{selected_id}/05_seg.png'):
286
  for i in range(6):
287
+ shutil.copy(f'{input_dir}/{selected_id}/{i:02d}_seg.png', f'{rendering_dir}/rendering_joint_00_state_{i:02d}.png')
288
+ shutil.copy(f'{input_dir}/{selected_id}/05_pure.png', f'{rendering_dir}/rendering_pure_joint_00_state_05.png')
289
+
 
290
  full_mesh, fixed_part, articulated_part = run_sds(base_dir, 1, cfg)
291
  return full_mesh, fixed_part, articulated_part
292
 
293
+ def pipeline(id_value, mesh_files, uploaded_image_gallery, joint_type_in, session_hash, run_idx):
294
+ """Server-side pipeline that yields state only; UI updates are applied via a mapper."""
295
+
296
+ # 1) Prepare inputs
297
+ if id_value is not None:
298
+ sel_id = f"{labels[id_value]}_{run_idx:02d}"
299
+ elif mesh_files is not None:
300
+ sel_id = f"mesh_uploading_{run_idx:02d}"
301
+ elif uploaded_image_gallery is not None:
302
+ sel_id = f"image_uploading_{run_idx:02d}"
303
+
304
+ base_dir = f'outputs/{sel_id}_{session_hash}'
305
+ os.makedirs(base_dir, exist_ok=True)
306
+ state_list_output_path = f'{base_dir}/state_list.json'
307
+
308
+ state_list = ["running", "prepare", "prepare", "prepare"]
309
+ with open(state_list_output_path, 'w') as f:
310
+ json.dump(state_list, f)
311
+ yield (
312
+ {"step": state_list[0], "sel_id": sel_id, "session_hash": session_hash},
313
+ {"step": state_list[1], "sel_id": sel_id, "session_hash": session_hash},
314
+ {"step": state_list[2], "sel_id": sel_id, "session_hash": session_hash},
315
+ {"step": state_list[3], "sel_id": sel_id, "session_hash": session_hash}, run_idx, \
316
+ f"<h3>Preparing input images...<p style=\"color:red\">(<u>~3 min</u>)</p></h3>"
317
+ )
318
+
319
+ if id_value is not None:
320
+ rendering_paths, _ = load_renderings_with_id(id_value, session_hash)
321
+ elif mesh_files is not None:
322
+ rendering_paths = process_and_update_gallery(mesh_files, session_hash)
323
+ elif uploaded_image_gallery is not None:
324
+ rendering_paths = [img[0] for img in uploaded_image_gallery]
325
+
326
+ gallery = [[p, None] for p in rendering_paths]
327
+ cached_path = [f'datasets/cached_results/{labels[id_value]}/full.glb',
328
+ f'datasets/cached_results/{labels[id_value]}/fixed.glb',
329
+ f'datasets/cached_results/{labels[id_value]}/art.glb']
330
+ save_gallery_to_renderings(gallery, sel_id, session_hash)
331
+
332
+ state_list = ["done", "running", "prepare", "prepare"]
333
+ with open(state_list_output_path, 'w') as f:
334
+ json.dump(state_list, f)
335
+ yield (
336
+ {"step": state_list[0], "gallery": gallery, "sel_id": sel_id, "cached_path": cached_path, "session_hash": session_hash},
337
+ {"step": state_list[1], "sel_id": sel_id, "session_hash": session_hash},
338
+ {"step": state_list[2], "sel_id": sel_id, "session_hash": session_hash},
339
+ {"step": state_list[3], "sel_id": sel_id, "session_hash": session_hash}, run_idx, \
340
+ f"<h3>Stage 1: Initial reconstruction... <span style=\"color:red\">(<u style=\"color:red\">~3 min</u>)</span></h3>"
341
+ )
342
+
343
+ # 3) Reconstruction
344
+ vox, recon = recon_trellis_meshes(gallery, f"{base_dir}/recon")
345
+
346
+ state_list = ["done", "done", "running", "running"]
347
+ with open(state_list_output_path, 'w') as f:
348
+ json.dump(state_list, f)
349
+ yield (
350
+ {"step": state_list[0], "gallery": gallery, "sel_id": sel_id, "cached_path": cached_path, "session_hash": session_hash},
351
+ {"step": state_list[1], "vox": vox, "recon": recon, "sel_id": sel_id, "session_hash": session_hash},
352
+ {"step": state_list[2], "sel_id": sel_id, "session_hash": session_hash},
353
+ {"step": state_list[3], "sel_id": sel_id, "session_hash": session_hash}, run_idx, \
354
+ f"<h3>Stage 2: Joint initialization... <span style=\"color:red\">(<u style=\"color:red\">~1 min</u>)</span></h3>"
355
+ )
356
+
357
+ # 4) Joint estimation
358
+ if joint_type_in is not None:
359
+ joint_type = joint_type_in
360
+ else:
361
+ if 'cabinet' in sel_id:
362
+ joint_type = 'revolute' if 'cabinet2' in sel_id else 'prismatic'
363
+ else:
364
+ joint_type = 'prismatic' if (sel_id in data_info['prismatic']['obj_ids']) else 'revolute'
365
+ print(f"[Joint Type] {joint_type}")
366
+ match, meta = estimate_initial_joints(gallery, joint_type, base_dir)
367
+
368
+ # 5) Format meta info
369
+ html = format_meta_info_text(meta)
370
+
371
+ state_list = ["done", "done", "done", "running"]
372
+ with open(state_list_output_path, 'w') as f:
373
+ json.dump(state_list, f)
374
+ yield (
375
+ {"step": state_list[0], "gallery": gallery, "sel_id": sel_id, "cached_path": cached_path, "session_hash": session_hash},
376
+ {"step": state_list[1], "vox": vox, "recon": recon, "sel_id": sel_id, "session_hash": session_hash},
377
+ {"step": state_list[2], "match": match, "html": html, "sel_id": sel_id, "session_hash": session_hash},
378
+ {"step": state_list[3], "sel_id": sel_id, "session_hash": session_hash}, run_idx, \
379
+ f"<h3>Stage 3: SDS optimization... <span style=\"color:red\">(<u style=\"color:red\">~10 min</u>)</span></h3>"
380
+ )
381
+
382
+ # 6) SDS refinement
383
+ full, fixed, art = articulated_generation_sds(sel_id, session_hash)
384
+
385
+ state_list = ["done", "done", "done", "done"]
386
+ with open(state_list_output_path, 'w') as f:
387
+ json.dump(state_list, f)
388
+ yield (
389
+ {"step": state_list[0], "gallery": gallery, "sel_id": sel_id, "cached_path": cached_path,"session_hash": session_hash},
390
+ {"step": state_list[1], "vox": vox, "recon": recon, "sel_id": sel_id, "session_hash": session_hash},
391
+ {"step": state_list[2], "match": match, "html": html, "sel_id": sel_id, "session_hash": session_hash},
392
+ {"step": state_list[3], "full": full, "fixed": fixed, "art": art, "sel_id": sel_id, "session_hash": session_hash},
393
+ run_idx+1, \
394
+ f"<h3>Done!</h3>"
395
+ )
396
+
397
  with gr.Blocks(delete_cache=(600, 600), css="""
398
  .gallery-container {
399
  overflow-x: auto !important;
 
439
  gr.Markdown("""
440
  ## FreeArt3D Demo
441
  ### You can use the following three methods to generate articulated 3D models.
442
+ 1. Choose an example object (from PartNet-Mobility or real-world).
443
+ 2. Upload multiple mesh files (e.g., .obj, .ply, .stl, .glb, .gltf) at different articulation states (images will be rendered automatically).
444
+ 3. Upload multiple input images with **a segmented object on the disk** at **different articulation states** (you can use a fixed view but have to contain ** at least 2 states**).
445
+
446
+ ### The total generation time is *~10 min*. Be patient :)
447
+ ### Currently it's difficult to run the full pipeline with ZeroGPU due to the long running time. We are applying for an exclusive GPU. Stay Tuned! (We add the cached results now for example objects for you to have a quick check)
448
  """)
449
 
450
  with gr.Row(equal_height=True):
451
+ with gr.Tab("Load by Example Object"):
452
  with gr.Row():
453
  id_input = gr.Dropdown(
454
  choices=get_available_ids(),
455
+ value='Cabinet (real-world)',
456
+ label="Example Object",
457
+ info='Select a real-world object or an object from the PartNet-Mobility dataset. (e.g., Box (100214))',
458
  )
459
  with gr.Row():
460
+ id_input_btn = gr.Button("Generate Articulated Object", variant="primary")
461
  with gr.Tab("Upload Mesh Files"):
462
  with gr.Row(equal_height=True):
463
  with gr.Column():
 
466
  with gr.Column():
467
  mesh_viewer = LitModel3D(label="Selected Mesh", exposure=10.0, height=300)
468
  with gr.Row():
469
+ joint_type_in_mesh = gr.Dropdown(label="joint_type", choices=["revolute", "prismatic"], value=None)
470
+ with gr.Row():
471
+ mesh_input_btn = gr.Button("Generate Articulated Object", variant="primary")
472
+ with gr.Tab("Upload Image Files"):
473
+ with gr.Row(equal_height=True):
474
+ uploaded_image_gallery = gr.Gallery(label="Input Images", show_label=True, elem_id="gallery", height=300, columns=10, allow_preview=True, elem_classes=["gallery-container"])
475
+ with gr.Row():
476
+ joint_type_in_image = gr.Dropdown(label="joint_type", choices=["revolute", "prismatic"], value=None)
477
+ with gr.Row():
478
+ image_input_btn = gr.Button("Generate Articulated Object", variant="primary")
479
+
480
+ with gr.Row():
481
+ with gr.Accordion("Current Stage", open=True):
482
+ current_stage = gr.HTML(value="<h3>Waiting for input...</h3>")
483
+
484
 
485
  with gr.Row(equal_height=True):
486
  with gr.Column():
487
+ input_image_gallery = gr.Gallery(label="Input Images", show_label=True, elem_id="gallery", height=300, columns=3, allow_preview=True, interactive=False, elem_classes=["gallery-container"])
 
488
  with gr.Column():
489
+ voxel_gallery = gr.Gallery(label="Reconstructed Voxels", show_label=True, elem_id="gallery", height=360, columns=3, allow_preview=True, interactive=False, elem_classes=["gallery-container"])
490
  with gr.Column():
491
+ recon_mesh_gallery = gr.Gallery(label="Reconstructed Meshes", show_label=True, elem_id="gallery", height=360, columns=3, allow_preview=True, interactive=False, elem_classes=["gallery-container"])
492
+
 
 
 
 
 
 
493
  with gr.Row():
494
+ matching_examples = gr.Gallery(label="Correspondences", show_label=True, elem_id="gallery", height=400, interactive=False, columns=5, allow_preview=True, elem_classes=["gallery-container"])
495
 
496
  with gr.Row():
497
  meta_info = gr.State(
 
503
  }
504
  )
505
  with gr.Accordion("Joint Information", open=True):
506
+ joint_info_html = gr.HTML(value="")
507
+
508
+ with gr.Row():
 
 
 
 
 
 
 
 
 
 
 
 
509
  with gr.Column():
510
  full_mesh = LitModel3D(label="Full Mesh", exposure=10.0, height=300)
511
  with gr.Column():
512
  fixed_part = LitModel3D(label="Fixed Part", exposure=10.0, height=300)
513
  with gr.Column():
514
  articulated_part = LitModel3D(label="Articulated Part", exposure=10.0, height=300)
515
+ with gr.Row():
516
+ with gr.Column():
517
+ full_mesh_cached = LitModel3D(label="Full Mesh (Cached)", exposure=10.0, height=300)
518
+ with gr.Column():
519
+ fixed_part_cached = LitModel3D(label="Fixed Part (Cached)", exposure=10.0, height=300)
520
+ with gr.Column():
521
+ articulated_part_cached = LitModel3D(label="Articulated Part (Cached)", exposure=10.0, height=300)
522
 
523
+ selected_id_state = gr.State(value="")
524
+ session_hash_state = gr.State(value="")
525
+ run_idx_state = gr.State(value=0)
526
+
527
+ image_gallery_state = gr.State(value="prepare")
528
+ recon_state = gr.State(value="prepare")
529
+ estimate_state = gr.State(value="prepare")
530
+ sds_state = gr.State(value="prepare")
531
+ none_val = gr.State(value=None)
532
 
533
  # Handlers
534
+ demo.load(start_session, outputs=session_hash_state)
535
  demo.unload(end_session)
536
+
537
  id_input_btn.click(
538
+ start_session,
539
+ outputs=session_hash_state,
540
+ ).then(
541
+ pipeline,
542
+ inputs=[id_input, none_val, none_val, none_val, session_hash_state, run_idx_state],
543
+ outputs=[image_gallery_state, recon_state, estimate_state, sds_state, run_idx_state, current_stage],
544
+ )
545
+
546
+ mesh_input_btn.click(
547
+ start_session,
548
+ outputs=session_hash_state,
549
+ ).then(
550
+ pipeline,
551
+ inputs=[none_val, mesh_files, none_val, joint_type_in_mesh, session_hash_state, run_idx_state],
552
+ outputs=[image_gallery_state, recon_state, estimate_state, sds_state, run_idx_state, current_stage],
553
+ )
554
+
555
+ image_input_btn.click(
556
+ start_session,
557
+ outputs=session_hash_state,
558
+ ).then(
559
+ pipeline,
560
+ inputs=[none_val, none_val, uploaded_image_gallery, joint_type_in_image, session_hash_state, run_idx_state],
561
+ outputs=[image_gallery_state, recon_state, estimate_state, sds_state, run_idx_state, current_stage],
562
+ )
563
+
564
+ # Watch state and update only relevant components per step
565
+ image_gallery_state.change(
566
+ image_gallery_state_change,
567
+ inputs=image_gallery_state,
568
+ outputs=[input_image_gallery, selected_id_state, full_mesh_cached, fixed_part_cached, articulated_part_cached,
569
+ voxel_gallery, recon_mesh_gallery,
570
+ matching_examples, joint_info_html,
571
+ full_mesh, fixed_part, articulated_part],
572
+ )
573
+
574
+ recon_state.change(
575
+ recon_state_change,
576
+ inputs=recon_state,
577
+ outputs=[voxel_gallery, recon_mesh_gallery],
578
+ )
579
+
580
+ estimate_state.change(
581
+ estimate_state_change,
582
+ inputs=estimate_state,
583
+ outputs=[matching_examples, joint_info_html],
584
  )
585
 
586
+ sds_state.change(
587
+ sds_state_change,
588
+ inputs=sds_state,
589
+ outputs=[full_mesh, fixed_part, articulated_part],
590
+ )
591
+
592
  # Handle mesh file uploads
593
  mesh_files.change(
594
  handle_mesh_upload,
595
  inputs=mesh_files,
596
  outputs=[mesh_selector, mesh_viewer]
597
  )
 
 
 
 
 
 
 
598
 
599
  # Handle dropdown selection for mesh view
600
  mesh_selector.change(
 
603
  outputs=mesh_viewer
604
  )
605
 
 
 
 
 
 
 
 
606
  # Ensure downstream uses the generic 'uploaded' namespace for output paths
607
+ uploaded_image_gallery.change(
608
  lambda *_: "uploaded",
609
  inputs=None,
610
  outputs=selected_id_state
611
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
612
 
613
  # Launch the Gradio app
614
  if __name__ == "__main__":
assets/disk.png CHANGED

Git LFS Details

  • SHA256: 0a687be19a84d769eff358f39c69fcff55ff3fc917c9e5f83c213a2996b2f6ba
  • Pointer size: 131 Bytes
  • Size of remote file: 573 kB

Git LFS Details

  • SHA256: 7147e1ed5fcd38b672d35a9f0d63ce3f6cc34e4a6fe7c2448218dab5f5b2ca47
  • Pointer size: 131 Bytes
  • Size of remote file: 528 kB
assets/teaser.png CHANGED

Git LFS Details

  • SHA256: 898275f2795edccd072af89443c961d924805fadcf82b3dfdb644613aabd45e5
  • Pointer size: 132 Bytes
  • Size of remote file: 1.87 MB

Git LFS Details

  • SHA256: 1c26c25109c1052ffff6f4d90b38c4b39be4f59eaed7a208bf64425f4207f041
  • Pointer size: 132 Bytes
  • Size of remote file: 3.92 MB
configs/default.yaml CHANGED
@@ -1,16 +1,33 @@
1
- total_iters: 3000
2
  print_interval: 10
3
  save_interval: 500
4
  vis_interval: 500
5
 
 
 
 
 
 
 
 
6
  noise_start: 0.5
7
  noise_end: 0.8
8
  refine_noise: 0.5
 
 
 
 
 
 
 
9
 
10
  batch_size: 1
11
  base_lr: 0.01
12
  art_lr: 0.01
13
- scale_lr: 0.01
 
 
 
14
 
15
  sds_weight: 0.1
16
  voxel_weight: 1
@@ -20,4 +37,4 @@ sample_interval: 0.5
20
  sample_coeff: 2.0
21
 
22
  train_num_state: 6
23
- inference_num_state: 6
 
1
+ total_iters: 1500
2
  print_interval: 10
3
  save_interval: 500
4
  vis_interval: 500
5
 
6
+ min_azi: 0.39269908169872414
7
+ max_azi: 1.1780972450961724
8
+
9
+ ransac_iteration: 1000
10
+ ransac_threshold: 0.1
11
+ ransac_sample: 3
12
+
13
  noise_start: 0.5
14
  noise_end: 0.8
15
  refine_noise: 0.5
16
+ expand_iteration: 100
17
+ expand_threshold_base: 0.5
18
+ expand_threshold_prismatic: 0.45
19
+ expand_threshold_revolute: 0.45
20
+ large_iteration_base: 50
21
+ large_iteration_prismatic: 30
22
+ large_iteration_revolute: 30
23
 
24
  batch_size: 1
25
  base_lr: 0.01
26
  art_lr: 0.01
27
+ pivot_lr: 0.1
28
+ scale_lr_prismatic: 0.005
29
+ scale_lr_revolute: 0.01
30
+ qpos_lr: 0.01
31
 
32
  sds_weight: 0.1
33
  voxel_weight: 1
 
37
  sample_coeff: 2.0
38
 
39
  train_num_state: 6
40
+ inference_num_state: 6
configs/partnet_target.json CHANGED
@@ -64,7 +64,7 @@
64
  "joint_type": "revolute"
65
  },
66
  "Refrigerator": {
67
- "joint_tags": ["door"],
68
  "joint_type": "revolute"
69
  },
70
  "WashingMachine": {
 
64
  "joint_type": "revolute"
65
  },
66
  "Refrigerator": {
67
+ "joint_tags": ["door", "door_frame"],
68
  "joint_type": "revolute"
69
  },
70
  "WashingMachine": {
datasets/PartNet/100214/02_pure.png DELETED

Git LFS Details

  • SHA256: 77b11a6901b162181bdc1e6c1941c7a71ae082ce929a7cdcd454c381dcc4ad54
  • Pointer size: 131 Bytes
  • Size of remote file: 418 kB
datasets/PartNet/100214/02_seg.png DELETED

Git LFS Details

  • SHA256: 013ea901d13002360c9739541cb8bcd59021324353c1eb1f2b3e301407e33e12
  • Pointer size: 131 Bytes
  • Size of remote file: 517 kB
datasets/PartNet/100214/03_pure.png DELETED

Git LFS Details

  • SHA256: 93fc1bbaa0e9d165ea023cb5a16129e4ab1d9f6a2c55d45914fce8d1d52e29f3
  • Pointer size: 131 Bytes
  • Size of remote file: 433 kB
datasets/PartNet/100214/03_seg.png DELETED

Git LFS Details

  • SHA256: 9cbf7cf335bdc2692c74136983d4e8979a8a04c81d5b780d3ba212e9329ec9e8
  • Pointer size: 131 Bytes
  • Size of remote file: 530 kB
datasets/PartNet/100214/04_pure.png DELETED

Git LFS Details

  • SHA256: 319d59cfbf80542d0c90ebcd54ac90a9428545c0711bba145a7c186558e48c64
  • Pointer size: 131 Bytes
  • Size of remote file: 445 kB
datasets/PartNet/100214/04_seg.png DELETED

Git LFS Details

  • SHA256: 0734d13f696a2b823547f36122246d9ea8b25a5743be6f9594ec5b21079ce0bb
  • Pointer size: 131 Bytes
  • Size of remote file: 541 kB
datasets/PartNet/100214/05_pure.png DELETED

Git LFS Details

  • SHA256: 2012a2357a346d13e6fe80f91d0e4f918381e91259ce711c4f16820d394a7f10
  • Pointer size: 131 Bytes
  • Size of remote file: 456 kB
datasets/PartNet/100214/05_seg.png DELETED

Git LFS Details

  • SHA256: 6fc940dff41ec2507dade432ac7d1968304d076877070cddff71057d690bc86b
  • Pointer size: 131 Bytes
  • Size of remote file: 551 kB
datasets/PartNet/100214/gt_mesh/00.glb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:aa33bf488300581d45bedaa1d1286e0a240068d1433b33d4b3625b95ff8b5e20
3
- size 3908732
 
 
 
 
datasets/PartNet/100214/gt_mesh/01.glb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:9ba38020066067c5c9948892387d2cde48dec9c3d9aeaa4fe489b1851b6aad5c
3
- size 3908756
 
 
 
 
datasets/PartNet/100214/gt_mesh/02.glb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:3adecc17b8dfe4f5fbd1da9695b9d634fa8c85f01ad472f56774224a63e74387
3
- size 3908756
 
 
 
 
datasets/PartNet/100214/gt_mesh/03.glb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:716fb1a554ca852c3e850fffe2f43db1fe908a152140c8409937bdb6b419a19a
3
- size 3908756
 
 
 
 
datasets/PartNet/100214/gt_mesh/04.glb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:0039fc82c8b7904f30e77cbcef101d31555960fc0eed0955fa625b7842000995
3
- size 3908840
 
 
 
 
datasets/PartNet/100214/gt_mesh/05.glb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:8a6976d0390034206ebe897bb682140556f1e83712540c714f01e20a9c74c875
3
- size 3908728
 
 
 
 
datasets/PartNet/100214/joint_info.json DELETED
@@ -1,21 +0,0 @@
1
- [
2
- {
3
- "type": "revolute",
4
- "range": [
5
- -1.6755160819145563,
6
- 0.3490658503988659
7
- ],
8
- "axis": {
9
- "origin": [
10
- 0.4566900000000005,
11
- 0.19353231481404498,
12
- -0.22
13
- ],
14
- "direction": [
15
- -1.0,
16
- 0.0,
17
- 0.0
18
- ]
19
- }
20
- }
21
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
datasets/PartNet/100214/joints.json DELETED
@@ -1,16 +0,0 @@
1
- {
2
- "category": "Box",
3
- "joints": [
4
- "joint_0"
5
- ],
6
- "descendants": {
7
- "joint_0": [],
8
- "joint_1": [],
9
- "joint_2": [],
10
- "joint_3": [
11
- "joint_0",
12
- "joint_1",
13
- "joint_2"
14
- ]
15
- }
16
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
datasets/PartNet/100214/mobility.urdf DELETED
@@ -1,470 +0,0 @@
1
- <?xml version="1.0" ?>
2
- <robot name="partnet_802f6cfeb6f41f16a59ff8378a27445f">
3
- <link name="base"/>
4
- <link name="link_0">
5
- <visual name="rotation_lid-1">
6
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
7
- <geometry>
8
- <mesh filename="textured_objs/original-4.obj"/>
9
- </geometry>
10
- </visual>
11
- <visual name="rotation_lid-1">
12
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
13
- <geometry>
14
- <mesh filename="textured_objs/original-9.obj"/>
15
- </geometry>
16
- </visual>
17
- <visual name="rotation_lid-1">
18
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
19
- <geometry>
20
- <mesh filename="textured_objs/original-37.obj"/>
21
- </geometry>
22
- </visual>
23
- <visual name="rotation_lid-1">
24
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
25
- <geometry>
26
- <mesh filename="textured_objs/original-36.obj"/>
27
- </geometry>
28
- </visual>
29
- <visual name="rotation_lid-1">
30
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
31
- <geometry>
32
- <mesh filename="textured_objs/original-34.obj"/>
33
- </geometry>
34
- </visual>
35
- <visual name="rotation_lid-1">
36
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
37
- <geometry>
38
- <mesh filename="textured_objs/original-35.obj"/>
39
- </geometry>
40
- </visual>
41
- <visual name="rotation_lid-1">
42
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
43
- <geometry>
44
- <mesh filename="textured_objs/original-38.obj"/>
45
- </geometry>
46
- </visual>
47
- <visual name="rotation_lid-1">
48
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
49
- <geometry>
50
- <mesh filename="textured_objs/original-12.obj"/>
51
- </geometry>
52
- </visual>
53
- <visual name="rotation_lid-1">
54
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
55
- <geometry>
56
- <mesh filename="textured_objs/original-13.obj"/>
57
- </geometry>
58
- </visual>
59
- <visual name="rotation_lid-1">
60
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
61
- <geometry>
62
- <mesh filename="textured_objs/original-15.obj"/>
63
- </geometry>
64
- </visual>
65
- <visual name="rotation_lid-1">
66
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
67
- <geometry>
68
- <mesh filename="textured_objs/original-16.obj"/>
69
- </geometry>
70
- </visual>
71
- <visual name="rotation_lid-1">
72
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
73
- <geometry>
74
- <mesh filename="textured_objs/original-18.obj"/>
75
- </geometry>
76
- </visual>
77
- <visual name="rotation_lid-1">
78
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
79
- <geometry>
80
- <mesh filename="textured_objs/original-19.obj"/>
81
- </geometry>
82
- </visual>
83
- <visual name="rotation_lid-1">
84
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
85
- <geometry>
86
- <mesh filename="textured_objs/original-21.obj"/>
87
- </geometry>
88
- </visual>
89
- <visual name="rotation_lid-1">
90
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
91
- <geometry>
92
- <mesh filename="textured_objs/original-20.obj"/>
93
- </geometry>
94
- </visual>
95
- <visual name="rotation_lid-1">
96
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
97
- <geometry>
98
- <mesh filename="textured_objs/original-17.obj"/>
99
- </geometry>
100
- </visual>
101
- <visual name="rotation_lid-1">
102
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
103
- <geometry>
104
- <mesh filename="textured_objs/original-14.obj"/>
105
- </geometry>
106
- </visual>
107
- <visual name="rotation_lid-1">
108
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
109
- <geometry>
110
- <mesh filename="textured_objs/original-32.obj"/>
111
- </geometry>
112
- </visual>
113
- <visual name="rotation_lid-1">
114
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
115
- <geometry>
116
- <mesh filename="textured_objs/original-31.obj"/>
117
- </geometry>
118
- </visual>
119
- <visual name="rotation_lid-1">
120
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
121
- <geometry>
122
- <mesh filename="textured_objs/original-30.obj"/>
123
- </geometry>
124
- </visual>
125
- <visual name="rotation_lid-1">
126
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
127
- <geometry>
128
- <mesh filename="textured_objs/original-29.obj"/>
129
- </geometry>
130
- </visual>
131
- <visual name="rotation_lid-1">
132
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
133
- <geometry>
134
- <mesh filename="textured_objs/original-26.obj"/>
135
- </geometry>
136
- </visual>
137
- <visual name="rotation_lid-1">
138
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
139
- <geometry>
140
- <mesh filename="textured_objs/original-27.obj"/>
141
- </geometry>
142
- </visual>
143
- <visual name="rotation_lid-1">
144
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
145
- <geometry>
146
- <mesh filename="textured_objs/original-25.obj"/>
147
- </geometry>
148
- </visual>
149
- <visual name="rotation_lid-1">
150
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
151
- <geometry>
152
- <mesh filename="textured_objs/original-24.obj"/>
153
- </geometry>
154
- </visual>
155
- <visual name="rotation_lid-1">
156
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
157
- <geometry>
158
- <mesh filename="textured_objs/original-23.obj"/>
159
- </geometry>
160
- </visual>
161
- <visual name="rotation_lid-1">
162
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
163
- <geometry>
164
- <mesh filename="textured_objs/original-33.obj"/>
165
- </geometry>
166
- </visual>
167
- <visual name="rotation_lid-1">
168
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
169
- <geometry>
170
- <mesh filename="textured_objs/original-28.obj"/>
171
- </geometry>
172
- </visual>
173
- <collision>
174
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
175
- <geometry>
176
- <mesh filename="textured_objs/original-4.obj"/>
177
- </geometry>
178
- </collision>
179
- <collision>
180
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
181
- <geometry>
182
- <mesh filename="textured_objs/original-9.obj"/>
183
- </geometry>
184
- </collision>
185
- <collision>
186
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
187
- <geometry>
188
- <mesh filename="textured_objs/original-37.obj"/>
189
- </geometry>
190
- </collision>
191
- <collision>
192
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
193
- <geometry>
194
- <mesh filename="textured_objs/original-36.obj"/>
195
- </geometry>
196
- </collision>
197
- <collision>
198
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
199
- <geometry>
200
- <mesh filename="textured_objs/original-34.obj"/>
201
- </geometry>
202
- </collision>
203
- <collision>
204
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
205
- <geometry>
206
- <mesh filename="textured_objs/original-35.obj"/>
207
- </geometry>
208
- </collision>
209
- <collision>
210
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
211
- <geometry>
212
- <mesh filename="textured_objs/original-38.obj"/>
213
- </geometry>
214
- </collision>
215
- <collision>
216
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
217
- <geometry>
218
- <mesh filename="textured_objs/original-12.obj"/>
219
- </geometry>
220
- </collision>
221
- <collision>
222
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
223
- <geometry>
224
- <mesh filename="textured_objs/original-13.obj"/>
225
- </geometry>
226
- </collision>
227
- <collision>
228
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
229
- <geometry>
230
- <mesh filename="textured_objs/original-15.obj"/>
231
- </geometry>
232
- </collision>
233
- <collision>
234
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
235
- <geometry>
236
- <mesh filename="textured_objs/original-16.obj"/>
237
- </geometry>
238
- </collision>
239
- <collision>
240
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
241
- <geometry>
242
- <mesh filename="textured_objs/original-18.obj"/>
243
- </geometry>
244
- </collision>
245
- <collision>
246
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
247
- <geometry>
248
- <mesh filename="textured_objs/original-19.obj"/>
249
- </geometry>
250
- </collision>
251
- <collision>
252
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
253
- <geometry>
254
- <mesh filename="textured_objs/original-21.obj"/>
255
- </geometry>
256
- </collision>
257
- <collision>
258
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
259
- <geometry>
260
- <mesh filename="textured_objs/original-20.obj"/>
261
- </geometry>
262
- </collision>
263
- <collision>
264
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
265
- <geometry>
266
- <mesh filename="textured_objs/original-17.obj"/>
267
- </geometry>
268
- </collision>
269
- <collision>
270
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
271
- <geometry>
272
- <mesh filename="textured_objs/original-14.obj"/>
273
- </geometry>
274
- </collision>
275
- <collision>
276
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
277
- <geometry>
278
- <mesh filename="textured_objs/original-32.obj"/>
279
- </geometry>
280
- </collision>
281
- <collision>
282
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
283
- <geometry>
284
- <mesh filename="textured_objs/original-31.obj"/>
285
- </geometry>
286
- </collision>
287
- <collision>
288
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
289
- <geometry>
290
- <mesh filename="textured_objs/original-30.obj"/>
291
- </geometry>
292
- </collision>
293
- <collision>
294
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
295
- <geometry>
296
- <mesh filename="textured_objs/original-29.obj"/>
297
- </geometry>
298
- </collision>
299
- <collision>
300
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
301
- <geometry>
302
- <mesh filename="textured_objs/original-26.obj"/>
303
- </geometry>
304
- </collision>
305
- <collision>
306
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
307
- <geometry>
308
- <mesh filename="textured_objs/original-27.obj"/>
309
- </geometry>
310
- </collision>
311
- <collision>
312
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
313
- <geometry>
314
- <mesh filename="textured_objs/original-25.obj"/>
315
- </geometry>
316
- </collision>
317
- <collision>
318
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
319
- <geometry>
320
- <mesh filename="textured_objs/original-24.obj"/>
321
- </geometry>
322
- </collision>
323
- <collision>
324
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
325
- <geometry>
326
- <mesh filename="textured_objs/original-23.obj"/>
327
- </geometry>
328
- </collision>
329
- <collision>
330
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
331
- <geometry>
332
- <mesh filename="textured_objs/original-33.obj"/>
333
- </geometry>
334
- </collision>
335
- <collision>
336
- <origin xyz="-0.4566900000000005 -0.19353231481404498 0.22"/>
337
- <geometry>
338
- <mesh filename="textured_objs/original-28.obj"/>
339
- </geometry>
340
- </collision>
341
- </link>
342
- <joint name="joint_0" type="revolute">
343
- <origin xyz="0.4566900000000005 0.19353231481404498 -0.22"/>
344
- <axis xyz="-1 0 0"/>
345
- <child link="link_0"/>
346
- <parent link="link_3"/>
347
- <limit lower="-1.6755160819145563" upper="0.3490658503988659"/>
348
- </joint>
349
- <link name="link_1">
350
- <visual name="lock-2">
351
- <origin xyz="0.31702800000000186 -0.12031968844452468 -0.42424240488341747"/>
352
- <geometry>
353
- <mesh filename="textured_objs/original-3.obj"/>
354
- </geometry>
355
- </visual>
356
- <collision>
357
- <origin xyz="0.31702800000000186 -0.12031968844452468 -0.42424240488341747"/>
358
- <geometry>
359
- <mesh filename="textured_objs/original-3.obj"/>
360
- </geometry>
361
- </collision>
362
- </link>
363
- <joint name="joint_1" type="revolute">
364
- <origin xyz="-0.31702800000000186 0.12031968844452468 0.42424240488341747"/>
365
- <axis xyz="-1 0 0"/>
366
- <child link="link_1"/>
367
- <parent link="link_3"/>
368
- <limit lower="-0.0" upper="0.4363323129985824"/>
369
- </joint>
370
- <link name="link_2">
371
- <visual name="lock-3">
372
- <origin xyz="0.31702800000000186 -0.12031968844452468 -0.42424240488341747"/>
373
- <geometry>
374
- <mesh filename="textured_objs/original-7.obj"/>
375
- </geometry>
376
- </visual>
377
- <collision>
378
- <origin xyz="0.31702800000000186 -0.12031968844452468 -0.42424240488341747"/>
379
- <geometry>
380
- <mesh filename="textured_objs/original-7.obj"/>
381
- </geometry>
382
- </collision>
383
- </link>
384
- <joint name="joint_2" type="revolute">
385
- <origin xyz="-0.31702800000000186 0.12031968844452468 0.42424240488341747"/>
386
- <axis xyz="-1 0 0"/>
387
- <child link="link_2"/>
388
- <parent link="link_3"/>
389
- <limit lower="-0.0" upper="0.4363323129985824"/>
390
- </joint>
391
- <link name="link_3">
392
- <visual name="base_body-4">
393
- <origin xyz="0 0 0"/>
394
- <geometry>
395
- <mesh filename="textured_objs/original-2.obj"/>
396
- </geometry>
397
- </visual>
398
- <visual name="base_body-4">
399
- <origin xyz="0 0 0"/>
400
- <geometry>
401
- <mesh filename="textured_objs/original-39.obj"/>
402
- </geometry>
403
- </visual>
404
- <visual name="base_body-4">
405
- <origin xyz="0 0 0"/>
406
- <geometry>
407
- <mesh filename="textured_objs/original-5.obj"/>
408
- </geometry>
409
- </visual>
410
- <visual name="base_body-4">
411
- <origin xyz="0 0 0"/>
412
- <geometry>
413
- <mesh filename="textured_objs/original-6.obj"/>
414
- </geometry>
415
- </visual>
416
- <visual name="base_body-4">
417
- <origin xyz="0 0 0"/>
418
- <geometry>
419
- <mesh filename="textured_objs/original-1.obj"/>
420
- </geometry>
421
- </visual>
422
- <visual name="base_body-4">
423
- <origin xyz="0 0 0"/>
424
- <geometry>
425
- <mesh filename="textured_objs/original-40.obj"/>
426
- </geometry>
427
- </visual>
428
- <collision>
429
- <origin xyz="0 0 0"/>
430
- <geometry>
431
- <mesh filename="textured_objs/original-2.obj"/>
432
- </geometry>
433
- </collision>
434
- <collision>
435
- <origin xyz="0 0 0"/>
436
- <geometry>
437
- <mesh filename="textured_objs/original-39.obj"/>
438
- </geometry>
439
- </collision>
440
- <collision>
441
- <origin xyz="0 0 0"/>
442
- <geometry>
443
- <mesh filename="textured_objs/original-5.obj"/>
444
- </geometry>
445
- </collision>
446
- <collision>
447
- <origin xyz="0 0 0"/>
448
- <geometry>
449
- <mesh filename="textured_objs/original-6.obj"/>
450
- </geometry>
451
- </collision>
452
- <collision>
453
- <origin xyz="0 0 0"/>
454
- <geometry>
455
- <mesh filename="textured_objs/original-1.obj"/>
456
- </geometry>
457
- </collision>
458
- <collision>
459
- <origin xyz="0 0 0"/>
460
- <geometry>
461
- <mesh filename="textured_objs/original-40.obj"/>
462
- </geometry>
463
- </collision>
464
- </link>
465
- <joint name="joint_3" type="fixed">
466
- <origin rpy="1.570796326794897 0 -1.570796326794897" xyz="0 0 0"/>
467
- <child link="link_3"/>
468
- <parent link="base"/>
469
- </joint>
470
- </robot>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
datasets/PartNet/100350/00_pure.png DELETED

Git LFS Details

  • SHA256: c6859dfa3ee63d855627fcd26bc670597ee08216b7dae77a94eb95d46f30799c
  • Pointer size: 131 Bytes
  • Size of remote file: 361 kB
datasets/PartNet/100350/00_seg.png DELETED

Git LFS Details

  • SHA256: a84ee5d5fcc707c531deea773bc6121e16172474b32380e4ebbcd083b11e3daf
  • Pointer size: 131 Bytes
  • Size of remote file: 485 kB
datasets/PartNet/100350/01_pure.png DELETED

Git LFS Details

  • SHA256: ed6770fe362a4dfa50621a0f0107c31081eeeb61b8dfd0d14206739882ec85d1
  • Pointer size: 131 Bytes
  • Size of remote file: 373 kB
datasets/PartNet/100350/01_seg.png DELETED

Git LFS Details

  • SHA256: e5c0615ab6b0985ba3950404063a6631552ff380bb7ce22b95bab3ed7b9a40dc
  • Pointer size: 131 Bytes
  • Size of remote file: 498 kB
datasets/PartNet/100350/02_pure.png DELETED

Git LFS Details

  • SHA256: 325de841f9ac1c133f7278c6be6ab8bf8a3a7c5e48fa36c2eadcf234dbe1e447
  • Pointer size: 131 Bytes
  • Size of remote file: 376 kB
datasets/PartNet/100350/02_seg.png DELETED

Git LFS Details

  • SHA256: a48ce4bc4231554446782ce790b459856d8c66f4568a1b8e9fbca225b85704ce
  • Pointer size: 131 Bytes
  • Size of remote file: 503 kB
datasets/PartNet/100350/03_pure.png DELETED

Git LFS Details

  • SHA256: e82a6fd067fc1eb1a9d3a962e8ae2f2bdc0fa1f7353890189dcf7a4eaf6168ff
  • Pointer size: 131 Bytes
  • Size of remote file: 380 kB
datasets/PartNet/100350/03_seg.png DELETED

Git LFS Details

  • SHA256: 7f2f3f632723440e99edd87253ace8364649172e149323ff9a4772a02f03d962
  • Pointer size: 131 Bytes
  • Size of remote file: 505 kB
datasets/PartNet/100350/04_pure.png DELETED

Git LFS Details

  • SHA256: 8832e175bb3d82918a4f6ea5db5578c164583e4a202db1048f233b3d8799ce44
  • Pointer size: 131 Bytes
  • Size of remote file: 379 kB
datasets/PartNet/100350/04_seg.png DELETED

Git LFS Details

  • SHA256: c7f82f13e4c6707b34e4fa61108bad3eaf385bb03ee94719278d761659275e79
  • Pointer size: 131 Bytes
  • Size of remote file: 500 kB
datasets/PartNet/100350/05_pure.png DELETED

Git LFS Details

  • SHA256: b5af6f52b490e2c970fc7f7692deaa5fd1fe684c75883a8aa8db900d6b6b1dc5
  • Pointer size: 131 Bytes
  • Size of remote file: 382 kB
datasets/PartNet/100350/05_seg.png DELETED

Git LFS Details

  • SHA256: 921d1927a580fc227d127ec84ea423aa3b833f2f847f719eee270baf69c290d2
  • Pointer size: 131 Bytes
  • Size of remote file: 500 kB
datasets/PartNet/100350/gt_mesh/00.glb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:bf6091c51252d287b15c8593ae1ea6c5597ae18bc83ba4b8c1de34b50a8ba5e3
3
- size 786128
 
 
 
 
datasets/PartNet/100350/gt_mesh/01.glb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:4d0cb35167941fea77e80bd5e7d0e74dc206399d6037cf3d4a17af7e2f0004d6
3
- size 787016
 
 
 
 
datasets/PartNet/100350/gt_mesh/02.glb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:223f20abebd138a4144131cbe03e7f731f1a5ad6e6077539697443d915419130
3
- size 786996
 
 
 
 
datasets/PartNet/100350/gt_mesh/03.glb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:992c725b6d5a5e46a5e81820dea75bb97feb2fef055f9df078aee469000cc766
3
- size 786976
 
 
 
 
datasets/PartNet/100350/gt_mesh/04.glb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:2362483d8bc9aca709293d03f4eb49dc1062e4c6dbf213687e896945d85e8b0c
3
- size 787068
 
 
 
 
datasets/PartNet/100350/gt_mesh/05.glb DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:f0b351e9a97d47a1234ddb875dc74bf0fc292a4b2480041920c59de222272941
3
- size 787080
 
 
 
 
datasets/PartNet/100350/joint_info.json DELETED
@@ -1,21 +0,0 @@
1
- [
2
- {
3
- "type": "revolute",
4
- "range": [
5
- -0.0,
6
- 2.9216811678385075
7
- ],
8
- "axis": {
9
- "origin": [
10
- 0.0,
11
- 0.07382043606209616,
12
- 0.5268791881000544
13
- ],
14
- "direction": [
15
- 1.0,
16
- 0.0,
17
- 0.0
18
- ]
19
- }
20
- }
21
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
datasets/PartNet/100350/joints.json DELETED
@@ -1,14 +0,0 @@
1
- {
2
- "category": "Lighter",
3
- "joints": [
4
- "joint_0"
5
- ],
6
- "descendants": {
7
- "joint_0": [],
8
- "joint_1": [],
9
- "joint_2": [
10
- "joint_0",
11
- "joint_1"
12
- ]
13
- }
14
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
datasets/PartNet/100350/mobility.urdf DELETED
@@ -1,904 +0,0 @@
1
- <?xml version="1.0" ?>
2
- <robot name="partnet_u7a32a94d-41d2-4f02-b21c-489a6646b9a5">
3
- <link name="base"/>
4
- <link name="link_0">
5
- <visual name="lid-1">
6
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
7
- <geometry>
8
- <mesh filename="textured_objs/original-50.obj"/>
9
- </geometry>
10
- </visual>
11
- <visual name="lid-1">
12
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
13
- <geometry>
14
- <mesh filename="textured_objs/original-46.obj"/>
15
- </geometry>
16
- </visual>
17
- <visual name="lid-1">
18
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
19
- <geometry>
20
- <mesh filename="textured_objs/original-49.obj"/>
21
- </geometry>
22
- </visual>
23
- <visual name="lid-1">
24
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
25
- <geometry>
26
- <mesh filename="textured_objs/original-54.obj"/>
27
- </geometry>
28
- </visual>
29
- <visual name="lid-1">
30
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
31
- <geometry>
32
- <mesh filename="textured_objs/original-53.obj"/>
33
- </geometry>
34
- </visual>
35
- <visual name="lid-1">
36
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
37
- <geometry>
38
- <mesh filename="textured_objs/original-52.obj"/>
39
- </geometry>
40
- </visual>
41
- <visual name="lid-1">
42
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
43
- <geometry>
44
- <mesh filename="textured_objs/original-51.obj"/>
45
- </geometry>
46
- </visual>
47
- <visual name="lid-1">
48
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
49
- <geometry>
50
- <mesh filename="textured_objs/original-56.obj"/>
51
- </geometry>
52
- </visual>
53
- <visual name="lid-1">
54
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
55
- <geometry>
56
- <mesh filename="textured_objs/original-55.obj"/>
57
- </geometry>
58
- </visual>
59
- <visual name="lid-1">
60
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
61
- <geometry>
62
- <mesh filename="textured_objs/original-47.obj"/>
63
- </geometry>
64
- </visual>
65
- <collision>
66
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
67
- <geometry>
68
- <mesh filename="textured_objs/original-50.obj"/>
69
- </geometry>
70
- </collision>
71
- <collision>
72
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
73
- <geometry>
74
- <mesh filename="textured_objs/original-46.obj"/>
75
- </geometry>
76
- </collision>
77
- <collision>
78
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
79
- <geometry>
80
- <mesh filename="textured_objs/original-49.obj"/>
81
- </geometry>
82
- </collision>
83
- <collision>
84
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
85
- <geometry>
86
- <mesh filename="textured_objs/original-54.obj"/>
87
- </geometry>
88
- </collision>
89
- <collision>
90
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
91
- <geometry>
92
- <mesh filename="textured_objs/original-53.obj"/>
93
- </geometry>
94
- </collision>
95
- <collision>
96
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
97
- <geometry>
98
- <mesh filename="textured_objs/original-52.obj"/>
99
- </geometry>
100
- </collision>
101
- <collision>
102
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
103
- <geometry>
104
- <mesh filename="textured_objs/original-51.obj"/>
105
- </geometry>
106
- </collision>
107
- <collision>
108
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
109
- <geometry>
110
- <mesh filename="textured_objs/original-56.obj"/>
111
- </geometry>
112
- </collision>
113
- <collision>
114
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
115
- <geometry>
116
- <mesh filename="textured_objs/original-55.obj"/>
117
- </geometry>
118
- </collision>
119
- <collision>
120
- <origin xyz="0 -0.07382043606209616 -0.5268791881000544"/>
121
- <geometry>
122
- <mesh filename="textured_objs/original-47.obj"/>
123
- </geometry>
124
- </collision>
125
- </link>
126
- <joint name="joint_0" type="revolute">
127
- <origin xyz="0 0.07382043606209616 0.5268791881000544"/>
128
- <axis xyz="1 0 0"/>
129
- <child link="link_0"/>
130
- <parent link="link_2"/>
131
- <limit lower="-0.0" upper="2.9216811678385075"/>
132
- </joint>
133
- <link name="link_1">
134
- <visual name="wheel-2">
135
- <origin xyz="-0.17066000000000003 -0.37948606312151356 0.2798602405394533"/>
136
- <geometry>
137
- <mesh filename="textured_objs/original-21.obj"/>
138
- </geometry>
139
- </visual>
140
- <collision>
141
- <origin xyz="-0.17066000000000003 -0.37948606312151356 0.2798602405394533"/>
142
- <geometry>
143
- <mesh filename="textured_objs/original-21.obj"/>
144
- </geometry>
145
- </collision>
146
- </link>
147
- <joint name="joint_1" type="continuous">
148
- <origin xyz="0.17066000000000003 0.37948606312151356 -0.2798602405394533"/>
149
- <axis xyz="-1 0 0"/>
150
- <child link="link_1"/>
151
- <parent link="link_2"/>
152
- </joint>
153
- <link name="link_2">
154
- <visual name="base_body-3">
155
- <origin xyz="0 0 0"/>
156
- <geometry>
157
- <mesh filename="textured_objs/original-29.obj"/>
158
- </geometry>
159
- </visual>
160
- <visual name="base_body-3">
161
- <origin xyz="0 0 0"/>
162
- <geometry>
163
- <mesh filename="textured_objs/original-30.obj"/>
164
- </geometry>
165
- </visual>
166
- <visual name="base_body-3">
167
- <origin xyz="0 0 0"/>
168
- <geometry>
169
- <mesh filename="textured_objs/original-36.obj"/>
170
- </geometry>
171
- </visual>
172
- <visual name="base_body-3">
173
- <origin xyz="0 0 0"/>
174
- <geometry>
175
- <mesh filename="textured_objs/original-41.obj"/>
176
- </geometry>
177
- </visual>
178
- <visual name="base_body-3">
179
- <origin xyz="0 0 0"/>
180
- <geometry>
181
- <mesh filename="textured_objs/original-28.obj"/>
182
- </geometry>
183
- </visual>
184
- <visual name="base_body-3">
185
- <origin xyz="0 0 0"/>
186
- <geometry>
187
- <mesh filename="textured_objs/original-64.obj"/>
188
- </geometry>
189
- </visual>
190
- <visual name="base_body-3">
191
- <origin xyz="0 0 0"/>
192
- <geometry>
193
- <mesh filename="textured_objs/original-71.obj"/>
194
- </geometry>
195
- </visual>
196
- <visual name="base_body-3">
197
- <origin xyz="0 0 0"/>
198
- <geometry>
199
- <mesh filename="textured_objs/original-83.obj"/>
200
- </geometry>
201
- </visual>
202
- <visual name="base_body-3">
203
- <origin xyz="0 0 0"/>
204
- <geometry>
205
- <mesh filename="textured_objs/original-22.obj"/>
206
- </geometry>
207
- </visual>
208
- <visual name="base_body-3">
209
- <origin xyz="0 0 0"/>
210
- <geometry>
211
- <mesh filename="textured_objs/original-26.obj"/>
212
- </geometry>
213
- </visual>
214
- <visual name="base_body-3">
215
- <origin xyz="0 0 0"/>
216
- <geometry>
217
- <mesh filename="textured_objs/original-4.obj"/>
218
- </geometry>
219
- </visual>
220
- <visual name="base_body-3">
221
- <origin xyz="0 0 0"/>
222
- <geometry>
223
- <mesh filename="textured_objs/original-3.obj"/>
224
- </geometry>
225
- </visual>
226
- <visual name="base_body-3">
227
- <origin xyz="0 0 0"/>
228
- <geometry>
229
- <mesh filename="textured_objs/original-65.obj"/>
230
- </geometry>
231
- </visual>
232
- <visual name="base_body-3">
233
- <origin xyz="0 0 0"/>
234
- <geometry>
235
- <mesh filename="textured_objs/original-33.obj"/>
236
- </geometry>
237
- </visual>
238
- <visual name="base_body-3">
239
- <origin xyz="0 0 0"/>
240
- <geometry>
241
- <mesh filename="textured_objs/original-2.obj"/>
242
- </geometry>
243
- </visual>
244
- <visual name="base_body-3">
245
- <origin xyz="0 0 0"/>
246
- <geometry>
247
- <mesh filename="textured_objs/original-44.obj"/>
248
- </geometry>
249
- </visual>
250
- <visual name="base_body-3">
251
- <origin xyz="0 0 0"/>
252
- <geometry>
253
- <mesh filename="textured_objs/original-8.obj"/>
254
- </geometry>
255
- </visual>
256
- <visual name="base_body-3">
257
- <origin xyz="0 0 0"/>
258
- <geometry>
259
- <mesh filename="textured_objs/original-9.obj"/>
260
- </geometry>
261
- </visual>
262
- <visual name="base_body-3">
263
- <origin xyz="0 0 0"/>
264
- <geometry>
265
- <mesh filename="textured_objs/original-45.obj"/>
266
- </geometry>
267
- </visual>
268
- <visual name="base_body-3">
269
- <origin xyz="0 0 0"/>
270
- <geometry>
271
- <mesh filename="textured_objs/original-35.obj"/>
272
- </geometry>
273
- </visual>
274
- <visual name="base_body-3">
275
- <origin xyz="0 0 0"/>
276
- <geometry>
277
- <mesh filename="textured_objs/original-61.obj"/>
278
- </geometry>
279
- </visual>
280
- <visual name="base_body-3">
281
- <origin xyz="0 0 0"/>
282
- <geometry>
283
- <mesh filename="textured_objs/original-59.obj"/>
284
- </geometry>
285
- </visual>
286
- <visual name="base_body-3">
287
- <origin xyz="0 0 0"/>
288
- <geometry>
289
- <mesh filename="textured_objs/original-5.obj"/>
290
- </geometry>
291
- </visual>
292
- <visual name="base_body-3">
293
- <origin xyz="0 0 0"/>
294
- <geometry>
295
- <mesh filename="textured_objs/original-77.obj"/>
296
- </geometry>
297
- </visual>
298
- <visual name="base_body-3">
299
- <origin xyz="0 0 0"/>
300
- <geometry>
301
- <mesh filename="textured_objs/original-63.obj"/>
302
- </geometry>
303
- </visual>
304
- <visual name="base_body-3">
305
- <origin xyz="0 0 0"/>
306
- <geometry>
307
- <mesh filename="textured_objs/original-27.obj"/>
308
- </geometry>
309
- </visual>
310
- <visual name="base_body-3">
311
- <origin xyz="0 0 0"/>
312
- <geometry>
313
- <mesh filename="textured_objs/original-6.obj"/>
314
- </geometry>
315
- </visual>
316
- <visual name="base_body-3">
317
- <origin xyz="0 0 0"/>
318
- <geometry>
319
- <mesh filename="textured_objs/original-31.obj"/>
320
- </geometry>
321
- </visual>
322
- <visual name="base_body-3">
323
- <origin xyz="0 0 0"/>
324
- <geometry>
325
- <mesh filename="textured_objs/original-37.obj"/>
326
- </geometry>
327
- </visual>
328
- <visual name="base_body-3">
329
- <origin xyz="0 0 0"/>
330
- <geometry>
331
- <mesh filename="textured_objs/original-15.obj"/>
332
- </geometry>
333
- </visual>
334
- <visual name="base_body-3">
335
- <origin xyz="0 0 0"/>
336
- <geometry>
337
- <mesh filename="textured_objs/original-76.obj"/>
338
- </geometry>
339
- </visual>
340
- <visual name="base_body-3">
341
- <origin xyz="0 0 0"/>
342
- <geometry>
343
- <mesh filename="textured_objs/original-72.obj"/>
344
- </geometry>
345
- </visual>
346
- <visual name="base_body-3">
347
- <origin xyz="0 0 0"/>
348
- <geometry>
349
- <mesh filename="textured_objs/original-62.obj"/>
350
- </geometry>
351
- </visual>
352
- <visual name="base_body-3">
353
- <origin xyz="0 0 0"/>
354
- <geometry>
355
- <mesh filename="textured_objs/original-75.obj"/>
356
- </geometry>
357
- </visual>
358
- <visual name="base_body-3">
359
- <origin xyz="0 0 0"/>
360
- <geometry>
361
- <mesh filename="textured_objs/original-66.obj"/>
362
- </geometry>
363
- </visual>
364
- <visual name="base_body-3">
365
- <origin xyz="0 0 0"/>
366
- <geometry>
367
- <mesh filename="textured_objs/original-58.obj"/>
368
- </geometry>
369
- </visual>
370
- <visual name="base_body-3">
371
- <origin xyz="0 0 0"/>
372
- <geometry>
373
- <mesh filename="textured_objs/original-67.obj"/>
374
- </geometry>
375
- </visual>
376
- <visual name="base_body-3">
377
- <origin xyz="0 0 0"/>
378
- <geometry>
379
- <mesh filename="textured_objs/original-69.obj"/>
380
- </geometry>
381
- </visual>
382
- <visual name="base_body-3">
383
- <origin xyz="0 0 0"/>
384
- <geometry>
385
- <mesh filename="textured_objs/original-11.obj"/>
386
- </geometry>
387
- </visual>
388
- <visual name="base_body-3">
389
- <origin xyz="0 0 0"/>
390
- <geometry>
391
- <mesh filename="textured_objs/original-38.obj"/>
392
- </geometry>
393
- </visual>
394
- <visual name="base_body-3">
395
- <origin xyz="0 0 0"/>
396
- <geometry>
397
- <mesh filename="textured_objs/original-68.obj"/>
398
- </geometry>
399
- </visual>
400
- <visual name="base_body-3">
401
- <origin xyz="0 0 0"/>
402
- <geometry>
403
- <mesh filename="textured_objs/original-80.obj"/>
404
- </geometry>
405
- </visual>
406
- <visual name="base_body-3">
407
- <origin xyz="0 0 0"/>
408
- <geometry>
409
- <mesh filename="textured_objs/original-18.obj"/>
410
- </geometry>
411
- </visual>
412
- <visual name="base_body-3">
413
- <origin xyz="0 0 0"/>
414
- <geometry>
415
- <mesh filename="textured_objs/original-70.obj"/>
416
- </geometry>
417
- </visual>
418
- <visual name="base_body-3">
419
- <origin xyz="0 0 0"/>
420
- <geometry>
421
- <mesh filename="textured_objs/original-74.obj"/>
422
- </geometry>
423
- </visual>
424
- <visual name="base_body-3">
425
- <origin xyz="0 0 0"/>
426
- <geometry>
427
- <mesh filename="textured_objs/original-25.obj"/>
428
- </geometry>
429
- </visual>
430
- <visual name="base_body-3">
431
- <origin xyz="0 0 0"/>
432
- <geometry>
433
- <mesh filename="textured_objs/original-17.obj"/>
434
- </geometry>
435
- </visual>
436
- <visual name="base_body-3">
437
- <origin xyz="0 0 0"/>
438
- <geometry>
439
- <mesh filename="textured_objs/original-73.obj"/>
440
- </geometry>
441
- </visual>
442
- <visual name="base_body-3">
443
- <origin xyz="0 0 0"/>
444
- <geometry>
445
- <mesh filename="textured_objs/original-42.obj"/>
446
- </geometry>
447
- </visual>
448
- <visual name="base_body-3">
449
- <origin xyz="0 0 0"/>
450
- <geometry>
451
- <mesh filename="textured_objs/original-79.obj"/>
452
- </geometry>
453
- </visual>
454
- <visual name="base_body-3">
455
- <origin xyz="0 0 0"/>
456
- <geometry>
457
- <mesh filename="textured_objs/original-24.obj"/>
458
- </geometry>
459
- </visual>
460
- <visual name="base_body-3">
461
- <origin xyz="0 0 0"/>
462
- <geometry>
463
- <mesh filename="textured_objs/original-20.obj"/>
464
- </geometry>
465
- </visual>
466
- <visual name="base_body-3">
467
- <origin xyz="0 0 0"/>
468
- <geometry>
469
- <mesh filename="textured_objs/original-32.obj"/>
470
- </geometry>
471
- </visual>
472
- <visual name="base_body-3">
473
- <origin xyz="0 0 0"/>
474
- <geometry>
475
- <mesh filename="textured_objs/original-7.obj"/>
476
- </geometry>
477
- </visual>
478
- <visual name="base_body-3">
479
- <origin xyz="0 0 0"/>
480
- <geometry>
481
- <mesh filename="textured_objs/original-81.obj"/>
482
- </geometry>
483
- </visual>
484
- <visual name="base_body-3">
485
- <origin xyz="0 0 0"/>
486
- <geometry>
487
- <mesh filename="textured_objs/original-84.obj"/>
488
- </geometry>
489
- </visual>
490
- <visual name="base_body-3">
491
- <origin xyz="0 0 0"/>
492
- <geometry>
493
- <mesh filename="textured_objs/original-78.obj"/>
494
- </geometry>
495
- </visual>
496
- <visual name="base_body-3">
497
- <origin xyz="0 0 0"/>
498
- <geometry>
499
- <mesh filename="textured_objs/original-10.obj"/>
500
- </geometry>
501
- </visual>
502
- <visual name="base_body-3">
503
- <origin xyz="0 0 0"/>
504
- <geometry>
505
- <mesh filename="textured_objs/original-14.obj"/>
506
- </geometry>
507
- </visual>
508
- <visual name="base_body-3">
509
- <origin xyz="0 0 0"/>
510
- <geometry>
511
- <mesh filename="textured_objs/original-82.obj"/>
512
- </geometry>
513
- </visual>
514
- <visual name="base_body-3">
515
- <origin xyz="0 0 0"/>
516
- <geometry>
517
- <mesh filename="textured_objs/original-60.obj"/>
518
- </geometry>
519
- </visual>
520
- <visual name="base_body-3">
521
- <origin xyz="0 0 0"/>
522
- <geometry>
523
- <mesh filename="textured_objs/original-40.obj"/>
524
- </geometry>
525
- </visual>
526
- <collision>
527
- <origin xyz="0 0 0"/>
528
- <geometry>
529
- <mesh filename="textured_objs/original-29.obj"/>
530
- </geometry>
531
- </collision>
532
- <collision>
533
- <origin xyz="0 0 0"/>
534
- <geometry>
535
- <mesh filename="textured_objs/original-30.obj"/>
536
- </geometry>
537
- </collision>
538
- <collision>
539
- <origin xyz="0 0 0"/>
540
- <geometry>
541
- <mesh filename="textured_objs/original-36.obj"/>
542
- </geometry>
543
- </collision>
544
- <collision>
545
- <origin xyz="0 0 0"/>
546
- <geometry>
547
- <mesh filename="textured_objs/original-41.obj"/>
548
- </geometry>
549
- </collision>
550
- <collision>
551
- <origin xyz="0 0 0"/>
552
- <geometry>
553
- <mesh filename="textured_objs/original-28.obj"/>
554
- </geometry>
555
- </collision>
556
- <collision>
557
- <origin xyz="0 0 0"/>
558
- <geometry>
559
- <mesh filename="textured_objs/original-64.obj"/>
560
- </geometry>
561
- </collision>
562
- <collision>
563
- <origin xyz="0 0 0"/>
564
- <geometry>
565
- <mesh filename="textured_objs/original-71.obj"/>
566
- </geometry>
567
- </collision>
568
- <collision>
569
- <origin xyz="0 0 0"/>
570
- <geometry>
571
- <mesh filename="textured_objs/original-83.obj"/>
572
- </geometry>
573
- </collision>
574
- <collision>
575
- <origin xyz="0 0 0"/>
576
- <geometry>
577
- <mesh filename="textured_objs/original-22.obj"/>
578
- </geometry>
579
- </collision>
580
- <collision>
581
- <origin xyz="0 0 0"/>
582
- <geometry>
583
- <mesh filename="textured_objs/original-26.obj"/>
584
- </geometry>
585
- </collision>
586
- <collision>
587
- <origin xyz="0 0 0"/>
588
- <geometry>
589
- <mesh filename="textured_objs/original-4.obj"/>
590
- </geometry>
591
- </collision>
592
- <collision>
593
- <origin xyz="0 0 0"/>
594
- <geometry>
595
- <mesh filename="textured_objs/original-3.obj"/>
596
- </geometry>
597
- </collision>
598
- <collision>
599
- <origin xyz="0 0 0"/>
600
- <geometry>
601
- <mesh filename="textured_objs/original-65.obj"/>
602
- </geometry>
603
- </collision>
604
- <collision>
605
- <origin xyz="0 0 0"/>
606
- <geometry>
607
- <mesh filename="textured_objs/original-33.obj"/>
608
- </geometry>
609
- </collision>
610
- <collision>
611
- <origin xyz="0 0 0"/>
612
- <geometry>
613
- <mesh filename="textured_objs/original-2.obj"/>
614
- </geometry>
615
- </collision>
616
- <collision>
617
- <origin xyz="0 0 0"/>
618
- <geometry>
619
- <mesh filename="textured_objs/original-44.obj"/>
620
- </geometry>
621
- </collision>
622
- <collision>
623
- <origin xyz="0 0 0"/>
624
- <geometry>
625
- <mesh filename="textured_objs/original-8.obj"/>
626
- </geometry>
627
- </collision>
628
- <collision>
629
- <origin xyz="0 0 0"/>
630
- <geometry>
631
- <mesh filename="textured_objs/original-9.obj"/>
632
- </geometry>
633
- </collision>
634
- <collision>
635
- <origin xyz="0 0 0"/>
636
- <geometry>
637
- <mesh filename="textured_objs/original-45.obj"/>
638
- </geometry>
639
- </collision>
640
- <collision>
641
- <origin xyz="0 0 0"/>
642
- <geometry>
643
- <mesh filename="textured_objs/original-35.obj"/>
644
- </geometry>
645
- </collision>
646
- <collision>
647
- <origin xyz="0 0 0"/>
648
- <geometry>
649
- <mesh filename="textured_objs/original-61.obj"/>
650
- </geometry>
651
- </collision>
652
- <collision>
653
- <origin xyz="0 0 0"/>
654
- <geometry>
655
- <mesh filename="textured_objs/original-59.obj"/>
656
- </geometry>
657
- </collision>
658
- <collision>
659
- <origin xyz="0 0 0"/>
660
- <geometry>
661
- <mesh filename="textured_objs/original-5.obj"/>
662
- </geometry>
663
- </collision>
664
- <collision>
665
- <origin xyz="0 0 0"/>
666
- <geometry>
667
- <mesh filename="textured_objs/original-77.obj"/>
668
- </geometry>
669
- </collision>
670
- <collision>
671
- <origin xyz="0 0 0"/>
672
- <geometry>
673
- <mesh filename="textured_objs/original-63.obj"/>
674
- </geometry>
675
- </collision>
676
- <collision>
677
- <origin xyz="0 0 0"/>
678
- <geometry>
679
- <mesh filename="textured_objs/original-27.obj"/>
680
- </geometry>
681
- </collision>
682
- <collision>
683
- <origin xyz="0 0 0"/>
684
- <geometry>
685
- <mesh filename="textured_objs/original-6.obj"/>
686
- </geometry>
687
- </collision>
688
- <collision>
689
- <origin xyz="0 0 0"/>
690
- <geometry>
691
- <mesh filename="textured_objs/original-31.obj"/>
692
- </geometry>
693
- </collision>
694
- <collision>
695
- <origin xyz="0 0 0"/>
696
- <geometry>
697
- <mesh filename="textured_objs/original-37.obj"/>
698
- </geometry>
699
- </collision>
700
- <collision>
701
- <origin xyz="0 0 0"/>
702
- <geometry>
703
- <mesh filename="textured_objs/original-15.obj"/>
704
- </geometry>
705
- </collision>
706
- <collision>
707
- <origin xyz="0 0 0"/>
708
- <geometry>
709
- <mesh filename="textured_objs/original-76.obj"/>
710
- </geometry>
711
- </collision>
712
- <collision>
713
- <origin xyz="0 0 0"/>
714
- <geometry>
715
- <mesh filename="textured_objs/original-72.obj"/>
716
- </geometry>
717
- </collision>
718
- <collision>
719
- <origin xyz="0 0 0"/>
720
- <geometry>
721
- <mesh filename="textured_objs/original-62.obj"/>
722
- </geometry>
723
- </collision>
724
- <collision>
725
- <origin xyz="0 0 0"/>
726
- <geometry>
727
- <mesh filename="textured_objs/original-75.obj"/>
728
- </geometry>
729
- </collision>
730
- <collision>
731
- <origin xyz="0 0 0"/>
732
- <geometry>
733
- <mesh filename="textured_objs/original-66.obj"/>
734
- </geometry>
735
- </collision>
736
- <collision>
737
- <origin xyz="0 0 0"/>
738
- <geometry>
739
- <mesh filename="textured_objs/original-58.obj"/>
740
- </geometry>
741
- </collision>
742
- <collision>
743
- <origin xyz="0 0 0"/>
744
- <geometry>
745
- <mesh filename="textured_objs/original-67.obj"/>
746
- </geometry>
747
- </collision>
748
- <collision>
749
- <origin xyz="0 0 0"/>
750
- <geometry>
751
- <mesh filename="textured_objs/original-69.obj"/>
752
- </geometry>
753
- </collision>
754
- <collision>
755
- <origin xyz="0 0 0"/>
756
- <geometry>
757
- <mesh filename="textured_objs/original-11.obj"/>
758
- </geometry>
759
- </collision>
760
- <collision>
761
- <origin xyz="0 0 0"/>
762
- <geometry>
763
- <mesh filename="textured_objs/original-38.obj"/>
764
- </geometry>
765
- </collision>
766
- <collision>
767
- <origin xyz="0 0 0"/>
768
- <geometry>
769
- <mesh filename="textured_objs/original-68.obj"/>
770
- </geometry>
771
- </collision>
772
- <collision>
773
- <origin xyz="0 0 0"/>
774
- <geometry>
775
- <mesh filename="textured_objs/original-80.obj"/>
776
- </geometry>
777
- </collision>
778
- <collision>
779
- <origin xyz="0 0 0"/>
780
- <geometry>
781
- <mesh filename="textured_objs/original-18.obj"/>
782
- </geometry>
783
- </collision>
784
- <collision>
785
- <origin xyz="0 0 0"/>
786
- <geometry>
787
- <mesh filename="textured_objs/original-70.obj"/>
788
- </geometry>
789
- </collision>
790
- <collision>
791
- <origin xyz="0 0 0"/>
792
- <geometry>
793
- <mesh filename="textured_objs/original-74.obj"/>
794
- </geometry>
795
- </collision>
796
- <collision>
797
- <origin xyz="0 0 0"/>
798
- <geometry>
799
- <mesh filename="textured_objs/original-25.obj"/>
800
- </geometry>
801
- </collision>
802
- <collision>
803
- <origin xyz="0 0 0"/>
804
- <geometry>
805
- <mesh filename="textured_objs/original-17.obj"/>
806
- </geometry>
807
- </collision>
808
- <collision>
809
- <origin xyz="0 0 0"/>
810
- <geometry>
811
- <mesh filename="textured_objs/original-73.obj"/>
812
- </geometry>
813
- </collision>
814
- <collision>
815
- <origin xyz="0 0 0"/>
816
- <geometry>
817
- <mesh filename="textured_objs/original-42.obj"/>
818
- </geometry>
819
- </collision>
820
- <collision>
821
- <origin xyz="0 0 0"/>
822
- <geometry>
823
- <mesh filename="textured_objs/original-79.obj"/>
824
- </geometry>
825
- </collision>
826
- <collision>
827
- <origin xyz="0 0 0"/>
828
- <geometry>
829
- <mesh filename="textured_objs/original-24.obj"/>
830
- </geometry>
831
- </collision>
832
- <collision>
833
- <origin xyz="0 0 0"/>
834
- <geometry>
835
- <mesh filename="textured_objs/original-20.obj"/>
836
- </geometry>
837
- </collision>
838
- <collision>
839
- <origin xyz="0 0 0"/>
840
- <geometry>
841
- <mesh filename="textured_objs/original-32.obj"/>
842
- </geometry>
843
- </collision>
844
- <collision>
845
- <origin xyz="0 0 0"/>
846
- <geometry>
847
- <mesh filename="textured_objs/original-7.obj"/>
848
- </geometry>
849
- </collision>
850
- <collision>
851
- <origin xyz="0 0 0"/>
852
- <geometry>
853
- <mesh filename="textured_objs/original-81.obj"/>
854
- </geometry>
855
- </collision>
856
- <collision>
857
- <origin xyz="0 0 0"/>
858
- <geometry>
859
- <mesh filename="textured_objs/original-84.obj"/>
860
- </geometry>
861
- </collision>
862
- <collision>
863
- <origin xyz="0 0 0"/>
864
- <geometry>
865
- <mesh filename="textured_objs/original-78.obj"/>
866
- </geometry>
867
- </collision>
868
- <collision>
869
- <origin xyz="0 0 0"/>
870
- <geometry>
871
- <mesh filename="textured_objs/original-10.obj"/>
872
- </geometry>
873
- </collision>
874
- <collision>
875
- <origin xyz="0 0 0"/>
876
- <geometry>
877
- <mesh filename="textured_objs/original-14.obj"/>
878
- </geometry>
879
- </collision>
880
- <collision>
881
- <origin xyz="0 0 0"/>
882
- <geometry>
883
- <mesh filename="textured_objs/original-82.obj"/>
884
- </geometry>
885
- </collision>
886
- <collision>
887
- <origin xyz="0 0 0"/>
888
- <geometry>
889
- <mesh filename="textured_objs/original-60.obj"/>
890
- </geometry>
891
- </collision>
892
- <collision>
893
- <origin xyz="0 0 0"/>
894
- <geometry>
895
- <mesh filename="textured_objs/original-40.obj"/>
896
- </geometry>
897
- </collision>
898
- </link>
899
- <joint name="joint_2" type="fixed">
900
- <origin rpy="1.570796326794897 0 -1.570796326794897" xyz="0 0 0"/>
901
- <child link="link_2"/>
902
- <parent link="base"/>
903
- </joint>
904
- </robot>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
datasets/PartNet/101363/00_pure.png DELETED

Git LFS Details

  • SHA256: 131f1d7ddd43d8ace513ad4e215fafc5d209b8dfb0ff23e0ac4c0cc73cb49750
  • Pointer size: 131 Bytes
  • Size of remote file: 411 kB
datasets/PartNet/101363/00_seg.png DELETED

Git LFS Details

  • SHA256: 1db3291d308cc71ea547cbda5005c4392e65c4cdf7fa265382d4c4cea8b295fa
  • Pointer size: 131 Bytes
  • Size of remote file: 527 kB