import sys from os import path sys.path.insert(0, path.dirname(__file__)) from folder_paths import get_filename_list, get_full_path, get_save_image_path, get_output_directory from comfy.model_management import get_torch_device from tsr.system import TSR from PIL import Image import numpy as np import torch class TripoSRSampler: def __init__(self): self.initialized_model = None @classmethod def INPUT_TYPES(s): return { "required": { "model": (get_filename_list("checkpoints"),), "reference_image": ("IMAGE",), "chunk_size": ("INT", {"default": 8192, "min": 1, "max": 10000}) } } RETURN_TYPES = ("MESH",) FUNCTION = "sample" CATEGORY = "Flowty TripoSR" def sample(self, model, reference_image, chunk_size): outputs = [] device = get_torch_device() if not torch.cuda.is_available(): device = "cpu" if not self.initialized_model: print("Loading TripoSR model") self.initialized_model = TSR.from_pretrained_custom( weight_path=get_full_path("checkpoints", model), config_path=path.join(path.dirname(__file__), "config.yaml") ) self.initialized_model.renderer.set_chunk_size(chunk_size) self.initialized_model.to(device) with torch.no_grad(): for image in reference_image: i = 255. * image.cpu().numpy() i = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8)) if i.mode == 'RGBA': i = i.convert('RGB') scene_codes = self.initialized_model([i], device) meshes = self.initialized_model.extract_mesh(scene_codes) outputs.append(meshes[0]) return (outputs,) class TripoSRViewer: @classmethod def INPUT_TYPES(s): return { "required": { "mesh": ("MESH",) } } RETURN_TYPES = () OUTPUT_NODE = True FUNCTION = "display" CATEGORY = "Flowty TripoSR" def display(self, mesh): saved = list() full_output_folder, filename, counter, subfolder, filename_prefix = get_save_image_path("meshsave", get_output_directory()) for (batch_number, single_mesh) in enumerate(mesh): filename_with_batch_num = filename.replace("%batch_num%", str(batch_number)) file = f"{filename_with_batch_num}_{counter:05}_.obj" single_mesh.apply_transform(np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, -1, 0, 0], [0, 0, 0, 1]])) single_mesh.export(path.join(full_output_folder, file)) saved.append({ "filename": file, "type": "output", "subfolder": subfolder }) return {"ui": {"mesh": saved}} NODE_CLASS_MAPPINGS = { "TripoSRSampler": TripoSRSampler, "TripoSRViewer": TripoSRViewer } NODE_DISPLAY_NAME_MAPPINGS = { "TripoSRSampler": "TripoSR Sampler", "TripoSRViewer": "TripoSR Viewer" } WEB_DIRECTORY = "./web" __all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS', 'WEB_DIRECTORY']