@@ -40,6 +37,9 @@ pipeline_tag: text-to-3d
“ Living out everyone’s imagination on creating and manipulating 3D assets.”
+This repository contains the models of the paper [Hunyuan3D 2.0: Scaling Diffusion Models for High Resolution Textured 3D Assets Generation](https://huggingface.co/papers/2501.12202).
+For code and more details on how to use it, refer to the [Github repository](https://github.com/Tencent/Hunyuan3D-2).
+
## 🔥 News
- Jan 21, 2025: 💬 Release [Hunyuan3D 2.0](https://huggingface.co/spaces/tencent/Hunyuan3D-2). Please give it a try!
@@ -60,8 +60,6 @@ We systematically evaluate our models, showing that Hunyuan3D 2.0 outperforms pr
including the open-source models and closed-source models in geometry details, condition alignment, texture quality, and
e.t.c.
-
-
@@ -104,6 +102,7 @@ Generation results of Hunyuan3D 2.0:
|----------------------|------------|--------------------------------------------------------|
| Hunyuan3D-DiT-v2-0 | 2025-01-21 | [Download](https://huggingface.co/tencent/Hunyuan3D-2) |
| Hunyuan3D-Paint-v2-0 | 2025-01-21 | [Download](https://huggingface.co/tencent/Hunyuan3D-2) |
+| Hunyuan3D-Delight-v2-0 | 2025-01-21 | [Download](https://huggingface.co/tencent/Hunyuan3D-2/tree/main/hunyuan3d-delight-v2-0) |
## 🤗 Get Started with Hunyuan3D 2.0
@@ -118,8 +117,9 @@ pip install -r requirements.txt
# for texture
cd hy3dgen/texgen/custom_rasterizer
python3 setup.py install
+cd ../../..
cd hy3dgen/texgen/differentiable_renderer
-bash compile_mesh_painter.sh
+bash compile_mesh_painter.sh OR python3 setup.py install (on Windows)
```
### API Usage
@@ -184,9 +184,29 @@ If you found this repository helpful, please cite our report:
title={Hunyuan3D 2.0: Scaling Diffusion Models for High Resolution Textured 3D Assets Generation},
author={Tencent Hunyuan3D Team},
year={2025},
+ eprint={2501.12202},
+ archivePrefix={arXiv},
+ primaryClass={cs.CV}
+}
+
+@misc{yang2024tencent,
+ title={Tencent Hunyuan3D-1.0: A Unified Framework for Text-to-3D and Image-to-3D Generation},
+ author={Tencent Hunyuan3D Team},
+ year={2024},
+ eprint={2411.02293},
+ archivePrefix={arXiv},
+ primaryClass={cs.CV}
}
```
+## Community Resources
+
+Thanks for the contributions of community members, here we have these great extensions of Hunyuan3D 2.0:
+
+- [ComfyUI-Hunyuan3DWrapper](https://github.com/kijai/ComfyUI-Hunyuan3DWrapper)
+- [Hunyuan3D-2-for-windows](https://github.com/sdbds/Hunyuan3D-2-for-windows)
+- [📦 A bundle for running on Windows | 整合包](https://github.com/YanWenKun/Comfy3D-WinPortable/releases/tag/r8-hunyuan3d2)
+
## Acknowledgements
We would like to thank the contributors to
@@ -201,4 +221,4 @@ and [HuggingFace](https://huggingface.co) repositories, for their open research
-
+
\ No newline at end of file
diff --git a/Gen_3D_Modules/Hunyuan3D_V2/hy3dgen/texgen/differentiable_renderer/setup.py b/Gen_3D_Modules/Hunyuan3D_V2/hy3dgen/texgen/differentiable_renderer/setup.py
new file mode 100644
index 0000000..902d842
--- /dev/null
+++ b/Gen_3D_Modules/Hunyuan3D_V2/hy3dgen/texgen/differentiable_renderer/setup.py
@@ -0,0 +1,47 @@
+from setuptools import setup, Extension
+import pybind11
+import sys
+import platform
+
+# Common compile arguments
+common_compile_args = []
+
+if sys.platform == 'win32':
+ # Windows-specific compile arguments
+ extra_compile_args = [
+ '/O2', # Optimization level
+ '/std:c++14', # C++ standard (using C++14 for better compatibility)
+ '/EHsc', # Exception handling model
+ '/MP', # Multi-process compilation
+ '/DWIN32_LEAN_AND_MEAN', # Exclude rarely-used Windows headers
+ ]
+ extra_link_args = []
+else:
+ # Linux/Unix compile arguments
+ extra_compile_args = [
+ '-O3', # Optimization level
+ '-std=c++14', # C++ standard
+ '-fPIC', # Position independent code
+ ]
+ extra_link_args = ['-fPIC']
+
+ext_modules = [
+ Extension(
+ "mesh_processor",
+ ["mesh_processor.cpp"],
+ include_dirs=[
+ pybind11.get_include(),
+ pybind11.get_include(user=True)
+ ],
+ language='c++',
+ extra_compile_args=common_compile_args + extra_compile_args,
+ extra_link_args=extra_link_args,
+ ),
+]
+
+setup(
+ name="mesh_processor",
+ ext_modules=ext_modules,
+ install_requires=['pybind11>=2.6.0'],
+ python_requires='>=3.6',
+)
\ No newline at end of file
diff --git a/Gen_3D_Modules/Hunyuan3D_V2/hy3dgen/texgen/pipelines.py b/Gen_3D_Modules/Hunyuan3D_V2/hy3dgen/texgen/pipelines.py
index 7c987cd..00bd8da 100644
--- a/Gen_3D_Modules/Hunyuan3D_V2/hy3dgen/texgen/pipelines.py
+++ b/Gen_3D_Modules/Hunyuan3D_V2/hy3dgen/texgen/pipelines.py
@@ -140,6 +140,40 @@ class Hunyuan3DPaintPipeline:
texture = torch.tensor(texture_np / 255).float().to(texture.device)
return texture
+
+ def recenter_image(self, image, border_ratio=0.2):
+ if image.mode == 'RGB':
+ return image
+ elif image.mode == 'L':
+ image = image.convert('RGB')
+ return image
+
+ alpha_channel = np.array(image)[:, :, 3]
+ non_zero_indices = np.argwhere(alpha_channel > 0)
+ if non_zero_indices.size == 0:
+ raise ValueError("Image is fully transparent")
+
+ min_row, min_col = non_zero_indices.min(axis=0)
+ max_row, max_col = non_zero_indices.max(axis=0)
+
+ cropped_image = image.crop((min_col, min_row, max_col + 1, max_row + 1))
+
+ width, height = cropped_image.size
+ border_width = int(width * border_ratio)
+ border_height = int(height * border_ratio)
+
+ new_width = width + 2 * border_width
+ new_height = height + 2 * border_height
+
+ square_size = max(new_width, new_height)
+
+ new_image = Image.new('RGBA', (square_size, square_size), (255, 255, 255, 0))
+
+ paste_x = (square_size - new_width) // 2 + border_width
+ paste_y = (square_size - new_height) // 2 + border_height
+
+ new_image.paste(cropped_image, (paste_x, paste_y))
+ return new_image
@torch.no_grad()
def __call__(self, mesh, image):
@@ -153,6 +187,7 @@ class Hunyuan3DPaintPipeline:
else:
image_prompt = image
+ image_prompt = self.recenter_image(image_prompt)
image_prompt = self.models['delight_model'](image_prompt)
step_num_i += 1
diff --git a/mesh_processer/mesh_utils.py b/mesh_processer/mesh_utils.py
index f631f53..a70b61b 100644
--- a/mesh_processer/mesh_utils.py
+++ b/mesh_processer/mesh_utils.py
@@ -211,9 +211,22 @@ def poisson_mesh_reconstruction(points, normals=None):
def decimate_mesh(
- verts, faces, target, backend="pymeshlab", remesh=False, optimalplacement=True
+ verts, faces, target=5e4, backend="pymeshlab", remesh=False, optimalplacement=True, verbose=True
):
- # optimalplacement: default is True, but for flat mesh must turn False to prevent spike artifect.
+ """ perform mesh decimation.
+
+ Args:
+ verts (np.ndarray): mesh vertices, float [N, 3]
+ faces (np.ndarray): mesh faces, int [M, 3]
+ target (int): targeted number of faces
+ backend (str, optional): algorithm backend, can be "pymeshlab" or "pyfqmr". Defaults to "pymeshlab".
+ remesh (bool, optional): whether to remesh after decimation. Defaults to False.
+ optimalplacement (bool, optional): For flat mesh, use False to prevent spikes. Defaults to True.
+ verbose (bool, optional): whether to print the decimation process. Defaults to True.
+
+ Returns:
+ Tuple[np.ndarray]: vertices and faces after decimation.
+ """
_ori_vert_shape = verts.shape
_ori_face_shape = faces.shape
@@ -231,7 +244,7 @@ def decimate_mesh(
ms.add_mesh(m, "mesh") # will copy!
# filters
- # ms.meshing_decimation_clustering(threshold=pml.Percentage(1))
+ # ms.meshing_decimation_clustering(threshold=pml.PercentageValue(1))
ms.meshing_decimation_quadric_edge_collapse(
targetfacenum=int(target), optimalplacement=optimalplacement
)
@@ -239,17 +252,17 @@ def decimate_mesh(
if remesh:
# ms.apply_coord_taubin_smoothing()
ms.meshing_isotropic_explicit_remeshing(
- iterations=3, targetlen=pml.Percentage(1)
+ iterations=3, targetlen=pml.PercentageValue(1)
)
# extract mesh
m = ms.current_mesh()
+ m.compact()
verts = m.vertex_matrix()
faces = m.face_matrix()
- print(
- f"[INFO] mesh decimation: {_ori_vert_shape} --> {verts.shape}, {_ori_face_shape} --> {faces.shape}"
- )
+ if verbose:
+ print(f"[INFO] mesh decimation: {_ori_vert_shape} --> {verts.shape}, {_ori_face_shape} --> {faces.shape}")
return verts, faces
diff --git a/nodes.py b/nodes.py
index accc238..b527f33 100644
--- a/nodes.py
+++ b/nodes.py
@@ -46,6 +46,7 @@ from .mesh_processer.mesh_utils import (
marching_cubes_density_to_mesh,
color_func_to_albedo,
interpolate_texture_map_attr,
+ decimate_mesh,
)
from FlexiCubes.flexicubes_trainer import FlexiCubesTrainer
@@ -608,6 +609,35 @@ class Fast_Clean_Mesh:
mesh = Mesh(v=vertices, f=faces, device=DEVICE)
return (mesh,)
+
+class Decimate_Mesh:
+ @classmethod
+ def INPUT_TYPES(cls):
+ return {
+ "required": {
+ "mesh": ("MESH",),
+ "target": ("INT", {"default": 5e4, "min": 0, "max": 0xffffffffffffffff}),
+ "remesh": ("BOOLEAN", {"default": True},),
+ "optimalplacement": ("BOOLEAN", {"default": True},),
+ },
+ }
+
+ RETURN_TYPES = (
+ "MESH",
+ )
+ RETURN_NAMES = (
+ "mesh",
+ )
+ FUNCTION = "process_mesh"
+ CATEGORY = "Comfy3D/Preprocessor"
+
+ def process_mesh(self, mesh, target, remesh, optimalplacement):
+
+ vertices, faces = decimate_mesh(mesh.v, mesh.f, target, remesh, optimalplacement)
+ mesh.v = vertices
+ mesh.f = faces
+
+ return (mesh,)
class Switch_3DGS_Axis:
@classmethod
diff --git a/pyproject.toml b/pyproject.toml
index ddcf166..195d74c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,7 +1,7 @@
[project]
name = "comfyui-3d-pack"
description = "Make ComfyUI generates 3D assets as good & convenient as it generates image/video!"
-version = "0.1.3"
+version = "0.1.4"
license = { file = "LICENSE" }
dynamic = ["dependencies"]
[tool.setuptools.dynamic]