add:easy sv3dLoader

This commit is contained in:
yolain
2024-03-31 18:19:16 +08:00
parent d5fc43e11f
commit ac7db29df9
5 changed files with 241 additions and 9 deletions
+1
View File
@@ -35,6 +35,7 @@
PS: Please update [ComfyUI_IPAdapter_plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) to v2, and moved v1 models to **ComfyUI\models\ipadapter** (Otherwise, the latest model is automatically downloaded from Huggingface)
<br>
- Added `easy sv3dLoader`
- Added `easy dynamiCrafterLoader`
- Added `easy ipadapterApply`
- Added `easy ipadapterApplyADV`
+1
View File
@@ -39,6 +39,7 @@
PS: 请更新至最新版v2的 [ComfyUI_IPAdapter_plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus), 并移动v1版本模型文件至 ComfyUI\models\ipadapter (否则会自动从huggingface下载最新模型)
<br>
- 增加 `easy sv3dLoader`
- 增加 `easy dynamiCrafterLoader`
- 增加 `easy ipadapterApply`
- 增加 `easy ipadapterApplyADV`
+169 -8
View File
@@ -25,6 +25,7 @@ from .libs.xyplot import easyXYPlot
from .libs.controlnet import easyControlnet
from .libs.conditioning import prompt_to_cond, set_cond
from .libs.cache import cache, update_cache
from .libs.easing import EasingBase
sampler = easySampler()
easyCache = easyLoader()
@@ -1117,7 +1118,7 @@ class zero123Loader:
@classmethod
def INPUT_TYPES(cls):
def get_file_list(filenames):
return [file for file in filenames if file != "put_models_here.txt" and "zero123" in file]
return [file for file in filenames if file != "put_models_here.txt" and "zero123" in file.lower()]
return {"required": {
"ckpt_name": (get_file_list(folder_paths.get_filename_list("checkpoints")),),
@@ -1197,6 +1198,164 @@ class zero123Loader:
return (pipe, model, vae)
# SV3D加载器
class sv3DLoader(EasingBase):
def __init__(self):
super().__init__()
@classmethod
def INPUT_TYPES(cls):
def get_file_list(filenames):
return [file for file in filenames if file != "put_models_here.txt" and "sv3d" in file]
return {"required": {
"ckpt_name": (get_file_list(folder_paths.get_filename_list("checkpoints")),),
"vae_name": (["Baked VAE"] + folder_paths.get_filename_list("vae"),),
"init_image": ("IMAGE",),
"empty_latent_width": ("INT", {"default": 576, "min": 16, "max": MAX_RESOLUTION, "step": 8}),
"empty_latent_height": ("INT", {"default": 576, "min": 16, "max": MAX_RESOLUTION, "step": 8}),
"batch_size": ("INT", {"default": 21, "min": 1, "max": 4096}),
"interp_easing": (["linear", "ease_in", "ease_out", "ease_in_out"], {"default": "linear"}),
"easing_mode": (["azimuth", "elevation", "custom"], {"default": "azimuth"}),
},
"optional": {"scheduler": ("STRING", {"default": "", "multiline": True})},
"hidden": {"prompt": "PROMPT", "my_unique_id": "UNIQUE_ID"}
}
RETURN_TYPES = ("PIPE_LINE", "MODEL", "STRING")
RETURN_NAMES = ("pipe", "model", "interp_log")
FUNCTION = "adv_pipeloader"
CATEGORY = "EasyUse/Loaders"
def adv_pipeloader(self, ckpt_name, vae_name, init_image, empty_latent_width, empty_latent_height, batch_size, interp_easing, easing_mode, scheduler='',prompt=None, my_unique_id=None):
model: ModelPatcher | None = None
vae: VAE | None = None
clip: CLIP | None = None
# Clean models from loaded_objects
easyCache.update_loaded_objects(prompt)
model, clip, vae, clip_vision = easyCache.load_checkpoint(ckpt_name, "Default", True)
output = clip_vision.encode_image(init_image)
pooled = output.image_embeds.unsqueeze(0)
pixels = comfy.utils.common_upscale(init_image.movedim(-1, 1), empty_latent_width, empty_latent_height, "bilinear", "center").movedim(1,
-1)
encode_pixels = pixels[:, :, :, :3]
t = vae.encode(encode_pixels)
azimuth_points = []
elevation_points = []
if easing_mode == 'azimuth':
azimuth_points = [(0, 0), (batch_size-1, 360)]
elevation_points = [(0, 0)] * batch_size
elif easing_mode == 'elevation':
azimuth_points = [(0, 0)] * batch_size
elevation_points = [(0, -90), (batch_size-1, 90)]
else:
schedulers = scheduler.rstrip('\n')
for line in schedulers.split('\n'):
frame_str, point_str = line.split(':')
point_str = point_str.strip()[1:-1]
point = point_str.split(',')
azimuth_point = point[0]
elevation_point = point[1] if point[1] else 0.0
frame = int(frame_str.strip())
azimuth = float(azimuth_point)
azimuth_points.append((frame, azimuth))
elevation_val = float(elevation_point)
elevation_points.append((frame, elevation_val))
azimuth_points.sort(key=lambda x: x[0])
elevation_points.sort(key=lambda x: x[0])
#interpolation
next_point = 1
next_elevation_point = 1
elevations = []
azimuths = []
# For azimuth interpolation
for i in range(batch_size):
# Find the interpolated azimuth for the current frame
while next_point < len(azimuth_points) and i >= azimuth_points[next_point][0]:
next_point += 1
if next_point == len(azimuth_points):
next_point -= 1
prev_point = max(next_point - 1, 0)
if azimuth_points[next_point][0] != azimuth_points[prev_point][0]:
timing = (i - azimuth_points[prev_point][0]) / (
azimuth_points[next_point][0] - azimuth_points[prev_point][0])
interpolated_azimuth = self.ease(azimuth_points[prev_point][1], azimuth_points[next_point][1], self.easing(timing, interp_easing))
else:
interpolated_azimuth = azimuth_points[prev_point][1]
# Interpolate the elevation
next_elevation_point = 1
while next_elevation_point < len(elevation_points) and i >= elevation_points[next_elevation_point][0]:
next_elevation_point += 1
if next_elevation_point == len(elevation_points):
next_elevation_point -= 1
prev_elevation_point = max(next_elevation_point - 1, 0)
if elevation_points[next_elevation_point][0] != elevation_points[prev_elevation_point][0]:
timing = (i - elevation_points[prev_elevation_point][0]) / (
elevation_points[next_elevation_point][0] - elevation_points[prev_elevation_point][0])
interpolated_elevation = self.ease(elevation_points[prev_point][1], elevation_points[next_point][1], self.easing(timing, interp_easing))
else:
interpolated_elevation = elevation_points[prev_elevation_point][1]
azimuths.append(interpolated_azimuth)
elevations.append(interpolated_elevation)
log_node_info("easy sv3dLoader", "azimuths:" + str(azimuths))
log_node_info("easy sv3dLoader", "elevations:" + str(elevations))
log = 'azimuths:' + str(azimuths) + '\n\n' + "elevations:" + str(elevations)
# Structure the final output
positive = [[pooled, {"concat_latent_image": t, "elevation": elevations, "azimuth": azimuths}]]
negative = [[torch.zeros_like(pooled),
{"concat_latent_image": torch.zeros_like(t), "elevation": elevations, "azimuth": azimuths}]]
latent = torch.zeros([batch_size, 4, empty_latent_height // 8, empty_latent_width // 8])
samples = {"samples": latent}
image = easySampler.pil2tensor(Image.new('RGB', (1, 1), (0, 0, 0)))
pipe = {"model": model,
"positive": positive,
"negative": negative,
"vae": vae,
"clip": clip,
"samples": samples,
"images": image,
"seed": 0,
"loader_settings": {"ckpt_name": ckpt_name,
"vae_name": vae_name,
"positive": positive,
"positive_l": None,
"positive_g": None,
"positive_balance": None,
"negative": negative,
"negative_l": None,
"negative_g": None,
"negative_balance": None,
"empty_latent_width": empty_latent_width,
"empty_latent_height": empty_latent_height,
"batch_size": batch_size,
"seed": 0,
"empty_samples": samples, }
}
return (pipe, model, log)
#svd加载器
class svdLoader:
@@ -4871,18 +5030,18 @@ class pipeIn:
neg = neg if neg is not None else pipe.get("negative")
if neg is None:
log_node_warn(f'pipeIn[{my_unique_id}]', "Neg Conditioning missing from pipeLine")
samples = latent if latent is not None else pipe.get("samples")
if samples is None:
log_node_warn(f'pipeIn[{my_unique_id}]', "Latent missing from pipeLine")
vae = vae if vae is not None else pipe.get("vae")
if vae is None:
log_node_warn(f'pipeIn[{my_unique_id}]', "VAE missing from pipeLine")
clip = clip if clip is not None else pipe.get("clip")
if clip is None:
log_node_warn(f'pipeIn[{my_unique_id}]', "Clip missing from pipeLine")
if image is None:
if latent is not None:
samples = latent
elif image is None:
samples = pipe.get("samples") if pipe is not None else None
image = pipe.get("images") if pipe is not None else None
else:
elif image is not None:
if pipe is None:
batch_size = 1
else:
@@ -6166,8 +6325,9 @@ NODE_CLASS_MAPPINGS = {
"easy fullLoader": fullLoader,
"easy a1111Loader": a1111Loader,
"easy comfyLoader": comfyLoader,
"easy zero123Loader": zero123Loader,
"easy svdLoader": svdLoader,
"easy sv3dLoader": sv3DLoader,
"easy zero123Loader": zero123Loader,
"easy dynamiCrafterLoader": dynamiCrafterLoader,
"easy cascadeLoader": cascadeLoader,
"easy loraStack": loraStackLoader,
@@ -6258,8 +6418,9 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"easy fullLoader": "EasyLoader (Full)",
"easy a1111Loader": "EasyLoader (A1111)",
"easy comfyLoader": "EasyLoader (Comfy)",
"easy zero123Loader": "EasyLoader (Zero123)",
"easy svdLoader": "EasyLoader (SVD)",
"easy sv3dLoader": "EasyLoader (SV3D)",
"easy zero123Loader": "EasyLoader (Zero123)",
"easy dynamiCrafterLoader": "EasyLoader (DynamiCrafter)",
"easy cascadeLoader": "EasyCascadeLoader",
"easy loraStack": "EasyLoraStack",
+27
View File
@@ -0,0 +1,27 @@
@staticmethod
def easyIn(t: float)-> float:
return t*t
@staticmethod
def easyOut(t: float)-> float:
return -(t * (t - 2))
@staticmethod
def easyInOut(t: float)-> float:
if t < 0.5:
return 2*t*t
else:
return (-2*t*t) + (4*t) - 1
class EasingBase:
def easing(self, t: float, function='linear') -> float:
if function == 'easyIn':
return easyIn(t)
elif function == 'easyOut':
return easyOut(t)
elif function == 'easyInOut':
return easyInOut(t)
else:
return t
def ease(self, start, end, t) -> float:
return end * t + start * (1 - t)
+43 -1
View File
@@ -858,6 +858,44 @@ app.registerExtension({
};
}
if(["easy sv3dLoader"].includes(nodeData.name)){
function changeSchedulerText(mode, batch_size, inputEl) {
console.log(mode)
switch (mode){
case 'azimuth':
inputEl.readOnly = true
inputEl.style.opacity = 0.6
return `0:(0.0,0.0)` + (batch_size > 1 ? `\n${batch_size-1}:(360.0,0.0)` : '')
case 'elevation':
inputEl.readOnly = true
inputEl.style.opacity = 0.6
return `0:(-90.0,0.0)` + (batch_size > 1 ? `\n${batch_size-1}:(90.0,0.0)` : '')
case 'custom':
inputEl.readOnly = false
inputEl.style.opacity = 1
return `0:(0.0,0.0)\n9:(180.0,0.0)\n20:(360.0,0.0)`
}
}
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = async function () {
onNodeCreated ? onNodeCreated.apply(this, []) : undefined;
const easing_mode_widget = this.widgets.find(w => w.name == 'easing_mode')
const batch_size = this.widgets.find(w => w.name == 'batch_size')
const scheduler = this.widgets.find(w => w.name == 'scheduler')
setTimeout(_=>{
if(!scheduler.value) scheduler.value = changeSchedulerText(easing_mode_widget.value, batch_size.value, scheduler.inputEl)
},1)
easing_mode_widget.callback = value=>{
scheduler.value = changeSchedulerText(value, batch_size.value, scheduler.inputEl)
}
batch_size.callback = value =>{
scheduler.value = changeSchedulerText(easing_mode_widget.value, value, scheduler.inputEl)
}
}
}
if (seedNodes.includes(nodeData.name)) {
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = async function () {
@@ -999,7 +1037,11 @@ const getSetWidgets = ['rescale_after_model', 'rescale',
'refiner_lora1_name', 'refiner_lora2_name', 'upscale_method',
'image_output', 'add_noise', 'info', 'sampler_name',
'ckpt_B_name', 'ckpt_C_name', 'save_model', 'refiner_ckpt_name',
'num_loras', 'mode', 'toggle', 'resolution', 'target_parameter', 'input_count', 'replace_count', 'downscale_mode', 'range_mode','text_combine_mode', 'input_mode','lora_count','ckpt_count', 'conditioning_mode', 'preset', 'use_tiled', 'use_batch', 'num_embeds']
'num_loras', 'mode', 'toggle', 'resolution', 'target_parameter',
'input_count', 'replace_count', 'downscale_mode', 'range_mode','text_combine_mode', 'input_mode',
'lora_count','ckpt_count', 'conditioning_mode', 'preset', 'use_tiled', 'use_batch', 'num_embeds',
"easing_mode"
]
function getSetters(node) {
if (node.widgets)