Spaces:
Running
on
Zero
Running
on
Zero
Upload folder using huggingface_hub
Browse files- README.md +37 -11
- assets/qrcode/discord.png +0 -0
- assets/qrcode/wechat.png +0 -0
- assets/qrcode/x.png +0 -0
- assets/qrcode/xiaohongshu.png +0 -0
- gradio_app.py +4 -4
- hg_app.py +67 -56
- minimal_demo.py +11 -2
README.md
CHANGED
@@ -10,20 +10,23 @@ pinned: false
|
|
10 |
short_description: Text-to-3D and Image-to-3D Generation
|
11 |
---
|
12 |
|
|
|
13 |
[中文阅读](README_zh_cn.md)
|
|
|
14 |
|
15 |
-
<p align="center">
|
16 |
<img src="./assets/images/teaser.jpg">
|
17 |
|
18 |
|
19 |
</p>
|
20 |
|
21 |
<div align="center">
|
22 |
-
<a href=https://3d.hunyuan.tencent.com target="_blank"><img src=https://img.shields.io/badge/
|
23 |
<a href=https://huggingface.co/spaces/tencent/Hunyuan3D-2 target="_blank"><img src=https://img.shields.io/badge/%F0%9F%A4%97%20Demo-276cb4.svg height=22px></a>
|
24 |
<a href=https://huggingface.co/tencent/Hunyuan3D-2 target="_blank"><img src=https://img.shields.io/badge/%F0%9F%A4%97%20Models-d96902.svg height=22px></a>
|
25 |
<a href=https://3d-models.hunyuan.tencent.com/ target="_blank"><img src= https://img.shields.io/badge/Page-bb8a2e.svg?logo=github height=22px></a>
|
26 |
-
<a href=https://discord.gg/GuaWYwzKbX target="_blank"><img src= https://img.shields.io/badge/
|
|
|
27 |
</div>
|
28 |
|
29 |
|
@@ -33,14 +36,21 @@ short_description: Text-to-3D and Image-to-3D Generation
|
|
33 |
|
34 |
[//]: # ( <a href="#"><img alt="PyPI - Downloads" src="https://img.shields.io/pypi/v/mulankit?logo=pypi" height=22px></a>)
|
35 |
|
36 |
-
|
|
|
|
|
37 |
<p align="center">
|
38 |
“ Living out everyone’s imagination on creating and manipulating 3D assets.”
|
39 |
</p>
|
40 |
|
41 |
## 🔥 News
|
42 |
|
43 |
-
- Jan 21, 2025: 💬
|
|
|
|
|
|
|
|
|
|
|
44 |
|
45 |
## **Abstract**
|
46 |
|
@@ -92,8 +102,8 @@ and the condition following ability.
|
|
92 |
|
93 |
Generation results of Hunyuan3D 2.0:
|
94 |
<p align="left">
|
95 |
-
<img src="assets/images/e2e-1.gif" height=
|
96 |
-
<img src="assets/images/e2e-2.gif" height=
|
97 |
</p>
|
98 |
|
99 |
### Pretrained Models
|
@@ -159,7 +169,6 @@ for handcrafted mesh**.
|
|
159 |
You could also host a [Gradio](https://www.gradio.app/) App in your own computer via:
|
160 |
|
161 |
```bash
|
162 |
-
pip3 install gradio==3.39.0
|
163 |
python3 gradio_app.py
|
164 |
```
|
165 |
|
@@ -169,12 +178,13 @@ Don't forget to visit [Hunyuan3D](https://3d.hunyuan.tencent.com) for quick use,
|
|
169 |
|
170 |
- [x] Inference Code
|
171 |
- [x] Model Checkpoints
|
|
|
172 |
- [ ] ComfyUI
|
173 |
- [ ] TensorRT Version
|
174 |
|
175 |
## 🔗 BibTeX
|
176 |
|
177 |
-
If you found this repository helpful, please cite our
|
178 |
|
179 |
```bibtex
|
180 |
@misc{hunyuan3d22025tencent,
|
@@ -182,13 +192,29 @@ If you found this repository helpful, please cite our report:
|
|
182 |
author={Tencent Hunyuan3D Team},
|
183 |
year={2025},
|
184 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
```
|
186 |
|
187 |
## Acknowledgements
|
188 |
|
189 |
We would like to thank the contributors to
|
190 |
-
the [DINOv2](https://github.com/facebookresearch/dinov2), [Stable Diffusion](https://github.com/Stability-AI/stablediffusion), [FLUX](https://github.com/black-forest-labs/flux), [diffusers](https://github.com/huggingface/diffusers)
|
191 |
-
and [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
192 |
|
193 |
## Star History
|
194 |
|
|
|
10 |
short_description: Text-to-3D and Image-to-3D Generation
|
11 |
---
|
12 |
|
13 |
+
|
14 |
[中文阅读](README_zh_cn.md)
|
15 |
+
[日本語で読む](README_ja_jp.md)
|
16 |
|
17 |
+
<p align="center">
|
18 |
<img src="./assets/images/teaser.jpg">
|
19 |
|
20 |
|
21 |
</p>
|
22 |
|
23 |
<div align="center">
|
24 |
+
<a href=https://3d.hunyuan.tencent.com target="_blank"><img src=https://img.shields.io/badge/Official%20Site-black.svg?logo=homepage height=22px></a>
|
25 |
<a href=https://huggingface.co/spaces/tencent/Hunyuan3D-2 target="_blank"><img src=https://img.shields.io/badge/%F0%9F%A4%97%20Demo-276cb4.svg height=22px></a>
|
26 |
<a href=https://huggingface.co/tencent/Hunyuan3D-2 target="_blank"><img src=https://img.shields.io/badge/%F0%9F%A4%97%20Models-d96902.svg height=22px></a>
|
27 |
<a href=https://3d-models.hunyuan.tencent.com/ target="_blank"><img src= https://img.shields.io/badge/Page-bb8a2e.svg?logo=github height=22px></a>
|
28 |
+
<a href=https://discord.gg/GuaWYwzKbX target="_blank"><img src= https://img.shields.io/badge/Discord-white.svg?logo=discord height=22px></a>
|
29 |
+
<a href=https://github.com/Tencent/Hunyuan3D-2/blob/main/assets/report/Tencent_Hunyuan3D_2_0.pdf target="_blank"><img src=https://img.shields.io/badge/Report-b5212f.svg?logo=arxiv height=22px></a>
|
30 |
</div>
|
31 |
|
32 |
|
|
|
36 |
|
37 |
[//]: # ( <a href="#"><img alt="PyPI - Downloads" src="https://img.shields.io/pypi/v/mulankit?logo=pypi" height=22px></a>)
|
38 |
|
39 |
+
> Join our **[Wechat](#find-us)** and **[Discord](#find-us)** group to discuss and find help from us.
|
40 |
+
|
41 |
+
|
42 |
<p align="center">
|
43 |
“ Living out everyone’s imagination on creating and manipulating 3D assets.”
|
44 |
</p>
|
45 |
|
46 |
## 🔥 News
|
47 |
|
48 |
+
- Jan 21, 2025: 💬 Enjoy exciting 3D generation on our website [Hunyuan3D Studio](https://3d.hunyuan.tencent.com)!
|
49 |
+
- Jan 21, 2025: 💬 Release inference code and pretrained models
|
50 |
+
of [Hunyuan3D 2.0](https://huggingface.co/tencent/Hunyuan3D-2).
|
51 |
+
- Jan 21, 2025: 💬 Release Hunyuan3D 2.0. Please give it a try
|
52 |
+
via [huggingface space](https://huggingface.co/spaces/tencent/Hunyuan3D-2)
|
53 |
+
our [official site](https://3d.hunyuan.tencent.com)!
|
54 |
|
55 |
## **Abstract**
|
56 |
|
|
|
102 |
|
103 |
Generation results of Hunyuan3D 2.0:
|
104 |
<p align="left">
|
105 |
+
<img src="assets/images/e2e-1.gif" height=250>
|
106 |
+
<img src="assets/images/e2e-2.gif" height=250>
|
107 |
</p>
|
108 |
|
109 |
### Pretrained Models
|
|
|
169 |
You could also host a [Gradio](https://www.gradio.app/) App in your own computer via:
|
170 |
|
171 |
```bash
|
|
|
172 |
python3 gradio_app.py
|
173 |
```
|
174 |
|
|
|
178 |
|
179 |
- [x] Inference Code
|
180 |
- [x] Model Checkpoints
|
181 |
+
- [x] Technical Report
|
182 |
- [ ] ComfyUI
|
183 |
- [ ] TensorRT Version
|
184 |
|
185 |
## 🔗 BibTeX
|
186 |
|
187 |
+
If you found this repository helpful, please cite our reports:
|
188 |
|
189 |
```bibtex
|
190 |
@misc{hunyuan3d22025tencent,
|
|
|
192 |
author={Tencent Hunyuan3D Team},
|
193 |
year={2025},
|
194 |
}
|
195 |
+
|
196 |
+
@misc{yang2024tencent,
|
197 |
+
title={Tencent Hunyuan3D-1.0: A Unified Framework for Text-to-3D and Image-to-3D Generation},
|
198 |
+
year={2024},
|
199 |
+
author={Tencent Hunyuan3D Team},
|
200 |
+
eprint={2411.02293},
|
201 |
+
archivePrefix={arXiv},
|
202 |
+
primaryClass={cs.CV}
|
203 |
+
}
|
204 |
```
|
205 |
|
206 |
## Acknowledgements
|
207 |
|
208 |
We would like to thank the contributors to
|
209 |
+
the [DINOv2](https://github.com/facebookresearch/dinov2), [Stable Diffusion](https://github.com/Stability-AI/stablediffusion), [FLUX](https://github.com/black-forest-labs/flux), [diffusers](https://github.com/huggingface/diffusers), [HuggingFace](https://huggingface.co), [CraftsMan3D](https://github.com/wyysf-98/CraftsMan3D),
|
210 |
+
and [Michelangelo](https://github.com/NeuralCarver/Michelangelo/tree/main) repositories, for their open research and
|
211 |
+
exploration.
|
212 |
+
|
213 |
+
## Find Us
|
214 |
+
|
215 |
+
| Wechat Group | Xiaohongshu | X | Discord |
|
216 |
+
|--------------|-------------|---|---------|
|
217 |
+
| | | | |
|
218 |
|
219 |
## Star History
|
220 |
|
assets/qrcode/discord.png
ADDED
assets/qrcode/wechat.png
ADDED
assets/qrcode/x.png
ADDED
assets/qrcode/xiaohongshu.png
ADDED
gradio_app.py
CHANGED
@@ -138,7 +138,7 @@ def _gen_shape(
|
|
138 |
time_meta['image_to_textured_3d'] = {'total': time.time() - start_time}
|
139 |
time_meta['total'] = time.time() - start_time_0
|
140 |
stats['time'] = time_meta
|
141 |
-
return mesh, save_folder
|
142 |
|
143 |
|
144 |
def generation_all(
|
@@ -150,7 +150,7 @@ def generation_all(
|
|
150 |
octree_resolution=256,
|
151 |
check_box_rembg=False
|
152 |
):
|
153 |
-
mesh, save_folder = _gen_shape(
|
154 |
caption,
|
155 |
image,
|
156 |
steps=steps,
|
@@ -183,7 +183,7 @@ def shape_generation(
|
|
183 |
octree_resolution=256,
|
184 |
check_box_rembg=False,
|
185 |
):
|
186 |
-
mesh, save_folder = _gen_shape(
|
187 |
caption,
|
188 |
image,
|
189 |
steps=steps,
|
@@ -366,7 +366,7 @@ if __name__ == '__main__':
|
|
366 |
if args.enable_t23d:
|
367 |
from hy3dgen.text2image import HunyuanDiTPipeline
|
368 |
|
369 |
-
t2i_worker = HunyuanDiTPipeline('Tencent-Hunyuan
|
370 |
HAS_T2I = True
|
371 |
|
372 |
from hy3dgen.shapegen import FaceReducer, FloaterRemover, DegenerateFaceRemover, \
|
|
|
138 |
time_meta['image_to_textured_3d'] = {'total': time.time() - start_time}
|
139 |
time_meta['total'] = time.time() - start_time_0
|
140 |
stats['time'] = time_meta
|
141 |
+
return mesh, image, save_folder
|
142 |
|
143 |
|
144 |
def generation_all(
|
|
|
150 |
octree_resolution=256,
|
151 |
check_box_rembg=False
|
152 |
):
|
153 |
+
mesh, image, save_folder = _gen_shape(
|
154 |
caption,
|
155 |
image,
|
156 |
steps=steps,
|
|
|
183 |
octree_resolution=256,
|
184 |
check_box_rembg=False,
|
185 |
):
|
186 |
+
mesh, image, save_folder = _gen_shape(
|
187 |
caption,
|
188 |
image,
|
189 |
steps=steps,
|
|
|
366 |
if args.enable_t23d:
|
367 |
from hy3dgen.text2image import HunyuanDiTPipeline
|
368 |
|
369 |
+
t2i_worker = HunyuanDiTPipeline('Tencent-Hunyuan--HunyuanDiT-v1.1-Diffusers-Distilled')
|
370 |
HAS_T2I = True
|
371 |
|
372 |
from hy3dgen.shapegen import FaceReducer, FloaterRemover, DegenerateFaceRemover, \
|
hg_app.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
# pip install gradio==4.44.1
|
2 |
-
if
|
3 |
import os
|
4 |
import spaces
|
5 |
import subprocess
|
@@ -9,8 +9,8 @@ if True:
|
|
9 |
print("cd /home/user/app/hy3dgen/texgen/differentiable_renderer/ && bash compile_mesh_painter.sh")
|
10 |
os.system("cd /home/user/app/hy3dgen/texgen/differentiable_renderer/ && bash compile_mesh_painter.sh")
|
11 |
print('install custom')
|
12 |
-
subprocess.run(shlex.split("pip install custom_rasterizer-0.1-cp310-cp310-linux_x86_64.whl"), check=True)
|
13 |
-
|
14 |
IP = "0.0.0.0"
|
15 |
PORT = 7860
|
16 |
|
@@ -29,7 +29,9 @@ import shutil
|
|
29 |
import time
|
30 |
from glob import glob
|
31 |
from pathlib import Path
|
32 |
-
|
|
|
|
|
33 |
import gradio as gr
|
34 |
import torch
|
35 |
import uvicorn
|
@@ -37,6 +39,14 @@ from fastapi import FastAPI
|
|
37 |
from fastapi.staticfiles import StaticFiles
|
38 |
|
39 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
def get_example_img_list():
|
41 |
print('Loading example img list ...')
|
42 |
return sorted(glob('./assets/example_images/*.png'))
|
@@ -50,19 +60,6 @@ def get_example_txt_list():
|
|
50 |
return txt_list
|
51 |
|
52 |
|
53 |
-
def gen_save_folder(max_size=60):
|
54 |
-
os.makedirs(SAVE_DIR, exist_ok=True)
|
55 |
-
exists = set(int(_) for _ in os.listdir(SAVE_DIR) if not _.startswith("."))
|
56 |
-
cur_id = min(set(range(max_size)) - exists) if len(exists) < max_size else -1
|
57 |
-
if os.path.exists(f"{SAVE_DIR}/{(cur_id + 1) % max_size}"):
|
58 |
-
shutil.rmtree(f"{SAVE_DIR}/{(cur_id + 1) % max_size}")
|
59 |
-
print(f"remove {SAVE_DIR}/{(cur_id + 1) % max_size} success !!!")
|
60 |
-
save_folder = f"{SAVE_DIR}/{max(0, cur_id)}"
|
61 |
-
os.makedirs(save_folder, exist_ok=True)
|
62 |
-
print(f"mkdir {save_folder} suceess !!!")
|
63 |
-
return save_folder
|
64 |
-
|
65 |
-
|
66 |
def export_mesh(mesh, save_folder, textured=False):
|
67 |
if textured:
|
68 |
path = os.path.join(save_folder, f'textured_mesh.glb')
|
@@ -71,16 +68,15 @@ def export_mesh(mesh, save_folder, textured=False):
|
|
71 |
mesh.export(path, include_normals=textured)
|
72 |
return path
|
73 |
|
74 |
-
|
75 |
def build_model_viewer_html(save_folder, height=660, width=790, textured=False):
|
76 |
if textured:
|
77 |
related_path = f"./textured_mesh.glb"
|
78 |
template_name = './assets/modelviewer-textured-template.html'
|
79 |
-
output_html_path = os.path.join(save_folder, f'
|
80 |
else:
|
81 |
related_path = f"./white_mesh.glb"
|
82 |
template_name = './assets/modelviewer-template.html'
|
83 |
-
output_html_path = os.path.join(save_folder, f'
|
84 |
|
85 |
with open(os.path.join(CURRENT_DIR, template_name), 'r') as f:
|
86 |
template_html = f.read()
|
@@ -111,18 +107,20 @@ def build_model_viewer_html(save_folder, height=660, width=790, textured=False):
|
|
111 |
</div>
|
112 |
"""
|
113 |
|
|
|
114 |
@spaces.GPU(duration=100)
|
115 |
def _gen_shape(
|
116 |
-
caption,
|
117 |
-
image,
|
118 |
-
steps
|
119 |
-
guidance_scale
|
120 |
-
seed
|
121 |
-
octree_resolution
|
122 |
-
check_box_rembg
|
|
|
123 |
):
|
124 |
if caption: print('prompt is', caption)
|
125 |
-
save_folder =
|
126 |
stats = {}
|
127 |
time_meta = {}
|
128 |
start_time_0 = time.time()
|
@@ -137,7 +135,7 @@ def _gen_shape(
|
|
137 |
|
138 |
image.save(os.path.join(save_folder, 'input.png'))
|
139 |
|
140 |
-
print(image.mode)
|
141 |
if check_box_rembg or image.mode == "RGB":
|
142 |
start_time = time.time()
|
143 |
image = rmbg_worker(image.convert('RGB'))
|
@@ -168,17 +166,20 @@ def _gen_shape(
|
|
168 |
time_meta['image_to_textured_3d'] = {'total': time.time() - start_time}
|
169 |
time_meta['total'] = time.time() - start_time_0
|
170 |
stats['time'] = time_meta
|
|
|
|
|
171 |
return mesh, save_folder, image
|
172 |
|
173 |
@spaces.GPU(duration=150)
|
174 |
def generation_all(
|
175 |
-
caption,
|
176 |
-
image,
|
177 |
-
steps
|
178 |
-
guidance_scale
|
179 |
-
seed
|
180 |
-
octree_resolution
|
181 |
-
check_box_rembg
|
|
|
182 |
):
|
183 |
mesh, save_folder, image = _gen_shape(
|
184 |
caption,
|
@@ -187,7 +188,8 @@ def generation_all(
|
|
187 |
guidance_scale=guidance_scale,
|
188 |
seed=seed,
|
189 |
octree_resolution=octree_resolution,
|
190 |
-
check_box_rembg=check_box_rembg
|
|
|
191 |
)
|
192 |
path = export_mesh(mesh, save_folder, textured=False)
|
193 |
model_viewer_html = build_model_viewer_html(save_folder, height=596, width=700)
|
@@ -196,22 +198,24 @@ def generation_all(
|
|
196 |
path_textured = export_mesh(textured_mesh, save_folder, textured=True)
|
197 |
model_viewer_html_textured = build_model_viewer_html(save_folder, height=596, width=700, textured=True)
|
198 |
|
|
|
199 |
return (
|
200 |
-
|
201 |
-
|
202 |
model_viewer_html,
|
203 |
model_viewer_html_textured,
|
204 |
)
|
205 |
|
206 |
@spaces.GPU(duration=100)
|
207 |
def shape_generation(
|
208 |
-
caption,
|
209 |
-
image,
|
210 |
-
steps
|
211 |
-
guidance_scale
|
212 |
-
seed
|
213 |
-
octree_resolution
|
214 |
-
check_box_rembg
|
|
|
215 |
):
|
216 |
mesh, save_folder, image = _gen_shape(
|
217 |
caption,
|
@@ -220,14 +224,15 @@ def shape_generation(
|
|
220 |
guidance_scale=guidance_scale,
|
221 |
seed=seed,
|
222 |
octree_resolution=octree_resolution,
|
223 |
-
check_box_rembg=check_box_rembg
|
|
|
224 |
)
|
225 |
|
226 |
path = export_mesh(mesh, save_folder, textured=False)
|
227 |
model_viewer_html = build_model_viewer_html(save_folder, height=596, width=700)
|
228 |
|
229 |
return (
|
230 |
-
|
231 |
model_viewer_html,
|
232 |
)
|
233 |
|
@@ -249,7 +254,7 @@ def build_app():
|
|
249 |
</div>
|
250 |
"""
|
251 |
|
252 |
-
with gr.Blocks(theme=gr.themes.Base(), title='Hunyuan-3D-2.0') as demo:
|
253 |
gr.HTML(title_html)
|
254 |
|
255 |
with gr.Row():
|
@@ -275,9 +280,13 @@ def build_app():
|
|
275 |
btn = gr.Button(value='Generate Shape Only', variant='primary')
|
276 |
btn_all = gr.Button(value='Generate Shape and Texture', variant='primary', visible=HAS_TEXTUREGEN)
|
277 |
|
|
|
|
|
|
|
|
|
278 |
with gr.Group():
|
279 |
-
file_out = gr.
|
280 |
-
file_out2 = gr.
|
281 |
|
282 |
with gr.Column(scale=5):
|
283 |
with gr.Tabs():
|
@@ -331,7 +340,7 @@ def build_app():
|
|
331 |
],
|
332 |
outputs=[file_out, html_output1]
|
333 |
).then(
|
334 |
-
lambda: gr.
|
335 |
outputs=[file_out],
|
336 |
)
|
337 |
|
@@ -348,10 +357,13 @@ def build_app():
|
|
348 |
],
|
349 |
outputs=[file_out, file_out2, html_output1, html_output2]
|
350 |
).then(
|
351 |
-
lambda: (gr.
|
352 |
outputs=[file_out, file_out2],
|
353 |
)
|
354 |
|
|
|
|
|
|
|
355 |
return demo
|
356 |
|
357 |
|
@@ -364,10 +376,9 @@ if __name__ == '__main__':
|
|
364 |
parser.add_argument('--enable_t23d', default=True)
|
365 |
args = parser.parse_args()
|
366 |
|
367 |
-
SAVE_DIR = args.cache_path
|
368 |
-
os.makedirs(SAVE_DIR, exist_ok=True)
|
369 |
-
|
370 |
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
371 |
|
372 |
HTML_OUTPUT_PLACEHOLDER = """
|
373 |
<div style='height: 596px; width: 100%; border-radius: 8px; border-color: #e5e7eb; order-style: solid; border-width: 1px;'></div>
|
|
|
1 |
# pip install gradio==4.44.1
|
2 |
+
if False:
|
3 |
import os
|
4 |
import spaces
|
5 |
import subprocess
|
|
|
9 |
print("cd /home/user/app/hy3dgen/texgen/differentiable_renderer/ && bash compile_mesh_painter.sh")
|
10 |
os.system("cd /home/user/app/hy3dgen/texgen/differentiable_renderer/ && bash compile_mesh_painter.sh")
|
11 |
print('install custom')
|
12 |
+
subprocess.run(shlex.split("pip install custom_rasterizer-0.1-cp310-cp310-linux_x86_64.whl"), check=True)
|
13 |
+
|
14 |
IP = "0.0.0.0"
|
15 |
PORT = 7860
|
16 |
|
|
|
29 |
import time
|
30 |
from glob import glob
|
31 |
from pathlib import Path
|
32 |
+
from PIL import Image
|
33 |
+
from datetime import datetime
|
34 |
+
import uuid
|
35 |
import gradio as gr
|
36 |
import torch
|
37 |
import uvicorn
|
|
|
39 |
from fastapi.staticfiles import StaticFiles
|
40 |
|
41 |
|
42 |
+
def start_session(req: gr.Request):
|
43 |
+
save_folder = os.path.join(SAVE_DIR, str(req.session_hash))
|
44 |
+
os.makedirs(save_folder, exist_ok=True)
|
45 |
+
|
46 |
+
def end_session(req: gr.Request):
|
47 |
+
save_folder = os.path.join(SAVE_DIR, str(req.session_hash))
|
48 |
+
shutil.rmtree(save_folder)
|
49 |
+
|
50 |
def get_example_img_list():
|
51 |
print('Loading example img list ...')
|
52 |
return sorted(glob('./assets/example_images/*.png'))
|
|
|
60 |
return txt_list
|
61 |
|
62 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
def export_mesh(mesh, save_folder, textured=False):
|
64 |
if textured:
|
65 |
path = os.path.join(save_folder, f'textured_mesh.glb')
|
|
|
68 |
mesh.export(path, include_normals=textured)
|
69 |
return path
|
70 |
|
|
|
71 |
def build_model_viewer_html(save_folder, height=660, width=790, textured=False):
|
72 |
if textured:
|
73 |
related_path = f"./textured_mesh.glb"
|
74 |
template_name = './assets/modelviewer-textured-template.html'
|
75 |
+
output_html_path = os.path.join(save_folder, f'{uuid.uuid4()}_textured_mesh.html')
|
76 |
else:
|
77 |
related_path = f"./white_mesh.glb"
|
78 |
template_name = './assets/modelviewer-template.html'
|
79 |
+
output_html_path = os.path.join(save_folder, f'{uuid.uuid4()}_white_mesh.html')
|
80 |
|
81 |
with open(os.path.join(CURRENT_DIR, template_name), 'r') as f:
|
82 |
template_html = f.read()
|
|
|
107 |
</div>
|
108 |
"""
|
109 |
|
110 |
+
|
111 |
@spaces.GPU(duration=100)
|
112 |
def _gen_shape(
|
113 |
+
caption: str,
|
114 |
+
image: Image.Image,
|
115 |
+
steps: int,
|
116 |
+
guidance_scale: float,
|
117 |
+
seed: int,
|
118 |
+
octree_resolution: int,
|
119 |
+
check_box_rembg: bool,
|
120 |
+
req: gr.Request,
|
121 |
):
|
122 |
if caption: print('prompt is', caption)
|
123 |
+
save_folder = os.path.join(SAVE_DIR, str(req.session_hash))
|
124 |
stats = {}
|
125 |
time_meta = {}
|
126 |
start_time_0 = time.time()
|
|
|
135 |
|
136 |
image.save(os.path.join(save_folder, 'input.png'))
|
137 |
|
138 |
+
print(f"[{datetime.now()}][HunYuan3D-2]]", str(req.session_hash), image.mode)
|
139 |
if check_box_rembg or image.mode == "RGB":
|
140 |
start_time = time.time()
|
141 |
image = rmbg_worker(image.convert('RGB'))
|
|
|
166 |
time_meta['image_to_textured_3d'] = {'total': time.time() - start_time}
|
167 |
time_meta['total'] = time.time() - start_time_0
|
168 |
stats['time'] = time_meta
|
169 |
+
|
170 |
+
torch.cuda.empty_cache()
|
171 |
return mesh, save_folder, image
|
172 |
|
173 |
@spaces.GPU(duration=150)
|
174 |
def generation_all(
|
175 |
+
caption: str,
|
176 |
+
image: Image.Image,
|
177 |
+
steps: int,
|
178 |
+
guidance_scale: float,
|
179 |
+
seed: int,
|
180 |
+
octree_resolution: int,
|
181 |
+
check_box_rembg: bool,
|
182 |
+
req: gr.Request,
|
183 |
):
|
184 |
mesh, save_folder, image = _gen_shape(
|
185 |
caption,
|
|
|
188 |
guidance_scale=guidance_scale,
|
189 |
seed=seed,
|
190 |
octree_resolution=octree_resolution,
|
191 |
+
check_box_rembg=check_box_rembg,
|
192 |
+
req=req
|
193 |
)
|
194 |
path = export_mesh(mesh, save_folder, textured=False)
|
195 |
model_viewer_html = build_model_viewer_html(save_folder, height=596, width=700)
|
|
|
198 |
path_textured = export_mesh(textured_mesh, save_folder, textured=True)
|
199 |
model_viewer_html_textured = build_model_viewer_html(save_folder, height=596, width=700, textured=True)
|
200 |
|
201 |
+
torch.cuda.empty_cache()
|
202 |
return (
|
203 |
+
path,
|
204 |
+
path_textured,
|
205 |
model_viewer_html,
|
206 |
model_viewer_html_textured,
|
207 |
)
|
208 |
|
209 |
@spaces.GPU(duration=100)
|
210 |
def shape_generation(
|
211 |
+
caption: str,
|
212 |
+
image: Image.Image,
|
213 |
+
steps: int,
|
214 |
+
guidance_scale: float,
|
215 |
+
seed: int,
|
216 |
+
octree_resolution: int,
|
217 |
+
check_box_rembg: bool,
|
218 |
+
req: gr.Request,
|
219 |
):
|
220 |
mesh, save_folder, image = _gen_shape(
|
221 |
caption,
|
|
|
224 |
guidance_scale=guidance_scale,
|
225 |
seed=seed,
|
226 |
octree_resolution=octree_resolution,
|
227 |
+
check_box_rembg=check_box_rembg,
|
228 |
+
req=req,
|
229 |
)
|
230 |
|
231 |
path = export_mesh(mesh, save_folder, textured=False)
|
232 |
model_viewer_html = build_model_viewer_html(save_folder, height=596, width=700)
|
233 |
|
234 |
return (
|
235 |
+
path,
|
236 |
model_viewer_html,
|
237 |
)
|
238 |
|
|
|
254 |
</div>
|
255 |
"""
|
256 |
|
257 |
+
with gr.Blocks(theme=gr.themes.Base(), title='Hunyuan-3D-2.0', delete_cache=(1000,1000)) as demo:
|
258 |
gr.HTML(title_html)
|
259 |
|
260 |
with gr.Row():
|
|
|
280 |
btn = gr.Button(value='Generate Shape Only', variant='primary')
|
281 |
btn_all = gr.Button(value='Generate Shape and Texture', variant='primary', visible=HAS_TEXTUREGEN)
|
282 |
|
283 |
+
# with gr.Group():
|
284 |
+
# file_out = gr.File(label="File", visible=False)
|
285 |
+
# file_out2 = gr.File(label="File", visible=False)
|
286 |
+
|
287 |
with gr.Group():
|
288 |
+
file_out = gr.DownloadButton(label="Download White Mesh", interactive=False)
|
289 |
+
file_out2 = gr.DownloadButton(label="Download Textured Mesh", interactive=False)
|
290 |
|
291 |
with gr.Column(scale=5):
|
292 |
with gr.Tabs():
|
|
|
340 |
],
|
341 |
outputs=[file_out, html_output1]
|
342 |
).then(
|
343 |
+
lambda: gr.Button(interactive=True),
|
344 |
outputs=[file_out],
|
345 |
)
|
346 |
|
|
|
357 |
],
|
358 |
outputs=[file_out, file_out2, html_output1, html_output2]
|
359 |
).then(
|
360 |
+
lambda: (gr.Button(interactive=True),gr.Button(interactive=True)),
|
361 |
outputs=[file_out, file_out2],
|
362 |
)
|
363 |
|
364 |
+
demo.load(start_session)
|
365 |
+
demo.unload(end_session)
|
366 |
+
|
367 |
return demo
|
368 |
|
369 |
|
|
|
376 |
parser.add_argument('--enable_t23d', default=True)
|
377 |
args = parser.parse_args()
|
378 |
|
|
|
|
|
|
|
379 |
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
|
380 |
+
SAVE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), args.cache_path)
|
381 |
+
os.makedirs(SAVE_DIR, exist_ok=True)
|
382 |
|
383 |
HTML_OUTPUT_PLACEHOLDER = """
|
384 |
<div style='height: 596px; width: 100%; border-radius: 8px; border-color: #e5e7eb; order-style: solid; border-width: 1px;'></div>
|
minimal_demo.py
CHANGED
@@ -23,6 +23,7 @@
|
|
23 |
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
24 |
|
25 |
import torch
|
|
|
26 |
|
27 |
from hy3dgen.rembg import BackgroundRemover
|
28 |
from hy3dgen.shapegen import Hunyuan3DDiTFlowMatchingPipeline, FaceReducer, FloaterRemover, DegenerateFaceRemover
|
@@ -30,10 +31,18 @@ from hy3dgen.text2image import HunyuanDiTPipeline
|
|
30 |
|
31 |
|
32 |
def image_to_3d(image_path='assets/demo.png'):
|
|
|
33 |
model_path = 'Hunyuan3D-2'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
pipeline = Hunyuan3DDiTFlowMatchingPipeline.from_pretrained(model_path)
|
35 |
|
36 |
-
mesh = pipeline(image=
|
37 |
generator=torch.manual_seed(2025))[0]
|
38 |
mesh = FloaterRemover()(mesh)
|
39 |
mesh = DegenerateFaceRemover()(mesh)
|
@@ -43,7 +52,7 @@ def image_to_3d(image_path='assets/demo.png'):
|
|
43 |
try:
|
44 |
from hy3dgen.texgen import Hunyuan3DPaintPipeline
|
45 |
pipeline = Hunyuan3DPaintPipeline.from_pretrained(model_path)
|
46 |
-
mesh = pipeline(mesh, image=
|
47 |
mesh.export('texture.glb')
|
48 |
except Exception as e:
|
49 |
print(e)
|
|
|
23 |
# by Tencent in accordance with TENCENT HUNYUAN COMMUNITY LICENSE AGREEMENT.
|
24 |
|
25 |
import torch
|
26 |
+
from PIL imprt Image
|
27 |
|
28 |
from hy3dgen.rembg import BackgroundRemover
|
29 |
from hy3dgen.shapegen import Hunyuan3DDiTFlowMatchingPipeline, FaceReducer, FloaterRemover, DegenerateFaceRemover
|
|
|
31 |
|
32 |
|
33 |
def image_to_3d(image_path='assets/demo.png'):
|
34 |
+
rembg = BackgroundRemover()
|
35 |
model_path = 'Hunyuan3D-2'
|
36 |
+
|
37 |
+
image = Image.open(image_path)
|
38 |
+
image = image.resize((1024, 1024))
|
39 |
+
|
40 |
+
if image.mode == 'RGB':
|
41 |
+
image = rembg(image)
|
42 |
+
|
43 |
pipeline = Hunyuan3DDiTFlowMatchingPipeline.from_pretrained(model_path)
|
44 |
|
45 |
+
mesh = pipeline(image=image, num_inference_steps=30, mc_algo='mc',
|
46 |
generator=torch.manual_seed(2025))[0]
|
47 |
mesh = FloaterRemover()(mesh)
|
48 |
mesh = DegenerateFaceRemover()(mesh)
|
|
|
52 |
try:
|
53 |
from hy3dgen.texgen import Hunyuan3DPaintPipeline
|
54 |
pipeline = Hunyuan3DPaintPipeline.from_pretrained(model_path)
|
55 |
+
mesh = pipeline(mesh, image=image)
|
56 |
mesh.export('texture.glb')
|
57 |
except Exception as e:
|
58 |
print(e)
|