diff --git a/__init__.py b/__init__.py index 5ee7d66..2d25932 100644 --- a/__init__.py +++ b/__init__.py @@ -7,6 +7,7 @@ NODE_CLASS_MAPPINGS = { "WanFunInpaintToVideoTiledVAE": WanFunInpaintToVideoTiledVAE, "WanVaceToVideoTiledVAE": WanVaceToVideoTiledVAE, "WanCameraImageToVideoTiledVAE":WanCameraImageToVideoTiledVAE, + "WanPhantomSubjectToVideoTiledVAE": WanPhantomSubjectToVideoTiledVAE, } NODE_DISPLAY_NAME_MAPPINGS = { @@ -16,4 +17,5 @@ NODE_DISPLAY_NAME_MAPPINGS = { "WanFunInpaintToVideoTiledVAE": "WanFunInpaintToVideo (Tiled VAE encode)", "WanVaceToVideoTiledVAE": "WanVaceToVideo (Tiled VAE encode)", "WanCameraImageToVideoTiledVAE": "WanCameraImageToVideo (Tiled VAE encode)", + "WanPhantomSubjectToVideoTiledVAE": "WanPhantomSubjectToVideo (Tiled VAE encode)", } diff --git a/nodes_wan.py b/nodes_wan.py index 334c29f..33143f6 100644 --- a/nodes_wan.py +++ b/nodes_wan.py @@ -357,3 +357,46 @@ class WanCameraImageToVideoTiledVAE: out_latent = {} out_latent["samples"] = latent return (positive, negative, out_latent) + +class WanPhantomSubjectToVideoTiledVAE: + @classmethod + def INPUT_TYPES(s): + return {"required": {"positive": ("CONDITIONING", ), + "negative": ("CONDITIONING", ), + "vae": ("VAE", ), + "width": ("INT", {"default": 832, "min": 16, "max": nodes.MAX_RESOLUTION, "step": 16}), + "height": ("INT", {"default": 480, "min": 16, "max": nodes.MAX_RESOLUTION, "step": 16}), + "length": ("INT", {"default": 81, "min": 1, "max": nodes.MAX_RESOLUTION, "step": 4}), + "batch_size": ("INT", {"default": 1, "min": 1, "max": 4096}), + + "tile_size": ("INT", {"default": 512, "min": 64, "max": 4096, "step": 64}), + "overlap": ("INT", {"default": 64, "min": 0, "max": 4096, "step": 32}), + "temporal_size": ("INT", {"default": 64, "min": 8, "max": 4096, "step": 4, "tooltip": "Amount of frames to encode at a time."}), + "temporal_overlap": ("INT", {"default": 8, "min": 4, "max": 4096, "step": 4, "tooltip": "Amount of frames to overlap."}) + }, + "optional": {"images": ("IMAGE", ), + }} + + RETURN_TYPES = ("CONDITIONING", "CONDITIONING", "CONDITIONING", "LATENT") + RETURN_NAMES = ("positive", "negative_text", "negative_img_text", "latent") + FUNCTION = "encode" + + CATEGORY = "conditioning/video_models" + + def encode(self, positive, negative, vae, width, height, length, batch_size, tile_size, overlap, temporal_size, temporal_overlap, images): + latent = torch.zeros([batch_size, 16, ((length - 1) // 4) + 1, height // 8, width // 8], device=comfy.model_management.intermediate_device()) + cond2 = negative + if images is not None: + images = comfy.utils.common_upscale(images[:length].movedim(-1, 1), width, height, "bilinear", "center").movedim(1, -1) + latent_images = [] + for i in images: + latent_images += [vae.encode_tiled(i.unsqueeze(0)[:, :, :, :3], tile_x=tile_size, tile_y=tile_size, overlap=overlap, tile_t=temporal_size, overlap_t=temporal_overlap)] + concat_latent_image = torch.cat(latent_images, dim=2) + + positive = node_helpers.conditioning_set_values(positive, {"time_dim_concat": concat_latent_image}) + cond2 = node_helpers.conditioning_set_values(negative, {"time_dim_concat": concat_latent_image}) + negative = node_helpers.conditioning_set_values(negative, {"time_dim_concat": comfy.latent_formats.Wan21().process_out(torch.zeros_like(concat_latent_image))}) + + out_latent = {} + out_latent["samples"] = latent + return (positive, cond2, negative, out_latent)