ComfyUI/comfy_extras/nodes_load_3d.py
Kohaku-Blueleaf 88d9168df0
Sync (#1)
* Allow disabling pe in flux code for some other models.

* Initial Hunyuan3Dv2 implementation.

Supports the multiview, mini, turbo models and VAEs.

* Fix orientation of hunyuan 3d model.

* A few fixes for the hunyuan3d models.

* Update frontend to 1.13 (#7331)

* Add backend primitive nodes (#7328)

* Add backend primitive nodes

* Add control after generate to int primitive

* Nodes to convert images to YUV and back.

Can be used to convert an image to black and white.

* Update frontend to 1.14 (#7343)

* Native LotusD Implementation (#7125)

* draft pass at a native comfy implementation of Lotus-D depth and normal est

* fix model_sampling kludges

* fix ruff

---------

Co-authored-by: comfyanonymous <121283862+comfyanonymous@users.noreply.github.com>

* Automatically set the right sampling type for lotus.

* support output normal and lineart once (#7290)

* [nit] Format error strings (#7345)

* ComfyUI version v0.3.27

* Fallback to pytorch attention if sage attention fails.

* Add model merging node for WAN 2.1

* Add Hunyuan3D to readme.

* Support more float8 types.

* Add CFGZeroStar node.

Works on all models that use a negative prompt but is meant for rectified
flow models.

* Support the WAN 2.1 fun control models.

Use the new WanFunControlToVideo node.

* Add WanFunInpaintToVideo node for the Wan fun inpaint models.

* Update frontend to 1.14.6 (#7416)

Cherry-pick the fix: https://github.com/Comfy-Org/ComfyUI_frontend/pull/3252

* Don't error if wan concat image has extra channels.

* ltxv: fix preprocessing exception when compression is 0. (#7431)

* Remove useless code.

* Fix latent composite node not working when source has alpha.

* Fix alpha channel mismatch on destination in ImageCompositeMasked

* Add option to store TE in bf16 (#7461)

* User missing (#7439)

* Ensuring a 401 error is returned when user data is not found in multi-user context.

* Returning a 401 error when provided comfy-user does not exists on server side.

* Fix comment.

This function does not support quads.

* MLU memory optimization (#7470)

Co-authored-by: huzhan <huzhan@cambricon.com>

* Fix alpha image issue in more nodes.

* Fix problem.

* Disable partial offloading of audio VAE.

* Add activations_shape info in UNet models (#7482)

* Add activations_shape info in UNet models

* activations_shape should be a list

* Support 512 siglip model.

* Show a proper error to the user when a vision model file is invalid.

* Support the wan fun reward loras.

---------

Co-authored-by: comfyanonymous <comfyanonymous@protonmail.com>
Co-authored-by: Chenlei Hu <hcl@comfy.org>
Co-authored-by: thot experiment <94414189+thot-experiment@users.noreply.github.com>
Co-authored-by: comfyanonymous <121283862+comfyanonymous@users.noreply.github.com>
Co-authored-by: Terry Jia <terryjia88@gmail.com>
Co-authored-by: Michael Kupchick <michael@lightricks.com>
Co-authored-by: BVH <82035780+bvhari@users.noreply.github.com>
Co-authored-by: Laurent Erignoux <lerignoux@gmail.com>
Co-authored-by: BiologicalExplosion <49753622+BiologicalExplosion@users.noreply.github.com>
Co-authored-by: huzhan <huzhan@cambricon.com>
Co-authored-by: Raphael Walker <slickytail.mc@gmail.com>
2025-04-08 18:38:44 +08:00

131 lines
4.3 KiB
Python

import nodes
import folder_paths
import os
def normalize_path(path):
return path.replace('\\', '/')
class Load3D():
@classmethod
def INPUT_TYPES(s):
input_dir = os.path.join(folder_paths.get_input_directory(), "3d")
os.makedirs(input_dir, exist_ok=True)
files = [normalize_path(os.path.join("3d", f)) for f in os.listdir(input_dir) if f.endswith(('.gltf', '.glb', '.obj', '.mtl', '.fbx', '.stl'))]
return {"required": {
"model_file": (sorted(files), {"file_upload": True}),
"image": ("LOAD_3D", {}),
"width": ("INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}),
"height": ("INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}),
}}
RETURN_TYPES = ("IMAGE", "MASK", "STRING", "IMAGE", "IMAGE")
RETURN_NAMES = ("image", "mask", "mesh_path", "normal", "lineart")
FUNCTION = "process"
EXPERIMENTAL = True
CATEGORY = "3d"
def process(self, model_file, image, **kwargs):
image_path = folder_paths.get_annotated_filepath(image['image'])
mask_path = folder_paths.get_annotated_filepath(image['mask'])
normal_path = folder_paths.get_annotated_filepath(image['normal'])
lineart_path = folder_paths.get_annotated_filepath(image['lineart'])
load_image_node = nodes.LoadImage()
output_image, ignore_mask = load_image_node.load_image(image=image_path)
ignore_image, output_mask = load_image_node.load_image(image=mask_path)
normal_image, ignore_mask2 = load_image_node.load_image(image=normal_path)
lineart_image, ignore_mask3 = load_image_node.load_image(image=lineart_path)
return output_image, output_mask, model_file, normal_image, lineart_image
class Load3DAnimation():
@classmethod
def INPUT_TYPES(s):
input_dir = os.path.join(folder_paths.get_input_directory(), "3d")
os.makedirs(input_dir, exist_ok=True)
files = [normalize_path(os.path.join("3d", f)) for f in os.listdir(input_dir) if f.endswith(('.gltf', '.glb', '.fbx'))]
return {"required": {
"model_file": (sorted(files), {"file_upload": True}),
"image": ("LOAD_3D_ANIMATION", {}),
"width": ("INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}),
"height": ("INT", {"default": 1024, "min": 1, "max": 4096, "step": 1}),
}}
RETURN_TYPES = ("IMAGE", "MASK", "STRING", "IMAGE")
RETURN_NAMES = ("image", "mask", "mesh_path", "normal")
FUNCTION = "process"
EXPERIMENTAL = True
CATEGORY = "3d"
def process(self, model_file, image, **kwargs):
image_path = folder_paths.get_annotated_filepath(image['image'])
mask_path = folder_paths.get_annotated_filepath(image['mask'])
normal_path = folder_paths.get_annotated_filepath(image['normal'])
load_image_node = nodes.LoadImage()
output_image, ignore_mask = load_image_node.load_image(image=image_path)
ignore_image, output_mask = load_image_node.load_image(image=mask_path)
normal_image, ignore_mask2 = load_image_node.load_image(image=normal_path)
return output_image, output_mask, model_file, normal_image
class Preview3D():
@classmethod
def INPUT_TYPES(s):
return {"required": {
"model_file": ("STRING", {"default": "", "multiline": False}),
}}
OUTPUT_NODE = True
RETURN_TYPES = ()
CATEGORY = "3d"
FUNCTION = "process"
EXPERIMENTAL = True
def process(self, model_file, **kwargs):
return {"ui": {"model_file": [model_file]}, "result": ()}
class Preview3DAnimation():
@classmethod
def INPUT_TYPES(s):
return {"required": {
"model_file": ("STRING", {"default": "", "multiline": False}),
}}
OUTPUT_NODE = True
RETURN_TYPES = ()
CATEGORY = "3d"
FUNCTION = "process"
EXPERIMENTAL = True
def process(self, model_file, **kwargs):
return {"ui": {"model_file": [model_file]}, "result": ()}
NODE_CLASS_MAPPINGS = {
"Load3D": Load3D,
"Load3DAnimation": Load3DAnimation,
"Preview3D": Preview3D,
"Preview3DAnimation": Preview3DAnimation
}
NODE_DISPLAY_NAME_MAPPINGS = {
"Load3D": "Load 3D",
"Load3DAnimation": "Load 3D - Animation",
"Preview3D": "Preview 3D",
"Preview3DAnimation": "Preview 3D - Animation"
}