Small update for Hunyuan3D-2
This commit is contained in:
@@ -9,14 +9,11 @@ language:
|
||||
tags:
|
||||
- image-to-3d
|
||||
- text-to-3d
|
||||
pipeline_tag: text-to-3d
|
||||
pipeline_tag: image-to-3d
|
||||
---
|
||||
|
||||
|
||||
<p align="center">
|
||||
<img src="./assets/images/teaser.jpg">
|
||||
|
||||
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
@@ -40,6 +37,9 @@ pipeline_tag: text-to-3d
|
||||
“ Living out everyone’s imagination on creating and manipulating 3D assets.”
|
||||
</p>
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
<p align="center">
|
||||
<img src="assets/images/system.jpg">
|
||||
</p>
|
||||
@@ -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
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=Tencent/Hunyuan3D-2&type=Date" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=Tencent/Hunyuan3D-2&type=Date" />
|
||||
</picture>
|
||||
</a>
|
||||
</a>
|
||||
@@ -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',
|
||||
)
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user