Files
MrForExample-ComfyUI-3D-Pack/loadmesh.py
T
2025-09-05 11:32:10 +02:00

269 lines
11 KiB
Python

class Preview_3DMesh:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"mesh_file_path": ("STRING", {"default": '', "multiline": False}),
},
}
OUTPUT_NODE = True
RETURN_TYPES = ()
FUNCTION = "preview_mesh"
CATEGORY = "Comfy3D/Visualize"
def preview_mesh(self, mesh_file_path):
mesh_folder_path, filename = os.path.split(mesh_file_path)
if not os.path.isabs(mesh_file_path):
mesh_file_path = os.path.join(comfy_paths.output_directory, mesh_folder_path, filename)
if not filename.lower().endswith(SUPPORTED_3D_EXTENSIONS):
cstr(f"[{self.__class__.__name__}] File name {filename} does not end with supported 3D file extensions: {SUPPORTED_3D_EXTENSIONS}").error.print()
mesh_file_path = ""
print(f"[Preview_3DMesh] Final mesh path: {mesh_file_path}")
print(f"[Preview_3DMesh] File exists: {os.path.exists(mesh_file_path) if mesh_file_path else False}")
previews = [
{
"filepath": mesh_file_path,
}
]
return {"ui": {"previews": previews}, "result": ()}
class Load_3D_Mesh:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"mesh_file_path": ("STRING", {"default": '', "multiline": False}),
"use_fastmesh": ("BOOLEAN", {"default": True, "tooltip": "Использовать FastMesh для GLB/GLTF файлов"}),
"resize": ("BOOLEAN", {"default": False},),
"renormal": ("BOOLEAN", {"default": True},),
"retex": ("BOOLEAN", {"default": False},),
"optimizable": ("BOOLEAN", {"default": False},),
"clean": ("BOOLEAN", {"default": False},),
"resize_bound": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1000.0, "step": 0.001}),
},
}
RETURN_TYPES = (
"MESH",
)
RETURN_NAMES = (
"mesh",
)
FUNCTION = "load_mesh"
CATEGORY = "Comfy3D/Import|Export"
def load_mesh(self, mesh_file_path, use_fastmesh, resize, renormal, retex, optimizable, clean, resize_bound):
import time
mesh = None
if not os.path.isabs(mesh_file_path):
mesh_file_path = os.path.join(comfy_paths.input_directory, mesh_file_path)
if os.path.exists(mesh_file_path):
folder, filename = os.path.split(mesh_file_path)
if filename.lower().endswith(SUPPORTED_3D_EXTENSIONS):
with torch.inference_mode(not optimizable):
start_time = time.time()
if use_fastmesh and mesh_file_path.endswith((".glb", ".gltf")):
mesh = FastMesh.load(mesh_file_path, resize, renormal, retex, clean, resize_bound)
print(f"[FastMesh] Loading completed in {time.time() - start_time:.3f}s")
else:
mesh = Mesh.load(mesh_file_path, resize, renormal, retex, clean, resize_bound)
print(f"[Mesh] Loading completed in {time.time() - start_time:.3f}s")
else:
cstr(f"[{self.__class__.__name__}] File name {filename} does not end with supported 3D file extensions: {SUPPORTED_3D_EXTENSIONS}").error.print()
else:
cstr(f"[{self.__class__.__name__}] File {mesh_file_path} does not exist").error.print()
return (mesh, )
class Save_3D_Mesh:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"mesh": ("MESH",),
"save_path": ("STRING", {"default": 'Mesh_%Y-%m-%d-%M-%S-%f.glb', "multiline": False}),
"use_fastmesh": ("BOOLEAN", {"default": True, "tooltip": "Использовать FastMesh для быстрого сохранения GLB/PLY/OBJ"}),
},
}
OUTPUT_NODE = True
RETURN_TYPES = (
"STRING",
)
RETURN_NAMES = (
"save_path",
)
FUNCTION = "save_mesh"
CATEGORY = "Comfy3D/Import|Export"
def save_mesh(self, mesh, save_path, use_fastmesh):
import time
save_path = parse_save_filename(save_path, comfy_paths.output_directory, SUPPORTED_3D_EXTENSIONS, self.__class__.__name__)
if save_path is not None:
start_time = time.time()
# Используем FastMesh методы для быстрого сохранения
if use_fastmesh and save_path.endswith((".glb", ".ply", ".obj")):
# Если это уже FastMesh - используем напрямую
print(f"[Save_3D_Mesh] FastMesh detected")
if hasattr(mesh, '_write_glb_fast'):
mesh.write(save_path)
save_time = time.time() - start_time
print(f"[FastMesh] Saving completed in {save_time:.3f}s")
else:
# Если обычный Mesh - создаем временный FastMesh для быстрых методов
print(f"[Save_3D_Mesh] REGULAR Mesh detected")
fast_mesh = FastMesh(
v=mesh.v, f=mesh.f, vn=mesh.vn, fn=mesh.fn,
vt=mesh.vt, ft=mesh.ft, vc=mesh.vc,
albedo=mesh.albedo, metallicRoughness=getattr(mesh, 'metallicRoughness', None),
device=mesh.device
)
fast_mesh.ori_center = getattr(mesh, 'ori_center', 0)
fast_mesh.ori_scale = getattr(mesh, 'ori_scale', 1)
fast_mesh.write(save_path)
save_time = time.time() - start_time
print(f"[FastMesh] Saving completed in {save_time:.3f}s")
else:
# Обычное сохранение через стандартный метод
mesh.write(save_path)
save_time = time.time() - start_time
print(f"[Mesh] Saving completed in {save_time:.3f}s")
return (save_path, )
class Preview_3D_FastMesh:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"mesh_file_path": ("STRING", {"default": '', "multiline": False}),
},
}
OUTPUT_NODE = True
RETURN_TYPES = ()
FUNCTION = "preview_mesh"
CATEGORY = "Comfy3D/Visualize"
def preview_mesh(self, mesh_file_path):
mesh_folder_path, filename = os.path.split(mesh_file_path)
if not os.path.isabs(mesh_file_path):
mesh_file_path = os.path.join(comfy_paths.output_directory, mesh_folder_path, filename)
if not filename.lower().endswith(SUPPORTED_3D_EXTENSIONS):
cstr(f"[{self.__class__.__name__}] File name {filename} does not end with supported 3D file extensions: {SUPPORTED_3D_EXTENSIONS}").error.print()
mesh_file_path = ""
print(f"[Preview_3D_FastMesh] Final mesh path: {mesh_file_path}")
print(f"[Preview_3D_FastMesh] File exists: {os.path.exists(mesh_file_path) if mesh_file_path else False}")
previews = [
{
"filepath": mesh_file_path,
}
]
return {"ui": {"previews": previews}, "result": ()}
class Load_3D_FastMesh:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"mesh_file_path": ("STRING", {"default": '', "multiline": False}),
"use_fastmesh": ("BOOLEAN", {"default": True, "tooltip": "Использовать FastMesh загрузчик"}),
"resize": ("BOOLEAN", {"default": False},),
"renormal": ("BOOLEAN", {"default": True},),
"retex": ("BOOLEAN", {"default": False},),
"optimizable": ("BOOLEAN", {"default": False},),
"clean": ("BOOLEAN", {"default": False},),
"resize_bound": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1000.0, "step": 0.001}),
},
}
RETURN_TYPES = (
"MESH",
)
RETURN_NAMES = (
"mesh",
)
FUNCTION = "load_mesh"
CATEGORY = "Comfy3D/Import|Export"
def load_mesh(self, mesh_file_path, use_fastmesh, resize, renormal, retex, optimizable, clean, resize_bound):
import time
mesh = None
if not os.path.isabs(mesh_file_path):
mesh_file_path = os.path.join(comfy_paths.input_directory, mesh_file_path)
if os.path.exists(mesh_file_path):
folder, filename = os.path.split(mesh_file_path)
if filename.lower().endswith(SUPPORTED_3D_EXTENSIONS):
with torch.inference_mode(not optimizable):
start_time = time.time()
if use_fastmesh and mesh_file_path.endswith((".glb", ".gltf")):
from mesh_processor.mesh import FastMesh
mesh = FastMesh.load(mesh_file_path, resize, renormal, retex, clean, resize_bound)
print(f"[FastMesh] Loading completed in {time.time() - start_time:.3f}s")
else:
mesh = Mesh.load(mesh_file_path, resize, renormal, retex, clean, resize_bound)
mesh_type = "FastMesh" if use_fastmesh else "Mesh"
print(f"[{mesh_type}] Loading completed in {time.time() - start_time:.3f}s")
else:
cstr(f"[{self.__class__.__name__}] File name {filename} does not end with supported 3D file extensions: {SUPPORTED_3D_EXTENSIONS}").error.print()
else:
cstr(f"[{self.__class__.__name__}] File {mesh_file_path} does not exist").error.print()
return (mesh, )
class Save_3D_FastMesh:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"mesh": ("MESH",),
"save_path": ("STRING", {"default": 'FastMesh_%Y-%m-%d-%M-%S-%f.glb', "multiline": False}),
},
}
OUTPUT_NODE = True
RETURN_TYPES = (
"STRING",
)
RETURN_NAMES = (
"save_path",
)
FUNCTION = "save_mesh"
CATEGORY = "Comfy3D/Import|Export"
def save_mesh(self, mesh, save_path):
import time
save_path = parse_save_filename(save_path, comfy_paths.output_directory, SUPPORTED_3D_EXTENSIONS, self.__class__.__name__)
if save_path is not None:
start_time = time.time()
mesh.write(save_path)
save_time = time.time() - start_time
mesh_type = "FastMesh" if hasattr(mesh, '_create_empty_albedo') else "Mesh"
print(f"[{mesh_type}] Saving completed in {save_time:.3f}s")
return (save_path, )