add:easy sv3dLoader
This commit is contained in:
@@ -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`
|
||||
|
||||
@@ -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
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user