diff --git a/Gen_3D_Modules/Hunyuan3D_V2/assets/1.glb b/Gen_3D_Modules/Hunyuan3D_V2/assets/1.glb deleted file mode 100644 index 0d33b00..0000000 Binary files a/Gen_3D_Modules/Hunyuan3D_V2/assets/1.glb and /dev/null differ diff --git a/Gen_3D_Modules/Hunyuan3D_V2/assets/demo.png b/Gen_3D_Modules/Hunyuan3D_V2/assets/demo.png deleted file mode 100755 index 00fda1d..0000000 Binary files a/Gen_3D_Modules/Hunyuan3D_V2/assets/demo.png and /dev/null differ diff --git a/Gen_3D_Modules/Hunyuan3D_V2/assets/env_maps/gradient.jpg b/Gen_3D_Modules/Hunyuan3D_V2/assets/env_maps/gradient.jpg deleted file mode 100644 index 55546c1..0000000 Binary files a/Gen_3D_Modules/Hunyuan3D_V2/assets/env_maps/gradient.jpg and /dev/null differ diff --git a/Gen_3D_Modules/Hunyuan3D_V2/assets/env_maps/white.jpg b/Gen_3D_Modules/Hunyuan3D_V2/assets/env_maps/white.jpg deleted file mode 100644 index f7af123..0000000 Binary files a/Gen_3D_Modules/Hunyuan3D_V2/assets/env_maps/white.jpg and /dev/null differ diff --git a/Gen_3D_Modules/Hunyuan3D_V2/assets/example_prompts.txt b/Gen_3D_Modules/Hunyuan3D_V2/assets/example_prompts.txt deleted file mode 100644 index 5155022..0000000 --- a/Gen_3D_Modules/Hunyuan3D_V2/assets/example_prompts.txt +++ /dev/null @@ -1,5 +0,0 @@ -一片绿色的树叶在白色背景上居中展现,清晰的纹理 -一只棕白相间的仓鼠,站在白色背景前。照片采用居中构图方式,卡通风格 -一盆绿色植物生长在红色花盆中,居中,写实 -a pot of green plants grows in a red flower pot. -a lovely rabbit eating carrots diff --git a/Gen_3D_Modules/Hunyuan3D_V2/assets/modelviewer-template.html b/Gen_3D_Modules/Hunyuan3D_V2/assets/modelviewer-template.html deleted file mode 100644 index 3406cb1..0000000 --- a/Gen_3D_Modules/Hunyuan3D_V2/assets/modelviewer-template.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - -
-
- - -
-
- - - \ No newline at end of file diff --git a/Gen_3D_Modules/Hunyuan3D_V2/assets/modelviewer-textured-template.html b/Gen_3D_Modules/Hunyuan3D_V2/assets/modelviewer-textured-template.html deleted file mode 100644 index 5f84cae..0000000 --- a/Gen_3D_Modules/Hunyuan3D_V2/assets/modelviewer-textured-template.html +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - - - - - -
-
-
- - -
- -
-
- Appearance -
-
Geometry
-
-
-
- - - - - \ No newline at end of file diff --git a/Gen_3D_Modules/Hunyuan3D_V2/assets/qrcode/discord.png b/Gen_3D_Modules/Hunyuan3D_V2/assets/qrcode/discord.png deleted file mode 100644 index a9c326d..0000000 Binary files a/Gen_3D_Modules/Hunyuan3D_V2/assets/qrcode/discord.png and /dev/null differ diff --git a/Gen_3D_Modules/Hunyuan3D_V2/assets/qrcode/wechat.png b/Gen_3D_Modules/Hunyuan3D_V2/assets/qrcode/wechat.png deleted file mode 100755 index 4f25092..0000000 Binary files a/Gen_3D_Modules/Hunyuan3D_V2/assets/qrcode/wechat.png and /dev/null differ diff --git a/Gen_3D_Modules/Hunyuan3D_V2/assets/qrcode/x.png b/Gen_3D_Modules/Hunyuan3D_V2/assets/qrcode/x.png deleted file mode 100644 index e9f9044..0000000 Binary files a/Gen_3D_Modules/Hunyuan3D_V2/assets/qrcode/x.png and /dev/null differ diff --git a/Gen_3D_Modules/Hunyuan3D_V2/assets/qrcode/xiaohongshu.png b/Gen_3D_Modules/Hunyuan3D_V2/assets/qrcode/xiaohongshu.png deleted file mode 100644 index 7ace644..0000000 Binary files a/Gen_3D_Modules/Hunyuan3D_V2/assets/qrcode/xiaohongshu.png and /dev/null differ diff --git a/Gen_3D_Modules/Hunyuan3D_V2/hy3dgen/shapegen/preprocessors.py b/Gen_3D_Modules/Hunyuan3D_V2/hy3dgen/shapegen/preprocessors.py old mode 100644 new mode 100755 index 2bdaff2..8a9cb9e --- a/Gen_3D_Modules/Hunyuan3D_V2/hy3dgen/shapegen/preprocessors.py +++ b/Gen_3D_Modules/Hunyuan3D_V2/hy3dgen/shapegen/preprocessors.py @@ -1,12 +1,3 @@ -# Open Source Model Licensed under the Apache License Version 2.0 -# and Other Licenses of the Third-Party Components therein: -# The below Model in this distribution may have been modified by THL A29 Limited -# ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2024 THL A29 Limited. -# Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved. -# The below software and/or models in this distribution may have been -# modified by THL A29 Limited ("Tencent Modifications"). -# All Tencent Modifications are Copyright (C) THL A29 Limited. - # Hunyuan 3D is licensed under the TENCENT HUNYUAN NON-COMMERCIAL LICENSE AGREEMENT # except for the third-party components listed below. # Hunyuan 3D does not impose any additional limitations beyond what is outlined @@ -87,7 +78,7 @@ class ImageProcessorV2: interpolation=cv2.INTER_AREA) bg = np.ones((result.shape[0], result.shape[1], 3), dtype=np.uint8) * 255 - # bg = np.zeros((result.shape[0], result.shape[1], 3), dtype=np.uint8) * 255 + mask = result[..., 3:].astype(np.float32) / 255 result = result[..., :3] * mask + bg * (1 - mask) @@ -96,15 +87,13 @@ class ImageProcessorV2: mask = mask.clip(0, 255).astype(np.uint8) return result, mask - def __call__(self, image, border_ratio=0.15, to_tensor=True, return_mask=False, **kwargs): - if self.border_ratio is not None: - border_ratio = self.border_ratio - print(f"Using border_ratio from init: {border_ratio}") + def load_image(self, image, border_ratio=0.15, to_tensor=True): if isinstance(image, str): image = cv2.imread(image, cv2.IMREAD_UNCHANGED) image, mask = self.recenter(image, border_ratio=border_ratio) image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) elif isinstance(image, Image.Image): + image = image.convert("RGBA") image = np.asarray(image) image, mask = self.recenter(image, border_ratio=border_ratio) @@ -115,13 +104,64 @@ class ImageProcessorV2: if to_tensor: image = array_to_tensor(image) mask = array_to_tensor(mask) - if return_mask: - return image, mask - return image + return image, mask + + def __call__(self, image, border_ratio=0.15, to_tensor=True, **kwargs): + if self.border_ratio is not None: + border_ratio = self.border_ratio + image, mask = self.load_image(image, border_ratio=border_ratio, to_tensor=to_tensor) + outputs = { + 'image': image, + 'mask': mask + } + return outputs + + +class MVImageProcessorV2(ImageProcessorV2): + """ + view order: front, front clockwise 90, back, front clockwise 270 + """ + return_view_idx = True + + def __init__(self, size=512, border_ratio=None): + super().__init__(size, border_ratio) + self.view2idx = { + 'front': 0, + 'left': 1, + 'back': 2, + 'right': 3 + } + + def __call__(self, image_dict, border_ratio=0.15, to_tensor=True, **kwargs): + if self.border_ratio is not None: + border_ratio = self.border_ratio + + images = [] + masks = [] + view_idxs = [] + for idx, (view_tag, image) in enumerate(image_dict.items()): + view_idxs.append(self.view2idx[view_tag]) + image, mask = self.load_image(image, border_ratio=border_ratio, to_tensor=to_tensor) + images.append(image) + masks.append(mask) + + zipped_lists = zip(view_idxs, images, masks) + sorted_zipped_lists = sorted(zipped_lists) + view_idxs, images, masks = zip(*sorted_zipped_lists) + + image = torch.cat(images, 0).unsqueeze(0) + mask = torch.cat(masks, 0).unsqueeze(0) + outputs = { + 'image': image, + 'mask': mask, + 'view_idxs': view_idxs + } + return outputs IMAGE_PROCESSORS = { "v2": ImageProcessorV2, + 'mv_v2': MVImageProcessorV2, } DEFAULT_IMAGEPROCESSOR = 'v2' diff --git a/Gen_3D_Modules/Hunyuan3D_V2/hy3dgen/texgen/pipelines.py b/Gen_3D_Modules/Hunyuan3D_V2/hy3dgen/texgen/pipelines.py index 2110588..33cbebc 100644 --- a/Gen_3D_Modules/Hunyuan3D_V2/hy3dgen/texgen/pipelines.py +++ b/Gen_3D_Modules/Hunyuan3D_V2/hy3dgen/texgen/pipelines.py @@ -53,38 +53,19 @@ class Hunyuan3DTexGenConfig: class Hunyuan3DPaintPipeline: @classmethod def from_pretrained(cls, model_path, subfolder='hunyuan3d-paint-v2-0-turbo'): - original_model_path = model_path - if not os.path.exists(model_path): - # try local path - base_dir = os.environ.get('HY3DGEN_MODELS', '~/.cache/hy3dgen') - model_path = os.path.expanduser(os.path.join(base_dir, model_path)) + delight_model_path = os.path.join(model_path, 'hunyuan3d-delight-v2-0') + multiview_model_path = os.path.join(model_path, subfolder) - delight_model_path = os.path.join(model_path, 'hunyuan3d-delight-v2-0') - multiview_model_path = os.path.join(model_path, subfolder) - - if not os.path.exists(delight_model_path) or not os.path.exists(multiview_model_path): - try: - import huggingface_hub - # download from huggingface - model_path = huggingface_hub.snapshot_download( - repo_id=original_model_path, allow_patterns=["hunyuan3d-delight-v2-0/*"] - ) - model_path = huggingface_hub.snapshot_download( - repo_id=original_model_path, allow_patterns=[f'{subfolder}/*'] - ) - delight_model_path = os.path.join(model_path, 'hunyuan3d-delight-v2-0') - multiview_model_path = os.path.join(model_path, subfolder) - return cls(Hunyuan3DTexGenConfig(delight_model_path, multiview_model_path, subfolder)) - except ImportError: - logger.warning( - "You need to install HuggingFace Hub to load models from the hub." - ) - raise RuntimeError(f"Model path {model_path} not found") - else: - return cls(Hunyuan3DTexGenConfig(delight_model_path, multiview_model_path, subfolder)) - - raise FileNotFoundError(f"Model path {original_model_path} not found and we could not find it at huggingface") + if os.path.exists(delight_model_path) and os.path.exists(multiview_model_path): + return cls(Hunyuan3DTexGenConfig( + delight_model_path, + multiview_model_path, + subfolder + )) + raise FileNotFoundError( + f"Required models not found in local paths: {delight_model_path} or {multiview_model_path}" + ) def __init__(self, config): self.config = config self.models = {} diff --git a/nodes.py b/nodes.py index 7036f71..794296d 100644 --- a/nodes.py +++ b/nodes.py @@ -4330,10 +4330,10 @@ class Load_Hunyuan3D_V2_ShapeGen_Pipeline: repo, subfolder, def_steps = self._MODES[generation_mode] use_safe = (weights_format == "safetensors") pipe = self._build_pipe(repo, subfolder, use_safe, flash_vdm) - pipe.default_steps = def_steps + pipe.num_inference_steps = def_steps return (pipe,) -class Load_Hunyuan3D_V2_TexGen_Pipeline: +class Load_Hunyuan3D_V2_TexGen_Pipeline: CATEGORY = "Comfy3D/Algorithm" RETURN_TYPES = ("DIFFUSERS_PIPE",) RETURN_NAMES = ("texgen_pipe",) @@ -4348,32 +4348,35 @@ class Load_Hunyuan3D_V2_TexGen_Pipeline: def INPUT_TYPES(cls): return {"required": { "generation_mode": (list(cls.MODEL2REPO.keys()),), - "weights_format": (["safetensors","ckpt"],), }} - @staticmethod - def _ensure_weights(repo_id: str, subfolder: str, use_safetensors: bool): - base_dir = os.path.join(CKPT_DIFFUSERS_PATH, repo_id) - os.makedirs(base_dir, exist_ok=True) - target_dir = os.path.join(base_dir, subfolder) - if not os.path.exists(target_dir): + def _download_required_weights(self, repo_id, subfolder): + ckpt_download_dir = os.path.join(CKPT_DIFFUSERS_PATH, repo_id) + os.makedirs(ckpt_download_dir, exist_ok=True) + + # Only download the "delight" and target submodel directories + for folder in ["hunyuan3d-delight-v2-0", subfolder]: snapshot_download( repo_id=repo_id, + local_dir=ckpt_download_dir, repo_type="model", - local_dir=base_dir, - resume_download=True, - ignore_patterns = HF_DOWNLOAD_IGNORE + force_download=False, + ignore_patterns=HF_DOWNLOAD_IGNORE ) - def load(self, generation_mode, weights_format): - repo_id,subfolder=self.MODEL2REPO[generation_mode] - Load_Hunyuan3D_V2_TexGen_Pipeline._ensure_weights(repo_id,subfolder, - weights_format=="safetensors") - pipe=Hunyuan3DPaintPipeline.from_pretrained( - model_path=repo_id, - subfolder=subfolder, + def load(self, generation_mode): + repo_id, subfolder = self.MODEL2REPO[generation_mode] + + self._download_required_weights(repo_id, subfolder) + + local_repo_dir = os.path.join(CKPT_DIFFUSERS_PATH, repo_id) + + pipe = Hunyuan3DPaintPipeline.from_pretrained( + model_path=local_repo_dir, + subfolder=subfolder ) - return (pipe.to("cuda",torch.float16),) + + return (pipe.to("cuda", torch.float16),) class Hunyuan3D_V2_Paint_Model_Turbo_MV: """ @@ -4443,7 +4446,8 @@ class Multi_Background_Remover: self, image_front, image_back=None, - image_left=None + image_left=None, + image_right=None ): rmbg = BackgroundRemover() @@ -4451,7 +4455,8 @@ class Multi_Background_Remover: k: v for k, v in { "front": image_front, "back": image_back, - "left": image_left + "left": image_left, + "right": image_right }.items() if v is not None } @@ -4504,7 +4509,7 @@ class Hunyuan3D_V2_ShapeGen_MV: if len(images) == 1: image = images[0] else: - directions = ["front", "back", "left"] + directions = ["front", "back", "left", "right"] image = {k: v for k, v in zip(directions, images)} steps = shapegen_pipe.default_steps if num_inference_steps == 0 else num_inference_steps