diff --git a/SDNode/blueprints.py b/SDNode/blueprints.py index 2ab8465..306c892 100644 --- a/SDNode/blueprints.py +++ b/SDNode/blueprints.py @@ -15,7 +15,7 @@ from bpy.types import Context, UILayout from .nodegroup import LABEL_TAG, SOCK_TAG, SDNGroup -from .utils import gen_mask, THelper +from .utils import gen_mask, THelper, WindowLogger from .plugins.animatedimageplayer import AnimatedImagePlayer as AIP from .nodes import NodeBase, Ops_Add_SaveImage, Ops_Link_Mask, Ops_Active_Tex, Set_Render_Res, Ops_Switch_Socket_Widget from .nodes import name2path, get_icon_path, Images @@ -115,21 +115,21 @@ def delegate(self: NodeBase): return 0 oriw = w w = max(self.bl_width_min, w) - fpis = get_pref().preview_image_size_type == "FIXED" - if fpis: + fixed = get_pref().preview_image_size_type == "FIXED" + if fixed: pw = get_pref().preview_image_size w = min(oriw, pw) sw = w w *= count - def delegate(self: NodeBase, w, fpis): + def delegate(self: NodeBase, w, fixed): """ 可能会因为 width 访问导致crash, 可以先清理Timer """ - if not fpis: + if not fixed: self.bl_width_max = 8192 self.bl_width_min = 32 - if self.width == w and not fpis: + if self.width == w and not fixed: return # 避免删除所有节点时导致blender崩溃 if len(self.get_tree().nodes) != hack_nodes_num[0]: @@ -137,11 +137,13 @@ def delegate(self: NodeBase, w, fpis): Timer.clear() return hack_nodes_num[0] = len(self.get_tree().nodes) - self.width = w - if self.bl_width_max < w or fpis: - self.bl_width_max = w + if w != self.width: + self.width = w + if self.bl_width_max < w or fixed: + self.bl_width_max = w + 32 - Timer.put((delegate, self, w, fpis)) + # Timer.put((delegate, self, w, fixed)) + delegate(self, w, fixed) return sw @@ -177,6 +179,9 @@ def setattr(s, self: NodeBase, prop_name, v): def new_btn_enable(s, self, layout, context): return True + def set_width(s, self: NodeBase): + ... + def draw_button(s, self: NodeBase, context: Context, layout: UILayout, prop: str, swsock=True, swdisp=False): def show_model_preview(self: NodeBase, context: bpy.types.Context, layout: bpy.types.UILayout, prop: str): if self.class_type not in name2path: @@ -692,6 +697,7 @@ def dump_specific(s, self: NodeBase = None, cfg=None, selected_only=False, **kwa def post_fn(s, self: NodeBase, t: Task, result): logger.debug("%s%s->%s", self.class_type, _T('Post Function'), result) + WindowLogger.push_log("%s%s->%s", self.class_type, _T('Post Function'), result) text = result.get("output", {}).get("tags", []) text = "".join(text) @@ -740,6 +746,7 @@ class PreviewTextNode(BluePrintBase): def post_fn(s, self: NodeBase, t: Task, result): logger.debug("%s%s->%s", self.class_type, _T('Post Function'), result) + WindowLogger.push_log("%s%s->%s", self.class_type, _T('Post Function'), result) text = result.get("output", {}).get("string", []) if text and isinstance(text[0], str): self.text = text[0] @@ -1160,6 +1167,17 @@ def cache_to_local(data, suffix="png", save_path="") -> Path: class 预览(BluePrintBase): comfyClass = "预览" + def set_width(s, self: NodeBase): + if not self.prev: + return self.width + pnum = len(self.prev) + p0 = self.prev[0].image + w = max(p0.size[0], p0.size[1]) + if w == 0: + return self.width + w = setwidth(self, w, count=min(self.lnum, pnum)) + return w + def spec_extra_properties(s, properties, nname, ndesc): prop = bpy.props.CollectionProperty(type=Images) properties["prev"] = prop @@ -1180,10 +1198,6 @@ def spec_draw(s, self: NodeBase, context: Context, layout: UILayout, prop: str, if pnum == 0: return True p0 = self.prev[0].image - w = max(p0.size[0], p0.size[1]) - if w == 0: - return True - w = setwidth(self, w, count=min(self.lnum, pnum)) layout.label(text=f"{p0.file_format} : [{p0.size[0]} x {p0.size[1]}]") col = layout.column(align=True) for i, p in enumerate(self.prev): @@ -1193,7 +1207,7 @@ def spec_draw(s, self: NodeBase, context: Context, layout: UILayout, prop: str, if prev.name not in Icon: Icon.reg_icon_by_pixel(prev, prev.name) icon_id = Icon[prev.name] - fcol.template_icon(icon_id, scale=w // 20) + fcol.template_icon(icon_id, scale=self.width // 20) return True def serialize_pre_specific(s, self: NodeBase): @@ -1203,11 +1217,14 @@ def serialize_pre_specific(s, self: NodeBase): def post_fn(s, self: NodeBase, t: Task, result): logger.debug("%s%s->%s", self.class_type, _T('Post Function'), result) + WindowLogger.push_log("%s%s->%s", self.class_type, _T('Post Function'), result) img_paths = result.get("output", {}).get("images", []) if not img_paths: logger.error('response is %s, cannot find images in it', result) + WindowLogger.push_log('response is %s, cannot find images in it', result) return logger.warning("%s: %s", _T('Load Preview Image'), img_paths) + WindowLogger.push_log("%s: %s", _T('Load Preview Image'), img_paths) def f(self, img_paths: list[dict]): self.prev.clear() @@ -1235,6 +1252,16 @@ def f(self, img_paths: list[dict]): class PreviewImage(BluePrintBase): comfyClass = "PreviewImage" + def set_width(s, self: NodeBase): + if not self.prev: + return self.width + pnum = len(self.prev) + p0 = self.prev[0].image + w = max(p0.size[0], p0.size[1]) + if w == 0: + return self.width + return setwidth(self, w, count=min(self.lnum, pnum)) + def spec_extra_properties(s, properties, nname, ndesc): prop = bpy.props.CollectionProperty(type=Images) properties["prev"] = prop @@ -1255,10 +1282,6 @@ def spec_draw(s, self: NodeBase, context: Context, layout: UILayout, prop: str, if pnum == 0: return True p0 = self.prev[0].image - w = max(p0.size[0], p0.size[1]) - if w == 0: - return True - w = setwidth(self, w, count=min(self.lnum, pnum)) layout.label(text=f"{p0.file_format} : [{p0.size[0]} x {p0.size[1]}]") col = layout.column(align=True) for i, p in enumerate(self.prev): @@ -1268,7 +1291,7 @@ def spec_draw(s, self: NodeBase, context: Context, layout: UILayout, prop: str, if prev.name not in Icon: Icon.reg_icon_by_pixel(prev, prev.name) icon_id = Icon[prev.name] - fcol.template_icon(icon_id, scale=w // 20) + fcol.template_icon(icon_id, scale=self.width // 20) return True def serialize_pre_specific(s, self: NodeBase): @@ -1278,11 +1301,14 @@ def serialize_pre_specific(s, self: NodeBase): def post_fn(s, self: NodeBase, t: Task, result): logger.debug("%s%s->%s", self.class_type, _T('Post Function'), result) + WindowLogger.push_log("%s%s->%s", self.class_type, _T('Post Function'), result) img_paths = result.get("output", {}).get("images", []) if not img_paths: logger.error('response is %s, cannot find images in it', result) + WindowLogger.push_log('response is %s, cannot find images in it', result) return logger.warning("%s: %s", _T('Load Preview Image'), img_paths) + WindowLogger.push_log("%s: %s", _T('Load Preview Image'), img_paths) def f(self, img_paths: list[dict]): self.prev.clear() @@ -1535,6 +1561,11 @@ def f(_, img): class 输入图像(BluePrintBase): comfyClass = "输入图像" + def set_width(s, self: NodeBase): + if not self.prev: + return self.width + return setwidth(self, max(self.prev.size[0], self.prev.size[1])) + def spec_extra_properties(s, properties, nname, ndesc): prop = bpy.props.PointerProperty(type=bpy.types.Image) properties["prev"] = prop @@ -1598,8 +1629,6 @@ def f(self): if not (img := Icon.find_image(self.image)): return self.prev = img - w = max(self.prev.size[0], self.prev.size[1]) - setwidth(self, w) update_screen() if Icon.try_mark_image(self.image) or not self.prev: Timer.put((f, self)) @@ -1618,9 +1647,7 @@ def f(self): row = layout.row(align=True) row.label(text=f"{self.prev.file_format} : [{self.prev.size[0]} x {self.prev.size[1]}]") row.operator(Set_Render_Res.bl_idname, text="", icon="LOOP_FORWARDS").node_name = self.name - w = max(self.prev.size[0], self.prev.size[1]) - w = setwidth(self, w) - layout.template_icon(icon_id, scale=w // 20) + layout.template_icon(icon_id, scale=self.width // 20) return True elif prop in {"render_layer", "out_layers", "frames_dir", "disable_render", "use_current_frame", "input_frame"}: return True @@ -1738,6 +1765,11 @@ def spec_draw(s, self: NodeBase, context: Context, layout: UILayout, prop: str, class 截图(BluePrintBase): comfyClass = "截图" + def set_width(s, self: NodeBase): + if not self.prev: + return self.width + return setwidth(self, max(self.prev.size[0], self.prev.size[1])) + def draw_button(s, self: NodeBase, context: Context, layout: UILayout, prop: str, swsock=True, swdisp=False): if prop in {"x1", "y1", "x2", "y2"}: return True @@ -1751,8 +1783,6 @@ def f(self): if not (img := Icon.find_image(self.image)): return self.prev = img - w = max(self.prev.size[0], self.prev.size[1]) - setwidth(self, w) update_screen() if Icon.try_mark_image(self.image) or not self.prev: Timer.put((f, self)) @@ -1771,9 +1801,7 @@ def f(self): row = layout.row(align=True) row.label(text=f"{self.prev.file_format} : [{self.prev.size[0]} x {self.prev.size[1]}]") row.operator(Set_Render_Res.bl_idname, text="", icon="LOOP_FORWARDS").node_name = self.name - w = max(self.prev.size[0], self.prev.size[1]) - w = setwidth(self, w) - layout.template_icon(icon_id, scale=w // 20) + layout.template_icon(icon_id, scale=self.width // 20) return True return super().draw_button(self, context, layout, prop, swsock, swdisp) @@ -1853,12 +1881,15 @@ def post_fn(s, self: NodeBase, t: Task, result): result : {'node': '11', 'output': {'videos': [{'filename': 'img.gif', 'subfolder': '', 'type': 'output', 'format': 'image/gif'}]}, 'prompt_id': ''} """ logger.debug("%s%s->%s", self.class_type, _T('Post Function'), result) + WindowLogger.push_log("%s%s->%s", self.class_type, _T('Post Function'), result) # img_paths = link_get(result, "output.videos") img_paths = result.get("output", {}).get("videos", []) if not img_paths: logger.error(f'response is {result}, cannot find images in it') + WindowLogger.push_log(f'response is {result}, cannot find images in it') return logger.warning("%s: %s", _T('Load Preview Image'), img_paths) + WindowLogger.push_log("%s: %s", _T('Load Preview Image'), img_paths) def f(self, img_paths: list[dict]): """ @@ -1922,12 +1953,15 @@ def post_fn(s, self: NodeBase, t: Task, result): {'node': '9', 'output': {'gifs': [{'filename': 'AnimateDiff_00003.mov', 'subfolder': '', 'type': 'output', 'format': 'video/ProRes'}]}, 'prompt_id': '462c8f2d-7e1b-4003-9a12-36b43bec6743'} """ logger.debug("%s%s->%s", self.class_type, _T('Post Function'), result) + WindowLogger.push_log("%s%s->%s", self.class_type, _T('Post Function'), result) # img_paths = link_get(result, "output.videos") img_paths = result.get("output", {}).get("gifs", []) if not img_paths: logger.error(f'response is {result}, cannot find images in it') + WindowLogger.push_log(f'response is {result}, cannot find images in it') return logger.warning("%s: %s", _T('Load Preview Image'), img_paths) + WindowLogger.push_log("%s: %s", _T('Load Preview Image'), img_paths) def f(self, img_paths: list[dict]): """ @@ -2018,12 +2052,15 @@ def draw_button(s, self: NodeBase, context: Context, layout: UILayout, prop: str def post_fn(s, self: NodeBase, t: Task, result): logger.debug("%s%s->%s", self.class_type, _T('Post Function'), result) + WindowLogger.push_log("%s%s->%s", self.class_type, _T('Post Function'), result) # img_paths = link_get(result, "output.videos") img_paths = result.get("output", {}).get("images", []) if not img_paths: logger.error(f'response is {result}, cannot find images in it') + WindowLogger.push_log(f'response is {result}, cannot find images in it') return logger.warning("%s: %s", _T('Load Preview Image'), img_paths) + WindowLogger.push_log("%s: %s", _T('Load Preview Image'), img_paths) def f(self, img_paths: list[dict]): """ @@ -2085,12 +2122,15 @@ def draw_button(s, self: NodeBase, context: Context, layout: UILayout, prop: str def post_fn(s, self: NodeBase, t: Task, result): logger.debug("%s%s->%s", self.class_type, _T('Post Function'), result) + WindowLogger.push_log("%s%s->%s", self.class_type, _T('Post Function'), result) # img_paths = link_get(result, "output.videos") img_paths = result.get("output", {}).get("images", []) if not img_paths: logger.error(f'response is {result}, cannot find images in it') + WindowLogger.push_log(f'response is {result}, cannot find images in it') return logger.warning("%s: %s", _T('Load Preview Image'), img_paths) + WindowLogger.push_log("%s: %s", _T('Load Preview Image'), img_paths) def f(self, img_paths: list[dict]): """ @@ -2221,6 +2261,7 @@ def import_obj(s, filepath) -> list[bpy.types.Object]: def post_fn(s, self: NodeBase, t: Task, result): logger.debug("%s%s->%s", self.class_type, _T('Post Function'), result) + WindowLogger.push_log("%s%s->%s", self.class_type, _T('Post Function'), result) # result = {'node': '4', 'output': {'mesh': [{'filename': 'meshsave_00002_.obj', 'type': 'output', 'subfolder': ''}]}} output = result.get("output", {}) meshes = output.get("mesh", []) @@ -2232,6 +2273,7 @@ def f(self, meshes): filename = data.get("filename", "") if not filename.lower().endswith(".obj"): logger.warning(f"Not process {filename}") + WindowLogger.push_log(f"Not process {filename}") continue if self.mode in {"Import", "Replace"}: @@ -2336,6 +2378,7 @@ def import_glb(s, filepath) -> list[bpy.types.Object]: def post_fn(s, self: NodeBase, t: Task, result): logger.debug("%s%s->%s", self.class_type, _T('Post Function'), result) + WindowLogger.push_log("%s%s->%s", self.class_type, _T('Post Function'), result) # result = {'node': '4', 'output': {'mesh': [{'filename': 'meshsave_00002_.obj', 'type': 'output', 'subfolder': ''}]}} output = result.get("output", {}) meshes = output.get("mesh", []) @@ -2347,6 +2390,7 @@ def f(self, meshes): filename = data.get("filename", "") if not filename.lower().endswith(".glb"): logger.warning(f"Not process {filename}") + WindowLogger.push_log(f"Not process {filename}") continue if self.mode in {"Import", "Replace"}: @@ -2574,11 +2618,14 @@ def serialize_pre_specific(s, self: NodeBase): def post_fn(s, self: NodeBase, t: Task, result): logger.debug("%s%s->%s", self.class_type, _T('Post Function'), result) + WindowLogger.push_log("%s%s->%s", self.class_type, _T('Post Function'), result) audio_paths = result.get("output", {}).get("audio", []) if not audio_paths: logger.error('response is %s, cannot find audio in it', result) + WindowLogger.push_log('response is %s, cannot find audio in it', result) return logger.warning("%s: %s", _T('Load Preview Audio'), audio_paths) + WindowLogger.push_log("%s: %s", _T('Load Preview Audio'), audio_paths) def f(self, audio_paths: list[dict]): if not audio_paths: diff --git a/SDNode/custom_support.py b/SDNode/custom_support.py index e60b9fe..9a73f43 100644 --- a/SDNode/custom_support.py +++ b/SDNode/custom_support.py @@ -168,7 +168,7 @@ def f(data, mtype): Timer.put((f, data, mtype)) return True - def draw(self, layout: bpy.types.UILayout, ctxt=""): + def draw(self, layout: bpy.types.UILayout, ctxt="", use_region_width=True): from . import TaskManager if self.enable: cp = bpy.context.screen.sdn_custom @@ -187,9 +187,11 @@ def draw(self, layout: bpy.types.UILayout, ctxt=""): import blf per = prog["value"] / prog["max"] content = f"{per*100:3.0f}% " - lnum = int(bpy.context.region.width / bpy.context.preferences.view.ui_scale / 7 - 21) - lnum = int(lnum * 0.3) - lnum = int((bpy.context.region.width - blf.dimensions(0, content)[0]) / blf.dimensions(0, "█")[0]) - 10 + lnum = 20 + if use_region_width: + lnum = int(bpy.context.region.width / bpy.context.preferences.view.ui_scale / 7 - 21) + lnum = int(lnum * 0.3) + lnum = int((bpy.context.region.width - blf.dimensions(0, content)[0]) / blf.dimensions(0, "█")[0]) - 10 v = int(per * lnum) content = content + "█" * v + "░" * (lnum - v) row = layout.row() diff --git a/SDNode/manager.py b/SDNode/manager.py index 772b2bc..a347ba8 100644 --- a/SDNode/manager.py +++ b/SDNode/manager.py @@ -9,6 +9,7 @@ import aud from platform import system import struct +from ast import literal_eval from concurrent.futures import ThreadPoolExecutor from copy import deepcopy from shutil import rmtree @@ -19,6 +20,7 @@ from subprocess import Popen, PIPE, STDOUT from pathlib import Path from queue import Queue +from .utils import WindowLogger from ..utils import rmtree as rt, logger, _T, PkgInstaller, update_screen from ..timer import Timer from ..preference import get_pref @@ -150,9 +152,18 @@ class ErrType: def get_print(self, info): etype = info["type"] + if isinstance(etype, str) and etype.endswith("cup.CupException"): + info = literal_eval(info["message"]) + etype = info["type"] func = getattr(self, etype, self.unknown) return func(info) + def sdn_no_image_provided(self, info): + return self.__print__(info) + + def sdn_image_not_found(self, info): + return self.__print__(info) + def unknown(self, info): if self.WITH_PRINT: print(info) @@ -179,8 +190,10 @@ def __print__(self, info): info_list = [] if msg: info_list.append(msg) + WindowLogger.push_log(msg) if dt: info_list.append(dt) + WindowLogger.push_log(dt) return info_list def required_input_missing(self, info): @@ -412,7 +425,8 @@ def node_error_parse(self): node_errors = self.error_info["node_errors"] import bpy from .utils import get_tree - logger.error("Node Error Parse") + logger.error(_T("Node Error Parse")) + WindowLogger.push_log(_T("Node Error Parse")) for sc in bpy.data.screens: try: tree = get_tree(screen=sc) @@ -630,13 +644,16 @@ def run(self) -> bool: if not model_path or not Path(model_path).exists(): logger.error(_T("ComfyUI Path Not Found")) TaskManager.put_error_msg(_T("ComfyUI Path Not Found")) + WindowLogger.push_log(_T("ComfyUI Path Not Found")) return logger.debug("%s: %s", _T("Model Path"), model_path) + WindowLogger.push_log("%s: %s", _T("Model Path"), model_path) python = pref.get_python() if pref.install_deps: self.run_pre() logger.warning(_T("Server Launching")) + WindowLogger.push_log(_T("Server Launching")) if sys.platform == "win32" and not python.exists(): logger.error("%s:", _T("python interpreter not found")) logger.error(" ↳%s:", _T("Ensure that the python_embeded located in the same level as ComfyUI dir")) @@ -646,6 +663,14 @@ def run(self) -> bool: logger.error(" │ ├─ python.exe") logger.error(" │ └─ ...") logger.error(" └─ ...") + WindowLogger.push_log("%s:", _T("python interpreter not found")) + WindowLogger.push_log(" ↳%s:", _T("Ensure that the python_embeded located in the same level as ComfyUI dir")) + WindowLogger.push_log(" SomeDirectory") + WindowLogger.push_log(" ├─ ComfyUI") + WindowLogger.push_log(" ├─ python_embeded") + WindowLogger.push_log(" │ ├─ python.exe") + WindowLogger.push_log(" │ └─ ...") + WindowLogger.push_log(" └─ ...") return # custom_nodes @@ -961,10 +986,12 @@ def init_server(fake=False, callback=lambda: ...): running = TaskManager.server.run() if not TaskManager.server.exited() and running: logger.warning(_T("Server Launched")) + WindowLogger.push_log(_T("Server Launched")) TaskManager.start_polling() callback() else: logger.error(_T("Server Launch Failed")) + WindowLogger.push_log(_T("Server Launch Failed")) TaskManager.server.close() return running @@ -992,10 +1019,14 @@ def close_server(): @staticmethod def push_task(task, pre=None, post=None, tree=None): logger.debug(_T('Add Task')) + WindowLogger.push_log(_T('Add Task')) if not TaskManager.is_launched(): TaskManager.put_error_msg(_T("Server Not Launched, Add Task Failed")) + WindowLogger.push_log(_T("Server Not Launched, Add Task Failed")) TaskManager.put_error_msg(_T("Please Check ComfyUI Directory")) + WindowLogger.push_log(_T("Please Check ComfyUI Directory")) logger.error(_T("Server Not Launched")) + WindowLogger.push_log(_T("Server Not Launched")) return TaskManager.task_queue.put(Task(task, pre=pre, post=post, tree=tree)) @@ -1055,6 +1086,7 @@ def poll_task(): task = TaskManager.task_queue.get() TaskManager.progress = {'value': 0, 'max': 1} logger.debug(_T("Submit Task")) + WindowLogger.push_log(_T("Submit Task")) TaskManager.cur_task = task try: TaskManager.submit(task) @@ -1088,6 +1120,7 @@ def submit(task: Task): def queue_task(task: dict): res = TaskManager.query_server_task() logger.debug("P/R: %s/%s", len(res["queue_pending"]), len(res["queue_running"])) + WindowLogger.push_log("P/R: %s/%s", len(res["queue_pending"]), len(res["queue_running"])) api = task.get("api") if api == "prompt": @@ -1220,16 +1253,23 @@ def on_message(ws, message): n = data.get("node", "") if n: logger.debug("%s: %s", _T("Executing Node"), n) + WindowLogger.push_log("%s: %s", _T("Executing Node"), n) elif mtype == "execution_start": ... elif mtype == "execution_cached": logger.debug("%s: %s", _T("Execution Cached"), data.get("nodes", "")) - elif mtype == "status": + WindowLogger.push_log("%s: %s", _T("Execution Cached"), data.get("nodes", "")) + elif mtype == "executed": + ... + elif mtype == "execution_success": ... elif mtype == "execution_error": ... + elif mtype == "status": + ... elif mtype != "progress": logger.debug("%s: %s", _T("Message Type"), mtype) + WindowLogger.push_log("%s: %s", _T("Message Type"), mtype) Timer.put(update_screen) @@ -1273,6 +1313,7 @@ def on_message(ws, message): TaskManager.progress_bar = 0 tm.push_res(data) logger.warning("%s: %s", _T("Ran Node"), data["node"]) + WindowLogger.push_log("%s: %s", _T("Ran Node"), data["node"]) elif mtype == "execution_error": _msg = data.get("message", None) if not _msg: @@ -1298,6 +1339,7 @@ def on_message(ws, message): ... elif mtype == "execution_success": logger.warning("%s: %s", _T("Execute Node Success"), data["node"]) + WindowLogger.push_log("%s: %s", _T("Execute Node Success"), data["node"]) elif mtype == "execution_interrupted": {"type": "execution_interrupted", "data": {"prompt_id": "e1f3cbf9-4b83-47cf-95c3-9f9a76ab5508", @@ -1331,6 +1373,7 @@ def on_message(ws, message): except ConnectionClosedError: ... logger.debug(_T("Poll Result Thread Exit")) + # WindowLogger.push_log(_T("Poll Result Thread Exit")) # 可能是blender退出, 会导致crash TaskManager.ws = None if TaskManager.server.is_launched(): Timer.put((TaskManager.restart_server, True)) diff --git a/SDNode/nodes.py b/SDNode/nodes.py index 78fe74a..797865b 100644 --- a/SDNode/nodes.py +++ b/SDNode/nodes.py @@ -147,6 +147,8 @@ def get_icon_path(nname): PREVICONPATH[class_type] = path_list for name, mpath in pathmap.items(): reg_name = get_reg_name(name) + if mpath not in d: + continue path_list[reg_name] = d[mpath][0] return PREVICONPATH.get(nname, {}) @@ -250,6 +252,9 @@ def wrap(self, context): if icon_id: ENUM_ITEMS_CACHE[nname][inp_name] = items si = str(item) + if si in spec_trans: + items.append((si, spec_trans.get(si, si), "")) + continue items.append((si, spec_trans.get(si, si), "", icon_id, len(items))) return items return wrap @@ -294,7 +299,7 @@ def FLOAT(nname, inp_name, reg_name, inp): {'default': 8.0, 'min': 0.0, 'max': 100.0} if len(inp) > 1: if "step" in inp[1]: - inp[1]["step"] *= 100 + inp[1]["step"] = min(inp[1]["step"] * 100, 100) if inp[1].pop("display", False): inp[1]["subtype"] = "FACTOR" default = inp[1].pop("default", 0) diff --git a/SDNode/operators.py b/SDNode/operators.py new file mode 100644 index 0000000..23efd6a --- /dev/null +++ b/SDNode/operators.py @@ -0,0 +1,692 @@ +import bpy +import tempfile +import json +import time +from hashlib import md5 +from pathlib import Path + +from bpy.types import Context, Event +from .tree import CFNodeTree, TREE_TYPE +from ..translations import ctxt +from ..utils import Timer, _T, get_ai_mat_tree, set_ai_mat_tree + + +class AIMatSolutionLoad(bpy.types.Operator): + bl_idname = "sdn.ai_mat_sol_load" + bl_label = "AI Mat Solution Load" + bl_description = "Load AI Mat Solution" + bl_translation_context = ctxt + bl_options = {"REGISTER", "UNDO"} + + @classmethod + def poll(cls, context: bpy.types.Context): + return context.object and context.object.type == 'MESH' + + def get_resolution(self): + size = bpy.context.scene.sdn.ai_mat_tex_size + return size, size + + def draw(self, context): + layout = self.layout + if "AI_Mat_Gen_Ori" in bpy.context.object: + layout.label(text="AI Mat already exists, Overwrite?") + + def invoke(self, context: Context, event: Event): + if "AI_Mat_Gen_Ori" in bpy.context.object: + wm = context.window_manager + return wm.invoke_props_dialog(self, width=200) + return self.execute(context) + + def execute(self, context: bpy.types.Context): + workflow = self.read_workflow() + ob = self.prepare_ob() + self.prepare_scene() + cam = self.prepare_cam(ob) + maps = { + "COLOR": "", + "DEPTH": "", + "NORMAL": "", + } + bpy.ops.object.select_all(action='DESELECT') + bpy.context.view_layer.objects.active = ob + ob.select_set(True) + for map_type in maps: + if f"{{{map_type}}}" not in workflow and f"({map_type})" not in workflow: + continue + obj_name = bpy.path.clean_name(ob.name) + obj_name += md5(ob.name.encode()).hexdigest()[:5] + result = self.render_map(ob, f"_gen_{obj_name}_{map_type}.png", map_type) + if not result: + continue + maps[map_type] = result + if bpy.context.scene.sdn.clear_material_slots: + ob.data.materials.clear() + self.project_uv(ob) + self.remove_cam(cam) + self.prepare_combine(ob) + mat = self.prepare_project_mat(ob) + # read workflow + # workflow = workflow.replace("{prompt}", "Stainless steel chest armor") + # for map_type in maps: + # if not maps[map_type]: + # continue + # workflow = workflow.replace(f"{{{map_type}}}", maps[map_type]) + workflow = workflow.replace("\"{w}\"", str(self.get_resolution()[0])) + workflow = workflow.replace("\"{h}\"", str(self.get_resolution()[1])) + workflow = json.loads(workflow) + node_tree = self.get_sdn_tree() + node_tree.load_json(workflow) + node_tree.name += "_" + ob.name + # replace edit_tree + for area in bpy.context.screen.areas: + for space in area.spaces: + if space.type != "NODE_EDITOR" or space.tree_type != TREE_TYPE: + continue + space.node_tree = node_tree + + def prepare(ob: bpy.types.Object, node_tree: CFNodeTree): + # 替换图片 + for node in node_tree.nodes: + if not node.label: + continue + if node.label[1:-1] in maps: + node.image = maps[node.label[1:-1]] + node.mode = "输入" + + def find_tex_recursive(tree: bpy.types.ShaderNodeTree, label: str = "") -> bpy.types.ShaderNodeTexImage: + """ + 递归查找带有label的Tex节点, 如果没有则返回第一个tex节点, 如果都没有则返回None + """ + if not tree: + return None + tex = None # 普通tex节点 + tex_recursive = None # 递归查找结果 + tex_label = None # 带标签的tex节点 + for node in tree.nodes: + if node.type == "TEX_IMAGE": + tex = node + if node.label == label: + tex_label = node + if node.type == "GROUP": + tex_recursive = tex_recursive or find_tex_recursive(node.node_tree, label) + return tex_label or tex_recursive or tex + tex_node = find_tex_recursive(mat.node_tree, "GenTex") + if "ToMatImage" in node_tree.nodes: + to_mat_img_node = node_tree.nodes["ToMatImage"] + to_mat_img_node.mode = "ToImage" + to_mat_img_node.image = tex_node.image if tex_node else None + if tex_node: + bpy.context.object["AI_Mat_Gen_Tex"] = tex_node.image + for node in node_tree.nodes: + if hasattr(node, "exe_rand"): + node.exe_rand = True + + Timer.put((prepare, ob, node_tree)) + set_ai_mat_tree(bpy.context.object, node_tree) + return {"FINISHED"} + + def get_solution_path(self): + return Path(bpy.context.scene.sdn.ai_gen_solution) + + def read_workflow(self): + wk_path = self.get_solution_path().with_suffix(".json") + if not wk_path.exists(): + wk_path = wk_path.parent.joinpath("_default.json") + with open(wk_path) as f: + return f.read() + return "{}" + + def get_sdn_tree(self) -> CFNodeTree: + return bpy.data.node_groups.new(name="AI_Mat_Gen", type=TREE_TYPE) + + def prepare_ob(self): + if bpy.context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") + ori_ob = bpy.context.object + if "AI_Mat_Gen_Ori" in ori_ob: + bpy.ops.object.convert(target="MESH") + ob = ori_ob + else: + for user_col in ori_ob.users_collection[:]: + user_col.objects.unlink(ori_ob) + if _T("Backups") not in bpy.data.collections: + _col = bpy.data.collections.new(name=_T("Backups")) + bpy.context.scene.collection.children.link(_col) + _col.hide_render = True + _col.hide_viewport = True + back_col = bpy.data.collections.get(_T("Backups")) + back_col.objects.link(ori_ob) + old_name = ori_ob.name + ob = ori_ob.copy() + ob.data = ob.data.copy() + ob["AI_Mat_Gen_Ori"] = ori_ob + bpy.ops.object.select_all(action='DESELECT') + bpy.context.scene.collection.objects.link(ob) + bpy.context.view_layer.objects.active = ob + ob.name = old_name + "_Copy" + ob.select_set(state=True) + bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) + + if "Stack" not in bpy.data.node_groups: + gn_path = self.get_solution_path().as_posix() + with bpy.data.libraries.load(gn_path) as (df, dt): + dt.node_groups = ["Stack"] + ng = bpy.data.node_groups.get("Stack") + mod = ob.modifiers.new(name='.Stack', type='NODES') + mod.node_group = ng + return ob + + def prepare_scene(self) -> bpy.types.Scene: + scene = bpy.context.scene + scene.cycles.samples = 16 + scene.render.film_transparent = True + scene.render.resolution_x = self.get_resolution()[0] + scene.render.resolution_y = self.get_resolution()[1] + scene.use_nodes = True + return scene + + def prepare_mat_norm(self, obj: bpy.types.Object): + if "Normal" not in bpy.data.materials: + gn_path = self.get_solution_path().as_posix() + with bpy.data.libraries.load(gn_path) as (df, dt): + dt.materials = ["Normal"] + obj.active_material = bpy.data.materials["Normal"] + return obj.active_material + + def prepare_mat_internal(self, obj: bpy.types.Object): + if bpy.context.scene.sdn.clear_material_slots: + obj.data.materials.clear() + return obj.active_material + + def prepare_cam(self, obj: bpy.types.Object): + from mathutils import Vector + import numpy as np + + bpy.ops.object.camera_add() + cam = bpy.context.object + cam.name = "MapRenderCam" + """ + 1 -- 5 + | | + 0 -- 4 + """ + sce = bpy.context.scene + sce.camera = cam + eobj = obj.evaluated_get(bpy.context.view_layer.depsgraph) + + points = np.array([Vector(corner) for corner in eobj.bound_box]) + center = Vector(points.mean(axis=0)) + size = max(points.max(axis=0) - points.min(axis=0)) * 1.5 + cam.location = center + Vector((0, -size, 0)) + cam.data.type = 'ORTHO' + cam.data.ortho_scale = size + cam.rotation_euler = 1.570796, 0, 0 + bpy.context.view_layer.objects.active = obj + obj.select_set(state=True) + bpy.ops.view3d.camera_to_view_selected() + cam.location.xz = max(cam.location.xz), max(cam.location.xz) + return cam + + def prepare_compositor_for_depth(self): + bpy.context.scene.use_nodes = True + tree = bpy.context.scene.node_tree + nodes = tree.nodes + nodes.clear() + # Add required nodes + render_layers_node = nodes.new(type='CompositorNodeRLayers') + render_layers_node.location = (0, 0) + normalize_node = nodes.new(type='CompositorNodeNormalize') + normalize_node.location = (200, 0) + alpha_math_node = nodes.new(type='CompositorNodeMath') + alpha_math_node.location = (400, 0) + alpha_math_node.operation = 'SUBTRACT' + composite_node = nodes.new(type='CompositorNodeComposite') + composite_node.location = (600, 0) + # Link nodes + tree.links.new(render_layers_node.outputs['Depth'], normalize_node.inputs[0]) + tree.links.new(normalize_node.outputs[0], alpha_math_node.inputs[1]) # Connect Depth output to input 1 of SUBTRACT node + tree.links.new(render_layers_node.outputs['Alpha'], alpha_math_node.inputs[0]) # Connect Alpha output to input 0 of SUBTRACT node + tree.links.new(alpha_math_node.outputs[0], composite_node.inputs[0]) # Connect the output of the SUBTRACT node to the Composite node + + def create_img_node(self, name, res, mat: bpy.types.Material): + img: bpy.types.Image = bpy.data.images.new(name=name, + width=res[0], + height=res[1], + alpha=True) + img_node = mat.node_tree.nodes.new("ShaderNodeTexImage") + img_node.image = img + img_node.select = True + mat.node_tree.nodes.active = img_node + return img_node + + def render_map(self, ob: bpy.types.Object, name, map_type): + if map_type == "DEPTH": + return self.render_depth(ob, name) + if map_type == "NORMAL": + return self.render_normal(ob, name) + if map_type == "COLOR": + return self.render_color(ob, name) + return "" + + def render_depth_1(self, ob: bpy.types.Object, name: str): + tempdir = tempfile.gettempdir() + final_path = Path(tempdir, name) + final_path.unlink(missing_ok=True) + self.prepare_compositor_for_depth() + bpy.context.scene.render.filepath = final_path.as_posix() + bpy.ops.render.render(write_still=True) + return final_path.as_posix() + + def render_depth(self, ob: bpy.types.Object, name: str): + tempdir = tempfile.gettempdir() + final_path = Path(tempdir, name) + final_path.unlink(missing_ok=True) + sce = bpy.context.scene.copy() + view_layer = sce.view_layers.new("_AI_Mat_View_Layer_Temp") + view_layer.use_pass_z = True + # 记录渲染状态, 随后恢复 + obj_render_status: dict[bpy.types.Object, bool] = {} + for obj in bpy.context.scene.objects: + if obj == ob: + continue + if obj.type in {"LIGHT", "CAMERA", "LIGHT_PROBE"}: + continue + obj_render_status[obj] = obj.hide_render + obj.hide_render = True + sce.use_nodes = True + # ----------准备渲染合成---------- + tree = sce.node_tree + nodes = tree.nodes + nodes.clear() + # 创建合成器节点 + render_layers_node = nodes.new(type='CompositorNodeRLayers') + render_layers_node.location = (0, 0) + render_layers_node.scene = sce + render_layers_node.layer = view_layer.name + composite_node = nodes.new(type='CompositorNodeComposite') + composite_node.location = (600, 0) + alpha_math_node = nodes.new(type='CompositorNodeMath') + alpha_math_node.location = (400, 0) + alpha_math_node.operation = 'SUBTRACT' + normalize_node = nodes.new(type='CompositorNodeNormalize') + normalize_node.location = (200, 0) + # 链接节点 + tree.links.new(render_layers_node.outputs["Depth"], normalize_node.inputs[0]) + tree.links.new(normalize_node.outputs[0], alpha_math_node.inputs[1]) + tree.links.new(alpha_math_node.outputs[0], composite_node.inputs[0]) + tree.links.new(render_layers_node.outputs['Alpha'], alpha_math_node.inputs[0]) + # 设置渲染参数 + sce.render.engine = "CYCLES" + sce.render.image_settings.file_format = "PNG" + sce.render.image_settings.color_mode = "RGB" + sce.render.image_settings.color_depth = "8" + sce.display_settings.display_device = "sRGB" + sce.view_settings.view_transform = "Standard" + sce.cycles.samples = 16 + sce.render.filepath = final_path.as_posix() + sce.world = None + bpy.ops.render.render(scene=sce.name, layer=view_layer.name, write_still=True) + sce.view_layers.remove(view_layer) + bpy.data.scenes.remove(sce) + # 恢复渲染状态 + for obj, status in obj_render_status.items(): + obj.hide_render = status + return final_path.as_posix() + + def render_normal(self, ob: bpy.types.Object, name: str): + self.prepare_mat_norm(ob) + bpy.context.scene.use_nodes = False + tempdir = tempfile.gettempdir() + final_path = Path(tempdir, name) + final_path.unlink(missing_ok=True) + sce = bpy.context.scene.copy() + view_layer = sce.view_layers.new("_AI_Mat_View_Layer_Temp") + view_layer.use_pass_normal = True + # 记录渲染状态, 随后恢复 + obj_render_status: dict[bpy.types.Object, bool] = {} + for obj in bpy.context.scene.objects: + if obj == ob: + continue + if obj.type in {"LIGHT", "CAMERA", "LIGHT_PROBE"}: + continue + obj_render_status[obj] = obj.hide_render + obj.hide_render = True + + # 准备场景设置 + sce.render.engine = 'CYCLES' + sce.render.image_settings.file_format = 'PNG' + sce.render.image_settings.color_mode = 'RGB' + sce.render.image_settings.color_depth = '8' + sce.display_settings.display_device = 'sRGB' + sce.view_settings.view_transform = 'Standard' + sce.cycles.samples = 16 + sce.render.filepath = final_path.as_posix() + world = bpy.data.worlds.new("._") + sce.world = world + world.use_nodes = True + for node in filter(lambda n: n.type == "BACKGROUND", world.node_tree.nodes): + node.inputs[0].default_value = (0.5, 0.5, 1.0, 1.0) + + bpy.ops.render.render(scene=sce.name, layer=view_layer.name, write_still=True) + sce.view_layers.remove(view_layer) + bpy.data.scenes.remove(sce) + bpy.data.worlds.remove(world) + # 恢复渲染状态 + for obj, status in obj_render_status.items(): + obj.hide_render = status + return final_path.as_posix() + + def render_color(self, ob: bpy.types.Object, name: str): + tempdir = tempfile.gettempdir() + final_path = Path(tempdir, name) + final_path.unlink(missing_ok=True) + + sce = bpy.context.scene.copy() + # 记录渲染状态, 随后恢复 + obj_render_status: dict[bpy.types.Object, bool] = {} + for obj in bpy.context.scene.objects: + if obj == ob: + continue + if obj.type in {"LIGHT", "CAMERA", "LIGHT_PROBE"}: + continue + obj_render_status[obj] = obj.hide_render + obj.hide_render = True + + sce.render.engine = "CYCLES" + sce.render.image_settings.file_format = "PNG" + sce.render.image_settings.color_mode = "RGB" + sce.render.image_settings.color_depth = "8" + sce.display_settings.display_device = "sRGB" + sce.view_settings.view_transform = "Standard" + sce.cycles.samples = 16 + sce.render.filepath = final_path.as_posix() + bpy.ops.render.render(scene=sce.name, write_still=True) + bpy.data.scenes.remove(sce) + + # 恢复渲染状态 + for obj, status in obj_render_status.items(): + obj.hide_render = status + return final_path.as_posix() + + def project_uv(self, ob: bpy.types.Object): + # UV投射 + uv_layer_name = "Projected_UV" + if uv_layer_name not in ob.data.uv_layers: + ob.data.uv_layers.new(name=uv_layer_name) + if ".Stack" in ob.modifiers: + mod = ob.modifiers[".Stack"] + mod.show_on_cage = False + mod.show_in_editmode = False + mod.show_viewport = False + mod.show_render = False + # 投射修改器 + mod = ob.modifiers.new(name=".UV_PROJECT", type='UV_PROJECT') + mod.uv_layer = uv_layer_name + mod.aspect_x = bpy.context.scene.render.resolution_x + mod.aspect_y = bpy.context.scene.render.resolution_y + mod.projectors[0].object = bpy.context.scene.camera + bpy.ops.object.modifier_apply(modifier=mod.name) + + def remove_cam(self, cam: bpy.types.Object): + cam_data = cam.data + bpy.data.objects.remove(cam) + bpy.data.cameras.remove(cam_data) + + def prepare_combine(self, ob: bpy.types.Object): + if "Project" not in bpy.data.node_groups: + gn_path = self.get_solution_path().as_posix() + with bpy.data.libraries.load(gn_path) as (df, dt): + dt.node_groups = ["Project"] + ng = bpy.data.node_groups.get("Project") + mod = ob.modifiers.new(name=".Project", type='NODES', ) + mod.node_group = ng + + def prepare_project_mat(self, ob: bpy.types.Object) -> bpy.types.Material: + """ + 每次生成新的材质 + """ + gn_path = self.get_solution_path().as_posix() + old_mats = set(ob.data.materials) + with bpy.data.libraries.load(gn_path) as (df, dt): + dt.materials = ["Project"] + new_mats = list(set(bpy.data.materials) - old_mats) + for new_mat in new_mats: + if new_mat.name == "Project": + new_mat.name += "_" + ob.name + ob.active_material = new_mat + break + return new_mat + + +class AIMatSolutionRun(bpy.types.Operator): + bl_idname = "sdn.ai_mat_sol_run" + bl_label = "Run AI Mat Solution" + bl_description = "Use depth and normal map to Gen Mesh Mat" + bl_translation_context = ctxt + bl_options = {"REGISTER", "UNDO"} + + @classmethod + def poll(cls, context): + return get_ai_mat_tree(context.object) + + def execute(self, context): + tree: CFNodeTree = get_ai_mat_tree(context.object) + if not tree: + self.report({"ERROR"}, "Can't find ComfyUI Node Tree") + return {"CANCELLED"} + tree.execute() + return {"FINISHED"} + + +class AIMatSolutionSave(bpy.types.Operator): + bl_idname = "sdn.ai_mat_sol_save" + bl_label = "Save AI Mat Solution" + bl_translation_context = ctxt + + name: bpy.props.StringProperty(name="Name", default="Solution") + + @classmethod + def poll(cls, context): + return context.object and context.object.type == "MESH" + + def invoke(self, context: Context, event: Event): + wm = context.window_manager + return wm.invoke_props_dialog(self, width=200) + + def execute(self, context: Context): + if not bpy.context.object.active_material: + self.report({"ERROR"}, "No active material") + return {"CANCELLED"} + # 只需要添加 工作流 和 最终渲染材质(需要借助几何属性) + # 几何节点: Stack + Project + # 材质: Normal + Depth + Project + find_tree: CFNodeTree = None + for area in bpy.context.screen.areas: + for space in area.spaces: + if space.type != "NODE_EDITOR" or space.tree_type != TREE_TYPE: + continue + find_tree = space.node_tree + break + if not find_tree: + self.report({"ERROR"}, "Can't find CFNodeTree") + return {"CANCELLED"} + try: + workflow = find_tree.save_json() + except Exception as e: + self.report({"ERROR"}, str(e.args)) + return {"FINISHED"} + # 老版本 + ori_stack_ng = bpy.data.node_groups.get("Stack") + ori_proj_ng = bpy.data.node_groups.get("Project") + ori_norm_mtl = bpy.data.materials.get("Normal") + ori_proj_mtl = bpy.data.materials.get("Project") + if ori_stack_ng: + ori_stack_ng.name = "." + ori_stack_ng.name + if ori_proj_ng: + ori_proj_ng.name = "." + ori_proj_ng.name + if ori_norm_mtl: + ori_norm_mtl.name = "." + ori_norm_mtl.name + if ori_proj_mtl: + ori_proj_mtl.name = "." + ori_proj_mtl.name + # 提前准备 Stack Project 几何节点 和 Normal 材质 + gn_path = self.get_solution_path().parent.joinpath("00-Default.blend") + with bpy.data.libraries.load(gn_path.as_posix()) as (df, dt): + dt.node_groups = ["Stack", "Project"] + dt.materials = ["Normal"] + wk_data = json.dumps(workflow, ensure_ascii=False, indent=4) + save_path = self.get_save_path() + stack_ng = bpy.data.node_groups.get("Stack") + proj_ng = bpy.data.node_groups.get("Project") + norm_mtl = bpy.data.materials.get("Normal") + proj_mtl = bpy.context.object.active_material.copy() # 目的材质 + proj_mtl.name = "Project" + save_data = {stack_ng, proj_ng, norm_mtl, proj_mtl} + # 存储 blend 和 json + bpy.data.libraries.write(save_path.with_suffix(".blend").as_posix(), save_data) + save_path.write_text(wk_data) + bpy.data.node_groups.remove(stack_ng) + bpy.data.node_groups.remove(proj_ng) + bpy.data.materials.remove(norm_mtl) + bpy.data.materials.remove(proj_mtl) + # 恢复老版本名称 + if ori_stack_ng: + ori_stack_ng.name = ori_stack_ng.name[1:] + if ori_proj_ng: + ori_proj_ng.name = ori_proj_ng.name[1:] + if ori_norm_mtl: + ori_norm_mtl.name = ori_norm_mtl.name[1:] + if ori_proj_mtl: + ori_proj_mtl.name = ori_proj_mtl.name[1:] + return {"FINISHED"} + + def draw(self, context: Context): + layout = self.layout + col = layout.column() + save_path = self.get_save_path() + col.alert = save_path.exists() + col.prop(self, "name") + if col.alert: + layout.label(text="AI Mat already exists, Overwrite?", icon="ERROR") + else: + layout.label(text="") + + def get_solution_path(self): + return Path(bpy.context.scene.sdn.ai_gen_solution) + + def get_save_path(self) -> Path: + return self.get_solution_path().parent / (self.name + ".json") + + +class AIMatSolutionDel(bpy.types.Operator): + bl_idname = "sdn.ai_mat_sol_del" + bl_label = "Delete AI Mat Solution" + bl_translation_context = ctxt + + def execute(self, context: Context): + res_path = self.get_solution_path() + res_path.unlink(missing_ok=True) + res_path.with_suffix(".blend").unlink(missing_ok=True) + return {"FINISHED"} + + def get_solution_path(self): + return Path(bpy.context.scene.sdn.ai_gen_solution) + + +class AIMatSolutionApply(bpy.types.Operator): + bl_idname = "sdn.ai_mat_sol_apply" + bl_label = "Apply" + bl_translation_context = ctxt + + @classmethod + def poll(cls, context): + return get_ai_mat_tree(context.object) + + def execute(self, context: Context): + if context.object.get("AI_Mat_Gen_Applied", None): + self.report({"ERROR"}, "Already applied") + return {"FINISHED"} + try: + # 新逻辑: + # 1. 新建 BakeNodeTree 节点树 + self.tree = bpy.data.node_groups.new("AI_Mat_Gen_Bake_Tree_Temp", "BakeNodeTree") + self.tree.is_running = True + self.tree.initialize_ai() + + self.obj: bpy.types.Object = context.object + self.ori: bpy.types.Object = self.obj.get("AI_Mat_Gen_Ori") + + self.tree.nodes["Mesh_Copy"].mesh_configs[0].target = self.obj + self.tree.nodes["Pass"].bake_passes = {bpy.context.scene.sdn.apply_bake_pass, } + self.tree.execute() + self.obj["AI_Mat_Gen_Applied"] = True + context.window_manager.modal_handler_add(self) + + # 2. 将新建的节点树中的 网格设置为当前的 Copy物体 + # 4. 执行 烘焙节点树 + # 5. 执行完成后删除Copy物体, 将原物体恢复 + return {"RUNNING_MODAL"} + except Exception: + import traceback + traceback.print_exc() + # 旧逻辑 + bpy.ops.object.convert(target="MESH") + return {"FINISHED"} + + def modal(self, context: Context, event: bpy.types.Event): + if self.tree.is_running: + return {"PASS_THROUGH"} + # tree 运行结束, 删除 Copy物体, 恢复原物体 + od = self.obj.data + bpy.data.objects.remove(self.obj) + bpy.data.meshes.remove(od) + for col in self.ori.users_collection: + col.objects.unlink(self.ori) + bpy.context.scene.collection.objects.link(self.ori) + bpy.data.node_groups.remove(self.tree) + self.ori.select_set(True) + bpy.context.view_layer.objects.active = self.ori + mod = self.ori.modifiers.get(f"AI_Tex_Preview_Mod_{self.ori.name}", None) + if not mod: + return {"FINISHED"} + # self.ori.data.materials.clear() + # # 将该修改器应用 + # with bpy.context.temp_override(object=self.ori): + # bpy.ops.object.modifier_apply(modifier=mod.name) + return {"FINISHED"} + + +class AIMatSolutionRestore(bpy.types.Operator): + bl_idname = "sdn.ai_mat_sol_restore" + bl_label = "Restore" + bl_translation_context = ctxt + + @classmethod + def poll(cls, context): + return context.object and "AI_Mat_Gen_Ori" in context.object + + def execute(self, context: Context): + """ + 还原: 将Copy物体删除, 将原物体恢复 + """ + ori: bpy.types.Object = context.object.get("AI_Mat_Gen_Ori") + if not ori: + return {"CANCELLED"} + od = context.object.data + bpy.data.objects.remove(context.object) + bpy.data.meshes.remove(od) + for col in ori.users_collection: + col.objects.unlink(ori) + bpy.context.scene.collection.objects.link(ori) + return {"FINISHED"} + + +clss = ( + AIMatSolutionLoad, + AIMatSolutionRun, + AIMatSolutionSave, + AIMatSolutionDel, + AIMatSolutionApply, + AIMatSolutionRestore, +) + +ops_register, ops_unregister = bpy.utils.register_classes_factory(clss) diff --git a/SDNode/resource/icons/none.png b/SDNode/resource/icons/none.png new file mode 100644 index 0000000..0a40325 Binary files /dev/null and b/SDNode/resource/icons/none.png differ diff --git a/SDNode/resource/solutions/CN/00-Default.blend b/SDNode/resource/solutions/CN/00-Default.blend new file mode 100644 index 0000000..dcc712b Binary files /dev/null and b/SDNode/resource/solutions/CN/00-Default.blend differ diff --git a/SDNode/resource/solutions/CN/00-Default.jpg b/SDNode/resource/solutions/CN/00-Default.jpg new file mode 100644 index 0000000..3a7bd3a Binary files /dev/null and b/SDNode/resource/solutions/CN/00-Default.jpg differ diff --git a/SDNode/resource/solutions/CN/00-Default.json b/SDNode/resource/solutions/CN/00-Default.json new file mode 100644 index 0000000..1c44e47 --- /dev/null +++ b/SDNode/resource/solutions/CN/00-Default.json @@ -0,0 +1,763 @@ +{ + "last_node_id": 19, + "last_link_id": 16, + "nodes": [ + { + "id": 10, + "type": "VAELoader", + "pos": [ + 853, + 983 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "VAE", + "type": "VAE", + "links": [ + 7 + ], + "slot_index": 0 + } + ], + "title": "VAE加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "pastel-waifu-diffusion.vae.pt" + ] + }, + { + "id": 12, + "type": "输入图像", + "pos": [ + -17, + 1501 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 10 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像", + "properties": { + "sdn_hide": false, + "label": "(NORMAL)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_大理石胸像01_Copyac241_NORMAL.png", + "输入" + ] + }, + { + "id": 13, + "type": "ControlNetLoader", + "pos": [ + -2, + 1281 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 8 + ], + "slot_index": 0 + } + ], + "title": "ControlNet加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_normalbae.pth" + ] + }, + { + "id": 14, + "type": "ControlNetApply", + "pos": [ + 389, + 1138 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 15, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 8, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 10, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 14 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 16, + "type": "存储", + "pos": [ + 1476, + 402 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 14, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 9, + "label": "images" + } + ], + "outputs": [], + "title": "ToMatImage", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "ComfyUI", + "" + ] + }, + { + "id": 17, + "type": "ControlNetApply", + "pos": [ + 6, + 1105 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 11, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 12, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 13, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 15 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 18, + "type": "ControlNetLoader", + "pos": [ + -384, + 1191 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 12 + ], + "slot_index": 0 + } + ], + "title": "ControlNet加载器.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_depth.pth" + ] + }, + { + "id": 19, + "type": "输入图像", + "pos": [ + -443, + 1409 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 13 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像.001", + "properties": { + "sdn_hide": false, + "label": "(DEPTH)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_大理石胸像01_Copyac241_DEPTH.png", + "输入" + ] + }, + { + "id": 3, + "type": "KSampler", + "pos": [ + 824, + 511 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 11, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 3, + "label": "model" + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": 14, + "label": "positive" + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": 1, + "label": "negative" + }, + { + "name": "latent_image", + "type": "LATENT", + "link": 4, + "label": "latent_image" + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 5 + ], + "slot_index": 0 + } + ], + "title": "K采样器", + "properties": { + "sdn_hide": false, + "label": "003" + }, + "widgets_values": [ + "3888636113", + "fixed", + 20, + 8.0, + "euler", + "karras", + 1.0 + ] + }, + { + "id": 4, + "type": "CheckpointLoaderSimple", + "pos": [ + -698, + 823 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 3 + ], + "slot_index": 0 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [ + 0, + 2 + ], + "slot_index": 1 + }, + { + "name": "VAE", + "type": "VAE", + "links": [], + "slot_index": 2 + } + ], + "title": "Checkpoint简易加载器", + "properties": { + "sdn_hide": false, + "label": "001" + }, + "widgets_values": [ + "GuoFeng3.2_f16.safetensors" + ] + }, + { + "id": 5, + "type": "CLIPTextEncode", + "pos": [ + -459, + 1008 + ], + "size": { + "0": 347, + "1": 30 + }, + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 0, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 11 + ], + "slot_index": 0 + } + ], + "title": "CLIP文本编码器(正)", + "properties": { + "sdn_hide": false, + "label": "002" + }, + "widgets_values": [ + "Model, 8K, Octane rendering, UE5, realistic, glossy, delicate texture, best quality" + ] + }, + { + "id": 6, + "type": "CLIPTextEncode", + "pos": [ + -129, + 764 + ], + "size": { + "0": 306, + "1": 30 + }, + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 2, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 1 + ], + "slot_index": 0 + } + ], + "title": "CLIP文本编码器(反)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "embedding:EasyNegative" + ] + }, + { + "id": 7, + "type": "EmptyLatentImage", + "pos": [ + 389, + 1336 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 4 + ], + "slot_index": 0 + } + ], + "title": "空Latent图像", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1024, + 1024, + 1 + ] + }, + { + "id": 8, + "type": "VAEDecode", + "pos": [ + 1176, + 867 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [ + { + "name": "samples", + "type": "LATENT", + "link": 5, + "label": "samples" + }, + { + "name": "vae", + "type": "VAE", + "link": 7, + "label": "vae" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 6, + 9 + ], + "slot_index": 0 + } + ], + "title": "VAE解码", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 9, + "type": "PreviewImage", + "pos": [ + 1476, + 602 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 6, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + } + ], + "links": [ + [ + 0, + 4, + 1, + 5, + 0, + "CLIP" + ], + [ + 1, + 6, + 0, + 3, + 2, + "CONDITIONING" + ], + [ + 2, + 4, + 1, + 6, + 0, + "CLIP" + ], + [ + 3, + 4, + 0, + 3, + 0, + "MODEL" + ], + [ + 4, + 7, + 0, + 3, + 3, + "LATENT" + ], + [ + 5, + 3, + 0, + 8, + 0, + "LATENT" + ], + [ + 6, + 8, + 0, + 9, + 0, + "IMAGE" + ], + [ + 7, + 10, + 0, + 8, + 1, + "VAE" + ], + [ + 8, + 13, + 0, + 14, + 1, + "CONTROL_NET" + ], + [ + 9, + 8, + 0, + 16, + 0, + "IMAGE" + ], + [ + 10, + 12, + 0, + 14, + 2, + "IMAGE" + ], + [ + 11, + 5, + 0, + 17, + 0, + "CONDITIONING" + ], + [ + 12, + 18, + 0, + 17, + 1, + "CONTROL_NET" + ], + [ + 13, + 19, + 0, + 17, + 2, + "IMAGE" + ], + [ + 14, + 14, + 0, + 3, + 1, + "CONDITIONING" + ], + [ + 15, + 17, + 0, + 14, + 0, + "CONDITIONING" + ] + ], + "groups": [], + "config": {}, + "extra": { + "groupNodes": {} + }, + "version": 0.4 +} \ No newline at end of file diff --git a/SDNode/resource/solutions/CN/_default.json b/SDNode/resource/solutions/CN/_default.json new file mode 100644 index 0000000..8f3f706 --- /dev/null +++ b/SDNode/resource/solutions/CN/_default.json @@ -0,0 +1,763 @@ +{ + "last_node_id": 19, + "last_link_id": 16, + "nodes": [ + { + "id": 10, + "type": "VAELoader", + "pos": [ + 817, + 1253 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "VAE", + "type": "VAE", + "links": [ + 7 + ], + "slot_index": 0 + } + ], + "title": "VAE加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "pastel-waifu-diffusion.vae.pt" + ] + }, + { + "id": 12, + "type": "输入图像", + "pos": [ + -17, + 1501 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 11 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像", + "properties": { + "sdn_hide": false, + "label": "(NORMAL)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_大理石胸像01_Copyac241_NORMAL.png", + "输入" + ] + }, + { + "id": 13, + "type": "ControlNetLoader", + "pos": [ + -2, + 1281 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 8 + ], + "slot_index": 0 + } + ], + "title": "ControlNet加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_normalbae.pth" + ] + }, + { + "id": 14, + "type": "ControlNetApply", + "pos": [ + 389, + 1138 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 12, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 8, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 11, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 9 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 16, + "type": "存储", + "pos": [ + 1476, + 402 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 14, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 10, + "label": "images" + } + ], + "outputs": [], + "title": "ToMatImage", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "ComfyUI", + "" + ] + }, + { + "id": 17, + "type": "ControlNetApply", + "pos": [ + 6, + 1105 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 13, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 14, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 15, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 12 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 18, + "type": "ControlNetLoader", + "pos": [ + -384, + 1191 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 14 + ], + "slot_index": 0 + } + ], + "title": "ControlNet加载器.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_depth.pth" + ] + }, + { + "id": 19, + "type": "输入图像", + "pos": [ + -443, + 1409 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 15 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像.001", + "properties": { + "sdn_hide": false, + "label": "(DEPTH)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_大理石胸像01_Copyac241_DEPTH.png", + "输入" + ] + }, + { + "id": 3, + "type": "KSampler", + "pos": [ + 824, + 511 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 11, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 3, + "label": "model" + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": 9, + "label": "positive" + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": 1, + "label": "negative" + }, + { + "name": "latent_image", + "type": "LATENT", + "link": 4, + "label": "latent_image" + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 5 + ], + "slot_index": 0 + } + ], + "title": "K采样器", + "properties": { + "sdn_hide": false, + "label": "003" + }, + "widgets_values": [ + "2791066226", + "fixed", + 20, + 8.0, + "euler", + "karras", + 1.0 + ] + }, + { + "id": 4, + "type": "CheckpointLoaderSimple", + "pos": [ + -698, + 823 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 3 + ], + "slot_index": 0 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [ + 0, + 2 + ], + "slot_index": 1 + }, + { + "name": "VAE", + "type": "VAE", + "links": [], + "slot_index": 2 + } + ], + "title": "Checkpoint简易加载器", + "properties": { + "sdn_hide": false, + "label": "001" + }, + "widgets_values": [ + "GuoFeng3.2_f16.safetensors" + ] + }, + { + "id": 5, + "type": "CLIPTextEncode", + "pos": [ + -459, + 1008 + ], + "size": { + "0": 347, + "1": 30 + }, + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 0, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 13 + ], + "slot_index": 0 + } + ], + "title": "CLIP文本编码器(正)", + "properties": { + "sdn_hide": false, + "label": "002" + }, + "widgets_values": [ + "Model, Masterpiece, Best Quality, Octane Rendering, UE5 Rendering, Realistic, Film and Television Grade" + ] + }, + { + "id": 6, + "type": "CLIPTextEncode", + "pos": [ + -129, + 764 + ], + "size": { + "0": 306, + "1": 30 + }, + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 2, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 1 + ], + "slot_index": 0 + } + ], + "title": "CLIP文本编码器(反)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "embedding:EasyNegative" + ] + }, + { + "id": 7, + "type": "EmptyLatentImage", + "pos": [ + 389, + 1336 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 4 + ], + "slot_index": 0 + } + ], + "title": "空Latent图像", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1024, + 1024, + 1 + ] + }, + { + "id": 8, + "type": "VAEDecode", + "pos": [ + 1176, + 867 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [ + { + "name": "samples", + "type": "LATENT", + "link": 5, + "label": "samples" + }, + { + "name": "vae", + "type": "VAE", + "link": 7, + "label": "vae" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 6, + 10 + ], + "slot_index": 0 + } + ], + "title": "VAE解码", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 9, + "type": "PreviewImage", + "pos": [ + 1476, + 602 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 6, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + } + ], + "links": [ + [ + 0, + 4, + 1, + 5, + 0, + "CLIP" + ], + [ + 1, + 6, + 0, + 3, + 2, + "CONDITIONING" + ], + [ + 2, + 4, + 1, + 6, + 0, + "CLIP" + ], + [ + 3, + 4, + 0, + 3, + 0, + "MODEL" + ], + [ + 4, + 7, + 0, + 3, + 3, + "LATENT" + ], + [ + 5, + 3, + 0, + 8, + 0, + "LATENT" + ], + [ + 6, + 8, + 0, + 9, + 0, + "IMAGE" + ], + [ + 7, + 10, + 0, + 8, + 1, + "VAE" + ], + [ + 8, + 13, + 0, + 14, + 1, + "CONTROL_NET" + ], + [ + 9, + 14, + 0, + 3, + 1, + "CONDITIONING" + ], + [ + 10, + 8, + 0, + 16, + 0, + "IMAGE" + ], + [ + 11, + 12, + 0, + 14, + 2, + "IMAGE" + ], + [ + 12, + 17, + 0, + 14, + 0, + "CONDITIONING" + ], + [ + 13, + 5, + 0, + 17, + 0, + "CONDITIONING" + ], + [ + 14, + 18, + 0, + 17, + 1, + "CONTROL_NET" + ], + [ + 15, + 19, + 0, + 17, + 2, + "IMAGE" + ] + ], + "groups": [], + "config": {}, + "extra": { + "groupNodes": {} + }, + "version": 0.4 +} \ No newline at end of file diff --git "a/SDNode/resource/solutions/CN/\347\237\263\345\214\226(Canny&Tile).blend" "b/SDNode/resource/solutions/CN/\347\237\263\345\214\226(Canny&Tile).blend" new file mode 100644 index 0000000..dcc712b Binary files /dev/null and "b/SDNode/resource/solutions/CN/\347\237\263\345\214\226(Canny&Tile).blend" differ diff --git "a/SDNode/resource/solutions/CN/\347\237\263\345\214\226(Canny&Tile).jpg" "b/SDNode/resource/solutions/CN/\347\237\263\345\214\226(Canny&Tile).jpg" new file mode 100644 index 0000000..ecd3113 Binary files /dev/null and "b/SDNode/resource/solutions/CN/\347\237\263\345\214\226(Canny&Tile).jpg" differ diff --git "a/SDNode/resource/solutions/CN/\347\237\263\345\214\226(Canny&Tile).json" "b/SDNode/resource/solutions/CN/\347\237\263\345\214\226(Canny&Tile).json" new file mode 100644 index 0000000..70d0238 --- /dev/null +++ "b/SDNode/resource/solutions/CN/\347\237\263\345\214\226(Canny&Tile).json" @@ -0,0 +1,957 @@ +{ + "last_node_id": 22, + "last_link_id": 22, + "nodes": [ + { + "id": 10, + "type": "VAELoader", + "pos": [ + 724, + 1154 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "VAE", + "type": "VAE", + "links": [ + 5, + 18 + ], + "slot_index": 0 + } + ], + "title": "VAE加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "pastel-waifu-diffusion.vae.pt" + ] + }, + { + "id": 11, + "type": "AIO_Preprocessor", + "pos": [ + -485, + 1474 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 12, + "label": "image" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 11, + 15 + ], + "slot_index": 0 + } + ], + "title": "AIO_Preprocessor", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "CannyEdgePreprocessor", + 512 + ] + }, + { + "id": 12, + "type": "AIO_Preprocessor", + "pos": [ + -117, + 1692 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 13, + "label": "image" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 14, + 16 + ], + "slot_index": 0 + } + ], + "title": "AIO_Preprocessor.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "TilePreprocessor", + 1024 + ] + }, + { + "id": 13, + "type": "ControlNetLoader", + "pos": [ + -7, + 1349 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 6 + ], + "slot_index": 0 + } + ], + "title": "ControlNet加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11f1e_sd15_tile.pth" + ] + }, + { + "id": 14, + "type": "ControlNetApply", + "pos": [ + 381, + 1197 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 14, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 8, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 6, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 14, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 19 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 15, + "type": "PreviewImage", + "pos": [ + -509, + 1661 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 11, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 15, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用).001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 16, + "type": "存储", + "pos": [ + 1468, + 461 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 18, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 7, + "label": "images" + } + ], + "outputs": [], + "title": "ToMatImage", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "ComfyUI", + "" + ] + }, + { + "id": 17, + "type": "ControlNetApply", + "pos": [ + -7, + 1164 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 9, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 10, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 11, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 8 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 18, + "type": "ControlNetLoader", + "pos": [ + -482, + 1264 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 10 + ], + "slot_index": 0 + } + ], + "title": "ControlNet加载器.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_canny.pth" + ] + }, + { + "id": 19, + "type": "输入图像", + "pos": [ + -855, + 1464 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 12, + 13, + 17 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像.001", + "properties": { + "sdn_hide": false, + "label": "(COLOR)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_大理石胸像01_Copyac241_COLOR.png", + "输入" + ] + }, + { + "id": 20, + "type": "PreviewImage", + "pos": [ + 149, + 1632 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 16, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用).002", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 22, + "type": "VAEEncode", + "pos": [ + 559, + 1683 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "pixels", + "type": "IMAGE", + "link": 17, + "label": "pixels" + }, + { + "name": "vae", + "type": "VAE", + "link": 18, + "label": "vae" + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [], + "slot_index": 0 + } + ], + "title": "VAE编码", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 3, + "type": "KSampler", + "pos": [ + 816, + 570 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 15, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 2, + "label": "model" + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": 19, + "label": "positive" + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": 20, + "label": "negative" + }, + { + "name": "latent_image", + "type": "LATENT", + "link": 21, + "label": "latent_image" + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 3 + ], + "slot_index": 0 + } + ], + "title": "K采样器", + "properties": { + "sdn_hide": false, + "label": "003" + }, + "widgets_values": [ + "2445975910", + "fixed", + 20, + 8.0, + "euler", + "karras", + 1.0 + ] + }, + { + "id": 4, + "type": "CheckpointLoaderSimple", + "pos": [ + -705, + 882 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 2 + ], + "slot_index": 0 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [ + 0, + 1 + ], + "slot_index": 1 + }, + { + "name": "VAE", + "type": "VAE", + "links": [], + "slot_index": 2 + } + ], + "title": "Checkpoint简易加载器", + "properties": { + "sdn_hide": false, + "label": "001" + }, + "widgets_values": [ + "GuoFeng3.2_f16.safetensors" + ] + }, + { + "id": 5, + "type": "CLIPTextEncode", + "pos": [ + -356, + 610 + ], + "size": { + "0": 347, + "1": 30 + }, + "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 0, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 9 + ], + "slot_index": 0 + } + ], + "title": "CLIP文本编码器(正)", + "properties": { + "sdn_hide": false, + "label": "002" + }, + "widgets_values": [ + "stone" + ] + }, + { + "id": 6, + "type": "CLIPTextEncode", + "pos": [ + 20, + 991 + ], + "size": { + "0": 306, + "1": 30 + }, + "flags": {}, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 1, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 20 + ], + "slot_index": 0 + } + ], + "title": "CLIP文本编码器(反)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "embedding:EasyNegative" + ] + }, + { + "id": 7, + "type": "EmptyLatentImage", + "pos": [ + 381, + 1395 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 21 + ], + "slot_index": 0 + } + ], + "title": "空Latent图像", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1024, + 1024, + 1 + ] + }, + { + "id": 8, + "type": "VAEDecode", + "pos": [ + 1168, + 926 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 16, + "mode": 0, + "inputs": [ + { + "name": "samples", + "type": "LATENT", + "link": 3, + "label": "samples" + }, + { + "name": "vae", + "type": "VAE", + "link": 5, + "label": "vae" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 4, + 7 + ], + "slot_index": 0 + } + ], + "title": "VAE解码", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 9, + "type": "PreviewImage", + "pos": [ + 1468, + 661 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 17, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 4, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + } + ], + "links": [ + [ + 0, + 4, + 1, + 5, + 0, + "CLIP" + ], + [ + 1, + 4, + 1, + 6, + 0, + "CLIP" + ], + [ + 2, + 4, + 0, + 3, + 0, + "MODEL" + ], + [ + 3, + 3, + 0, + 8, + 0, + "LATENT" + ], + [ + 4, + 8, + 0, + 9, + 0, + "IMAGE" + ], + [ + 5, + 10, + 0, + 8, + 1, + "VAE" + ], + [ + 6, + 13, + 0, + 14, + 1, + "CONTROL_NET" + ], + [ + 7, + 8, + 0, + 16, + 0, + "IMAGE" + ], + [ + 8, + 17, + 0, + 14, + 0, + "CONDITIONING" + ], + [ + 9, + 5, + 0, + 17, + 0, + "CONDITIONING" + ], + [ + 10, + 18, + 0, + 17, + 1, + "CONTROL_NET" + ], + [ + 11, + 11, + 0, + 17, + 2, + "IMAGE" + ], + [ + 12, + 19, + 0, + 11, + 0, + "IMAGE" + ], + [ + 13, + 19, + 0, + 12, + 0, + "IMAGE" + ], + [ + 14, + 12, + 0, + 14, + 2, + "IMAGE" + ], + [ + 15, + 11, + 0, + 15, + 0, + "IMAGE" + ], + [ + 16, + 12, + 0, + 20, + 0, + "IMAGE" + ], + [ + 17, + 19, + 0, + 22, + 0, + "IMAGE" + ], + [ + 18, + 10, + 0, + 22, + 1, + "VAE" + ], + [ + 19, + 14, + 0, + 3, + 1, + "CONDITIONING" + ], + [ + 20, + 6, + 0, + 3, + 2, + "CONDITIONING" + ], + [ + 21, + 7, + 0, + 3, + 3, + "LATENT" + ] + ], + "groups": [], + "config": {}, + "extra": { + "groupNodes": {} + }, + "version": 0.4 +} \ No newline at end of file diff --git "a/SDNode/resource/solutions/CN/\350\241\243\346\234\215(\346\267\261\345\272\246&\346\263\225\345\220\221).blend" "b/SDNode/resource/solutions/CN/\350\241\243\346\234\215(\346\267\261\345\272\246&\346\263\225\345\220\221).blend" new file mode 100644 index 0000000..ddaa593 Binary files /dev/null and "b/SDNode/resource/solutions/CN/\350\241\243\346\234\215(\346\267\261\345\272\246&\346\263\225\345\220\221).blend" differ diff --git "a/SDNode/resource/solutions/CN/\350\241\243\346\234\215(\346\267\261\345\272\246&\346\263\225\345\220\221).jpg" "b/SDNode/resource/solutions/CN/\350\241\243\346\234\215(\346\267\261\345\272\246&\346\263\225\345\220\221).jpg" new file mode 100644 index 0000000..00ab124 Binary files /dev/null and "b/SDNode/resource/solutions/CN/\350\241\243\346\234\215(\346\267\261\345\272\246&\346\263\225\345\220\221).jpg" differ diff --git "a/SDNode/resource/solutions/CN/\350\241\243\346\234\215(\346\267\261\345\272\246&\346\263\225\345\220\221).json" "b/SDNode/resource/solutions/CN/\350\241\243\346\234\215(\346\267\261\345\272\246&\346\263\225\345\220\221).json" new file mode 100644 index 0000000..49dc9a8 --- /dev/null +++ "b/SDNode/resource/solutions/CN/\350\241\243\346\234\215(\346\267\261\345\272\246&\346\263\225\345\220\221).json" @@ -0,0 +1,763 @@ +{ + "last_node_id": 19, + "last_link_id": 16, + "nodes": [ + { + "id": 10, + "type": "VAELoader", + "pos": [ + 853, + 983 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "VAE", + "type": "VAE", + "links": [ + 7 + ], + "slot_index": 0 + } + ], + "title": "VAE加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "pastel-waifu-diffusion.vae.pt" + ] + }, + { + "id": 12, + "type": "输入图像", + "pos": [ + -17, + 1501 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 11 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像", + "properties": { + "sdn_hide": false, + "label": "(NORMAL)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_球体_Copyff875_NORMAL.png", + "输入" + ] + }, + { + "id": 13, + "type": "ControlNetLoader", + "pos": [ + -2, + 1281 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 8 + ], + "slot_index": 0 + } + ], + "title": "ControlNet加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_normalbae.pth" + ] + }, + { + "id": 14, + "type": "ControlNetApply", + "pos": [ + 389, + 1138 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 12, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 8, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 11, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 9 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 16, + "type": "存储", + "pos": [ + 1476, + 402 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 14, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 10, + "label": "images" + } + ], + "outputs": [], + "title": "ToMatImage", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "ComfyUI", + "" + ] + }, + { + "id": 17, + "type": "ControlNetApply", + "pos": [ + 6, + 1105 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 13, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 14, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 15, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 12 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 18, + "type": "ControlNetLoader", + "pos": [ + -384, + 1191 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 14 + ], + "slot_index": 0 + } + ], + "title": "ControlNet加载器.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_depth.pth" + ] + }, + { + "id": 19, + "type": "输入图像", + "pos": [ + -443, + 1409 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 15 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像.001", + "properties": { + "sdn_hide": false, + "label": "(DEPTH)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_球体_Copyff875_DEPTH.png", + "输入" + ] + }, + { + "id": 3, + "type": "KSampler", + "pos": [ + 824, + 511 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 11, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 3, + "label": "model" + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": 9, + "label": "positive" + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": 1, + "label": "negative" + }, + { + "name": "latent_image", + "type": "LATENT", + "link": 4, + "label": "latent_image" + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 5 + ], + "slot_index": 0 + } + ], + "title": "K采样器", + "properties": { + "sdn_hide": false, + "label": "003" + }, + "widgets_values": [ + "3856068742", + "fixed", + 20, + 8.0, + "euler", + "karras", + 1.0 + ] + }, + { + "id": 4, + "type": "CheckpointLoaderSimple", + "pos": [ + -698, + 823 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 3 + ], + "slot_index": 0 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [ + 0, + 2 + ], + "slot_index": 1 + }, + { + "name": "VAE", + "type": "VAE", + "links": [], + "slot_index": 2 + } + ], + "title": "Checkpoint简易加载器", + "properties": { + "sdn_hide": false, + "label": "001" + }, + "widgets_values": [ + "GuoFeng3.2_f16.safetensors" + ] + }, + { + "id": 5, + "type": "CLIPTextEncode", + "pos": [ + -459, + 1008 + ], + "size": { + "0": 347, + "1": 30 + }, + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 0, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 13 + ], + "slot_index": 0 + } + ], + "title": "CLIP文本编码器(正)", + "properties": { + "sdn_hide": false, + "label": "002" + }, + "widgets_values": [ + "Blue cloth" + ] + }, + { + "id": 6, + "type": "CLIPTextEncode", + "pos": [ + -129, + 764 + ], + "size": { + "0": 306, + "1": 30 + }, + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 2, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 1 + ], + "slot_index": 0 + } + ], + "title": "CLIP文本编码器(反)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "embedding:EasyNegative" + ] + }, + { + "id": 7, + "type": "EmptyLatentImage", + "pos": [ + 389, + 1336 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 4 + ], + "slot_index": 0 + } + ], + "title": "空Latent图像", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1024, + 1024, + 1 + ] + }, + { + "id": 8, + "type": "VAEDecode", + "pos": [ + 1176, + 867 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [ + { + "name": "samples", + "type": "LATENT", + "link": 5, + "label": "samples" + }, + { + "name": "vae", + "type": "VAE", + "link": 7, + "label": "vae" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 6, + 10 + ], + "slot_index": 0 + } + ], + "title": "VAE解码", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 9, + "type": "PreviewImage", + "pos": [ + 1476, + 602 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 6, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + } + ], + "links": [ + [ + 0, + 4, + 1, + 5, + 0, + "CLIP" + ], + [ + 1, + 6, + 0, + 3, + 2, + "CONDITIONING" + ], + [ + 2, + 4, + 1, + 6, + 0, + "CLIP" + ], + [ + 3, + 4, + 0, + 3, + 0, + "MODEL" + ], + [ + 4, + 7, + 0, + 3, + 3, + "LATENT" + ], + [ + 5, + 3, + 0, + 8, + 0, + "LATENT" + ], + [ + 6, + 8, + 0, + 9, + 0, + "IMAGE" + ], + [ + 7, + 10, + 0, + 8, + 1, + "VAE" + ], + [ + 8, + 13, + 0, + 14, + 1, + "CONTROL_NET" + ], + [ + 9, + 14, + 0, + 3, + 1, + "CONDITIONING" + ], + [ + 10, + 8, + 0, + 16, + 0, + "IMAGE" + ], + [ + 11, + 12, + 0, + 14, + 2, + "IMAGE" + ], + [ + 12, + 17, + 0, + 14, + 0, + "CONDITIONING" + ], + [ + 13, + 5, + 0, + 17, + 0, + "CONDITIONING" + ], + [ + 14, + 18, + 0, + 17, + 1, + "CONTROL_NET" + ], + [ + 15, + 19, + 0, + 17, + 2, + "IMAGE" + ] + ], + "groups": [], + "config": {}, + "extra": { + "groupNodes": {} + }, + "version": 0.4 +} \ No newline at end of file diff --git "a/SDNode/resource/solutions/CN/\351\207\221\345\261\236\345\214\226(\346\267\261\345\272\246&Canny\347\272\277).blend" "b/SDNode/resource/solutions/CN/\351\207\221\345\261\236\345\214\226(\346\267\261\345\272\246&Canny\347\272\277).blend" new file mode 100644 index 0000000..4028ef6 Binary files /dev/null and "b/SDNode/resource/solutions/CN/\351\207\221\345\261\236\345\214\226(\346\267\261\345\272\246&Canny\347\272\277).blend" differ diff --git "a/SDNode/resource/solutions/CN/\351\207\221\345\261\236\345\214\226(\346\267\261\345\272\246&Canny\347\272\277).jpg" "b/SDNode/resource/solutions/CN/\351\207\221\345\261\236\345\214\226(\346\267\261\345\272\246&Canny\347\272\277).jpg" new file mode 100644 index 0000000..ff98e9c Binary files /dev/null and "b/SDNode/resource/solutions/CN/\351\207\221\345\261\236\345\214\226(\346\267\261\345\272\246&Canny\347\272\277).jpg" differ diff --git "a/SDNode/resource/solutions/CN/\351\207\221\345\261\236\345\214\226(\346\267\261\345\272\246&Canny\347\272\277).json" "b/SDNode/resource/solutions/CN/\351\207\221\345\261\236\345\214\226(\346\267\261\345\272\246&Canny\347\272\277).json" new file mode 100644 index 0000000..913d126 --- /dev/null +++ "b/SDNode/resource/solutions/CN/\351\207\221\345\261\236\345\214\226(\346\267\261\345\272\246&Canny\347\272\277).json" @@ -0,0 +1,957 @@ +{ + "last_node_id": 22, + "last_link_id": 22, + "nodes": [ + { + "id": 10, + "type": "VAELoader", + "pos": [ + 724, + 1154 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "VAE", + "type": "VAE", + "links": [ + 5, + 18 + ], + "slot_index": 0 + } + ], + "title": "VAE加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "pastel-waifu-diffusion.vae.pt" + ] + }, + { + "id": 11, + "type": "AIO_Preprocessor", + "pos": [ + -485, + 1474 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 12, + "label": "image" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 11, + 15 + ], + "slot_index": 0 + } + ], + "title": "AIO_Preprocessor", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "DepthAnythingPreprocessor", + 512 + ] + }, + { + "id": 12, + "type": "AIO_Preprocessor", + "pos": [ + -117, + 1692 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 13, + "label": "image" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 14, + 16 + ], + "slot_index": 0 + } + ], + "title": "AIO_Preprocessor.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "CannyEdgePreprocessor", + 1024 + ] + }, + { + "id": 13, + "type": "ControlNetLoader", + "pos": [ + -7, + 1349 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 6 + ], + "slot_index": 0 + } + ], + "title": "ControlNet加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_canny.pth" + ] + }, + { + "id": 14, + "type": "ControlNetApply", + "pos": [ + 381, + 1197 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 14, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 8, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 6, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 14, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 19 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 15, + "type": "PreviewImage", + "pos": [ + -446, + 1666 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 11, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 15, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用).001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 16, + "type": "存储", + "pos": [ + 1468, + 461 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 18, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 7, + "label": "images" + } + ], + "outputs": [], + "title": "ToMatImage", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "ComfyUI", + "" + ] + }, + { + "id": 17, + "type": "ControlNetApply", + "pos": [ + -7, + 1164 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 9, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 10, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 11, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 8 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 18, + "type": "ControlNetLoader", + "pos": [ + -482, + 1264 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 10 + ], + "slot_index": 0 + } + ], + "title": "ControlNet加载器.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_depth.pth" + ] + }, + { + "id": 19, + "type": "输入图像", + "pos": [ + -855, + 1464 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 12, + 13, + 17 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像.001", + "properties": { + "sdn_hide": false, + "label": "(COLOR)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_大理石胸像01_Copyac241_COLOR.png", + "输入" + ] + }, + { + "id": 20, + "type": "PreviewImage", + "pos": [ + 149, + 1632 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 16, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用).002", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 22, + "type": "VAEEncode", + "pos": [ + 559, + 1683 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "pixels", + "type": "IMAGE", + "link": 17, + "label": "pixels" + }, + { + "name": "vae", + "type": "VAE", + "link": 18, + "label": "vae" + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [], + "slot_index": 0 + } + ], + "title": "VAE编码", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 3, + "type": "KSampler", + "pos": [ + 816, + 570 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 15, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 2, + "label": "model" + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": 19, + "label": "positive" + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": 20, + "label": "negative" + }, + { + "name": "latent_image", + "type": "LATENT", + "link": 21, + "label": "latent_image" + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 3 + ], + "slot_index": 0 + } + ], + "title": "K采样器", + "properties": { + "sdn_hide": false, + "label": "003" + }, + "widgets_values": [ + "1481012336", + "fixed", + 20, + 8.0, + "euler", + "karras", + 1.0 + ] + }, + { + "id": 4, + "type": "CheckpointLoaderSimple", + "pos": [ + -705, + 882 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 2 + ], + "slot_index": 0 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [ + 0, + 1 + ], + "slot_index": 1 + }, + { + "name": "VAE", + "type": "VAE", + "links": [], + "slot_index": 2 + } + ], + "title": "Checkpoint简易加载器", + "properties": { + "sdn_hide": false, + "label": "001" + }, + "widgets_values": [ + "GuoFeng3.2_f16.safetensors" + ] + }, + { + "id": 5, + "type": "CLIPTextEncode", + "pos": [ + -356, + 610 + ], + "size": { + "0": 347, + "1": 30 + }, + "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 0, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 9 + ], + "slot_index": 0 + } + ], + "title": "CLIP文本编码器(正)", + "properties": { + "sdn_hide": false, + "label": "002" + }, + "widgets_values": [ + "Stainless steel products, metallic material, anisotropic" + ] + }, + { + "id": 6, + "type": "CLIPTextEncode", + "pos": [ + 20, + 991 + ], + "size": { + "0": 306, + "1": 30 + }, + "flags": {}, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 1, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 20 + ], + "slot_index": 0 + } + ], + "title": "CLIP文本编码器(反)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "embedding:EasyNegative" + ] + }, + { + "id": 7, + "type": "EmptyLatentImage", + "pos": [ + 381, + 1395 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 21 + ], + "slot_index": 0 + } + ], + "title": "空Latent图像", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1024, + 1024, + 1 + ] + }, + { + "id": 8, + "type": "VAEDecode", + "pos": [ + 1168, + 926 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 16, + "mode": 0, + "inputs": [ + { + "name": "samples", + "type": "LATENT", + "link": 3, + "label": "samples" + }, + { + "name": "vae", + "type": "VAE", + "link": 5, + "label": "vae" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 4, + 7 + ], + "slot_index": 0 + } + ], + "title": "VAE解码", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 9, + "type": "PreviewImage", + "pos": [ + 1468, + 661 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 17, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 4, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + } + ], + "links": [ + [ + 0, + 4, + 1, + 5, + 0, + "CLIP" + ], + [ + 1, + 4, + 1, + 6, + 0, + "CLIP" + ], + [ + 2, + 4, + 0, + 3, + 0, + "MODEL" + ], + [ + 3, + 3, + 0, + 8, + 0, + "LATENT" + ], + [ + 4, + 8, + 0, + 9, + 0, + "IMAGE" + ], + [ + 5, + 10, + 0, + 8, + 1, + "VAE" + ], + [ + 6, + 13, + 0, + 14, + 1, + "CONTROL_NET" + ], + [ + 7, + 8, + 0, + 16, + 0, + "IMAGE" + ], + [ + 8, + 17, + 0, + 14, + 0, + "CONDITIONING" + ], + [ + 9, + 5, + 0, + 17, + 0, + "CONDITIONING" + ], + [ + 10, + 18, + 0, + 17, + 1, + "CONTROL_NET" + ], + [ + 11, + 11, + 0, + 17, + 2, + "IMAGE" + ], + [ + 12, + 19, + 0, + 11, + 0, + "IMAGE" + ], + [ + 13, + 19, + 0, + 12, + 0, + "IMAGE" + ], + [ + 14, + 12, + 0, + 14, + 2, + "IMAGE" + ], + [ + 15, + 11, + 0, + 15, + 0, + "IMAGE" + ], + [ + 16, + 12, + 0, + 20, + 0, + "IMAGE" + ], + [ + 17, + 19, + 0, + 22, + 0, + "IMAGE" + ], + [ + 18, + 10, + 0, + 22, + 1, + "VAE" + ], + [ + 19, + 14, + 0, + 3, + 1, + "CONDITIONING" + ], + [ + 20, + 6, + 0, + 3, + 2, + "CONDITIONING" + ], + [ + 21, + 7, + 0, + 3, + 3, + "LATENT" + ] + ], + "groups": [], + "config": {}, + "extra": { + "groupNodes": {} + }, + "version": 0.4 +} \ No newline at end of file diff --git "a/SDNode/resource/solutions/CN/\351\207\221\345\261\236\347\224\237\346\210\220(\346\267\261\345\272\246&\346\263\225\345\220\221).blend" "b/SDNode/resource/solutions/CN/\351\207\221\345\261\236\347\224\237\346\210\220(\346\267\261\345\272\246&\346\263\225\345\220\221).blend" new file mode 100644 index 0000000..4028ef6 Binary files /dev/null and "b/SDNode/resource/solutions/CN/\351\207\221\345\261\236\347\224\237\346\210\220(\346\267\261\345\272\246&\346\263\225\345\220\221).blend" differ diff --git "a/SDNode/resource/solutions/CN/\351\207\221\345\261\236\347\224\237\346\210\220(\346\267\261\345\272\246&\346\263\225\345\220\221).jpg" "b/SDNode/resource/solutions/CN/\351\207\221\345\261\236\347\224\237\346\210\220(\346\267\261\345\272\246&\346\263\225\345\220\221).jpg" new file mode 100644 index 0000000..7f6c181 Binary files /dev/null and "b/SDNode/resource/solutions/CN/\351\207\221\345\261\236\347\224\237\346\210\220(\346\267\261\345\272\246&\346\263\225\345\220\221).jpg" differ diff --git "a/SDNode/resource/solutions/CN/\351\207\221\345\261\236\347\224\237\346\210\220(\346\267\261\345\272\246&\346\263\225\345\220\221).json" "b/SDNode/resource/solutions/CN/\351\207\221\345\261\236\347\224\237\346\210\220(\346\267\261\345\272\246&\346\263\225\345\220\221).json" new file mode 100644 index 0000000..d8e4797 --- /dev/null +++ "b/SDNode/resource/solutions/CN/\351\207\221\345\261\236\347\224\237\346\210\220(\346\267\261\345\272\246&\346\263\225\345\220\221).json" @@ -0,0 +1,763 @@ +{ + "last_node_id": 19, + "last_link_id": 16, + "nodes": [ + { + "id": 10, + "type": "VAELoader", + "pos": [ + 853, + 983 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "VAE", + "type": "VAE", + "links": [ + 7 + ], + "slot_index": 0 + } + ], + "title": "VAE加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "pastel-waifu-diffusion.vae.pt" + ] + }, + { + "id": 12, + "type": "输入图像", + "pos": [ + -17, + 1501 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 11 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像", + "properties": { + "sdn_hide": false, + "label": "(NORMAL)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_球体_Copyff875_NORMAL.png", + "输入" + ] + }, + { + "id": 13, + "type": "ControlNetLoader", + "pos": [ + -2, + 1281 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 8 + ], + "slot_index": 0 + } + ], + "title": "ControlNet加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_normalbae.pth" + ] + }, + { + "id": 14, + "type": "ControlNetApply", + "pos": [ + 389, + 1138 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 12, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 8, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 11, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 9 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 16, + "type": "存储", + "pos": [ + 1476, + 402 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 14, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 10, + "label": "images" + } + ], + "outputs": [], + "title": "ToMatImage", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "ComfyUI", + "" + ] + }, + { + "id": 17, + "type": "ControlNetApply", + "pos": [ + 6, + 1105 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 13, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 14, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 15, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 12 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 18, + "type": "ControlNetLoader", + "pos": [ + -384, + 1191 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 14 + ], + "slot_index": 0 + } + ], + "title": "ControlNet加载器.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_depth.pth" + ] + }, + { + "id": 19, + "type": "输入图像", + "pos": [ + -443, + 1409 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 15 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像.001", + "properties": { + "sdn_hide": false, + "label": "(DEPTH)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_球体_Copyff875_DEPTH.png", + "输入" + ] + }, + { + "id": 3, + "type": "KSampler", + "pos": [ + 824, + 511 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 11, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 3, + "label": "model" + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": 9, + "label": "positive" + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": 1, + "label": "negative" + }, + { + "name": "latent_image", + "type": "LATENT", + "link": 4, + "label": "latent_image" + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 5 + ], + "slot_index": 0 + } + ], + "title": "K采样器", + "properties": { + "sdn_hide": false, + "label": "003" + }, + "widgets_values": [ + "3856068742", + "fixed", + 20, + 8.0, + "euler", + "karras", + 1.0 + ] + }, + { + "id": 4, + "type": "CheckpointLoaderSimple", + "pos": [ + -698, + 823 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 3 + ], + "slot_index": 0 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [ + 0, + 2 + ], + "slot_index": 1 + }, + { + "name": "VAE", + "type": "VAE", + "links": [], + "slot_index": 2 + } + ], + "title": "Checkpoint简易加载器", + "properties": { + "sdn_hide": false, + "label": "001" + }, + "widgets_values": [ + "GuoFeng3.2_f16.safetensors" + ] + }, + { + "id": 5, + "type": "CLIPTextEncode", + "pos": [ + -459, + 1008 + ], + "size": { + "0": 347, + "1": 30 + }, + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 0, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 13 + ], + "slot_index": 0 + } + ], + "title": "CLIP文本编码器(正)", + "properties": { + "sdn_hide": false, + "label": "002" + }, + "widgets_values": [ + "stainless steel, ruins" + ] + }, + { + "id": 6, + "type": "CLIPTextEncode", + "pos": [ + -129, + 764 + ], + "size": { + "0": 306, + "1": 30 + }, + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 2, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 1 + ], + "slot_index": 0 + } + ], + "title": "CLIP文本编码器(反)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "embedding:EasyNegative" + ] + }, + { + "id": 7, + "type": "EmptyLatentImage", + "pos": [ + 389, + 1336 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 4 + ], + "slot_index": 0 + } + ], + "title": "空Latent图像", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1024, + 1024, + 1 + ] + }, + { + "id": 8, + "type": "VAEDecode", + "pos": [ + 1176, + 867 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [ + { + "name": "samples", + "type": "LATENT", + "link": 5, + "label": "samples" + }, + { + "name": "vae", + "type": "VAE", + "link": 7, + "label": "vae" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 6, + 10 + ], + "slot_index": 0 + } + ], + "title": "VAE解码", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 9, + "type": "PreviewImage", + "pos": [ + 1476, + 602 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 6, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + } + ], + "links": [ + [ + 0, + 4, + 1, + 5, + 0, + "CLIP" + ], + [ + 1, + 6, + 0, + 3, + 2, + "CONDITIONING" + ], + [ + 2, + 4, + 1, + 6, + 0, + "CLIP" + ], + [ + 3, + 4, + 0, + 3, + 0, + "MODEL" + ], + [ + 4, + 7, + 0, + 3, + 3, + "LATENT" + ], + [ + 5, + 3, + 0, + 8, + 0, + "LATENT" + ], + [ + 6, + 8, + 0, + 9, + 0, + "IMAGE" + ], + [ + 7, + 10, + 0, + 8, + 1, + "VAE" + ], + [ + 8, + 13, + 0, + 14, + 1, + "CONTROL_NET" + ], + [ + 9, + 14, + 0, + 3, + 1, + "CONDITIONING" + ], + [ + 10, + 8, + 0, + 16, + 0, + "IMAGE" + ], + [ + 11, + 12, + 0, + 14, + 2, + "IMAGE" + ], + [ + 12, + 17, + 0, + 14, + 0, + "CONDITIONING" + ], + [ + 13, + 5, + 0, + 17, + 0, + "CONDITIONING" + ], + [ + 14, + 18, + 0, + 17, + 1, + "CONTROL_NET" + ], + [ + 15, + 19, + 0, + 17, + 2, + "IMAGE" + ] + ], + "groups": [], + "config": {}, + "extra": { + "groupNodes": {} + }, + "version": 0.4 +} \ No newline at end of file diff --git a/SDNode/resource/solutions/EN/00-Default.blend b/SDNode/resource/solutions/EN/00-Default.blend new file mode 100644 index 0000000..2ebdc0d Binary files /dev/null and b/SDNode/resource/solutions/EN/00-Default.blend differ diff --git a/SDNode/resource/solutions/EN/00-Default.jpg b/SDNode/resource/solutions/EN/00-Default.jpg new file mode 100644 index 0000000..5dc5b82 Binary files /dev/null and b/SDNode/resource/solutions/EN/00-Default.jpg differ diff --git a/SDNode/resource/solutions/EN/00-Default.json b/SDNode/resource/solutions/EN/00-Default.json new file mode 100644 index 0000000..19b48ea --- /dev/null +++ b/SDNode/resource/solutions/EN/00-Default.json @@ -0,0 +1,763 @@ +{ + "last_node_id": 19, + "last_link_id": 16, + "nodes": [ + { + "id": 10, + "type": "VAELoader", + "pos": [ + 853, + 983 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "VAE", + "type": "VAE", + "links": [ + 7 + ], + "slot_index": 0 + } + ], + "title": "VAE加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "pastel-waifu-diffusion.vae.pt" + ] + }, + { + "id": 12, + "type": "输入图像", + "pos": [ + -17, + 1501 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 10 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像", + "properties": { + "sdn_hide": false, + "label": "(NORMAL)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_大理石胸像01_Copyac241_NORMAL.png", + "输入" + ] + }, + { + "id": 13, + "type": "ControlNetLoader", + "pos": [ + -2, + 1281 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 8 + ], + "slot_index": 0 + } + ], + "title": "ControlNetLoader", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_normalbae.pth" + ] + }, + { + "id": 14, + "type": "ControlNetApply", + "pos": [ + 389, + 1138 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 15, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 8, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 10, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 14 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 16, + "type": "存储", + "pos": [ + 1476, + 402 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 14, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 9, + "label": "images" + } + ], + "outputs": [], + "title": "ToMatImage", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "ComfyUI", + "" + ] + }, + { + "id": 17, + "type": "ControlNetApply", + "pos": [ + 6, + 1105 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 11, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 12, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 13, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 15 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 18, + "type": "ControlNetLoader", + "pos": [ + -384, + 1191 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 12 + ], + "slot_index": 0 + } + ], + "title": "ControlNetLoader.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_depth.pth" + ] + }, + { + "id": 19, + "type": "输入图像", + "pos": [ + -443, + 1409 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 13 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像.001", + "properties": { + "sdn_hide": false, + "label": "(DEPTH)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_大理石胸像01_Copyac241_DEPTH.png", + "输入" + ] + }, + { + "id": 3, + "type": "KSampler", + "pos": [ + 824, + 511 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 11, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 3, + "label": "model" + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": 14, + "label": "positive" + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": 1, + "label": "negative" + }, + { + "name": "latent_image", + "type": "LATENT", + "link": 4, + "label": "latent_image" + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 5 + ], + "slot_index": 0 + } + ], + "title": "K采样器", + "properties": { + "sdn_hide": false, + "label": "003" + }, + "widgets_values": [ + "3888636113", + "fixed", + 20, + 8.0, + "euler", + "karras", + 1.0 + ] + }, + { + "id": 4, + "type": "CheckpointLoaderSimple", + "pos": [ + -698, + 823 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 3 + ], + "slot_index": 0 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [ + 0, + 2 + ], + "slot_index": 1 + }, + { + "name": "VAE", + "type": "VAE", + "links": [], + "slot_index": 2 + } + ], + "title": "CheckpointLoaderSimple", + "properties": { + "sdn_hide": false, + "label": "001" + }, + "widgets_values": [ + "GuoFeng3.2_f16.safetensors" + ] + }, + { + "id": 5, + "type": "CLIPTextEncode", + "pos": [ + -459, + 1008 + ], + "size": { + "0": 347, + "1": 30 + }, + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 0, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 11 + ], + "slot_index": 0 + } + ], + "title": "CLIPTextEncode(Positive)", + "properties": { + "sdn_hide": false, + "label": "002" + }, + "widgets_values": [ + "Model, 8K, Octane rendering, UE5, realistic, glossy, delicate texture, best quality" + ] + }, + { + "id": 6, + "type": "CLIPTextEncode", + "pos": [ + -129, + 764 + ], + "size": { + "0": 306, + "1": 30 + }, + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 2, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 1 + ], + "slot_index": 0 + } + ], + "title": "CLIPTextEncode(Negative)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "embedding:EasyNegative" + ] + }, + { + "id": 7, + "type": "EmptyLatentImage", + "pos": [ + 389, + 1336 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 4 + ], + "slot_index": 0 + } + ], + "title": "空Latent图像", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1024, + 1024, + 1 + ] + }, + { + "id": 8, + "type": "VAEDecode", + "pos": [ + 1176, + 867 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [ + { + "name": "samples", + "type": "LATENT", + "link": 5, + "label": "samples" + }, + { + "name": "vae", + "type": "VAE", + "link": 7, + "label": "vae" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 6, + 9 + ], + "slot_index": 0 + } + ], + "title": "VAE解码", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 9, + "type": "PreviewImage", + "pos": [ + 1476, + 602 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 6, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + } + ], + "links": [ + [ + 0, + 4, + 1, + 5, + 0, + "CLIP" + ], + [ + 1, + 6, + 0, + 3, + 2, + "CONDITIONING" + ], + [ + 2, + 4, + 1, + 6, + 0, + "CLIP" + ], + [ + 3, + 4, + 0, + 3, + 0, + "MODEL" + ], + [ + 4, + 7, + 0, + 3, + 3, + "LATENT" + ], + [ + 5, + 3, + 0, + 8, + 0, + "LATENT" + ], + [ + 6, + 8, + 0, + 9, + 0, + "IMAGE" + ], + [ + 7, + 10, + 0, + 8, + 1, + "VAE" + ], + [ + 8, + 13, + 0, + 14, + 1, + "CONTROL_NET" + ], + [ + 9, + 8, + 0, + 16, + 0, + "IMAGE" + ], + [ + 10, + 12, + 0, + 14, + 2, + "IMAGE" + ], + [ + 11, + 5, + 0, + 17, + 0, + "CONDITIONING" + ], + [ + 12, + 18, + 0, + 17, + 1, + "CONTROL_NET" + ], + [ + 13, + 19, + 0, + 17, + 2, + "IMAGE" + ], + [ + 14, + 14, + 0, + 3, + 1, + "CONDITIONING" + ], + [ + 15, + 17, + 0, + 14, + 0, + "CONDITIONING" + ] + ], + "groups": [], + "config": {}, + "extra": { + "groupNodes": {} + }, + "version": 0.4 +} \ No newline at end of file diff --git a/SDNode/resource/solutions/EN/Gen Cloth(Depth&Normal).blend b/SDNode/resource/solutions/EN/Gen Cloth(Depth&Normal).blend new file mode 100644 index 0000000..4d991ae Binary files /dev/null and b/SDNode/resource/solutions/EN/Gen Cloth(Depth&Normal).blend differ diff --git a/SDNode/resource/solutions/EN/Gen Cloth(Depth&Normal).jpg b/SDNode/resource/solutions/EN/Gen Cloth(Depth&Normal).jpg new file mode 100644 index 0000000..5adbe55 Binary files /dev/null and b/SDNode/resource/solutions/EN/Gen Cloth(Depth&Normal).jpg differ diff --git a/SDNode/resource/solutions/EN/Gen Cloth(Depth&Normal).json b/SDNode/resource/solutions/EN/Gen Cloth(Depth&Normal).json new file mode 100644 index 0000000..bcc0bf2 --- /dev/null +++ b/SDNode/resource/solutions/EN/Gen Cloth(Depth&Normal).json @@ -0,0 +1,763 @@ +{ + "last_node_id": 19, + "last_link_id": 16, + "nodes": [ + { + "id": 10, + "type": "VAELoader", + "pos": [ + 853, + 983 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "VAE", + "type": "VAE", + "links": [ + 7 + ], + "slot_index": 0 + } + ], + "title": "VAE加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "pastel-waifu-diffusion.vae.pt" + ] + }, + { + "id": 12, + "type": "输入图像", + "pos": [ + -17, + 1501 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 11 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像", + "properties": { + "sdn_hide": false, + "label": "(NORMAL)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_球体_Copyff875_NORMAL.png", + "输入" + ] + }, + { + "id": 13, + "type": "ControlNetLoader", + "pos": [ + -2, + 1281 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 8 + ], + "slot_index": 0 + } + ], + "title": "ControlNetLoader", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_normalbae.pth" + ] + }, + { + "id": 14, + "type": "ControlNetApply", + "pos": [ + 389, + 1138 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 12, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 8, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 11, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 9 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 16, + "type": "存储", + "pos": [ + 1476, + 402 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 14, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 10, + "label": "images" + } + ], + "outputs": [], + "title": "ToMatImage", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "ComfyUI", + "" + ] + }, + { + "id": 17, + "type": "ControlNetApply", + "pos": [ + 6, + 1105 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 13, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 14, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 15, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 12 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 18, + "type": "ControlNetLoader", + "pos": [ + -384, + 1191 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 14 + ], + "slot_index": 0 + } + ], + "title": "ControlNetLoader.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_depth.pth" + ] + }, + { + "id": 19, + "type": "输入图像", + "pos": [ + -443, + 1409 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 15 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像.001", + "properties": { + "sdn_hide": false, + "label": "(DEPTH)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_球体_Copyff875_DEPTH.png", + "输入" + ] + }, + { + "id": 3, + "type": "KSampler", + "pos": [ + 824, + 511 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 11, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 3, + "label": "model" + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": 9, + "label": "positive" + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": 1, + "label": "negative" + }, + { + "name": "latent_image", + "type": "LATENT", + "link": 4, + "label": "latent_image" + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 5 + ], + "slot_index": 0 + } + ], + "title": "K采样器", + "properties": { + "sdn_hide": false, + "label": "003" + }, + "widgets_values": [ + "3856068742", + "fixed", + 20, + 8.0, + "euler", + "karras", + 1.0 + ] + }, + { + "id": 4, + "type": "CheckpointLoaderSimple", + "pos": [ + -698, + 823 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 3 + ], + "slot_index": 0 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [ + 0, + 2 + ], + "slot_index": 1 + }, + { + "name": "VAE", + "type": "VAE", + "links": [], + "slot_index": 2 + } + ], + "title": "CheckpointLoaderSimple", + "properties": { + "sdn_hide": false, + "label": "001" + }, + "widgets_values": [ + "GuoFeng3.2_f16.safetensors" + ] + }, + { + "id": 5, + "type": "CLIPTextEncode", + "pos": [ + -459, + 1008 + ], + "size": { + "0": 347, + "1": 30 + }, + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 0, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 13 + ], + "slot_index": 0 + } + ], + "title": "CLIPTextEncode(Positive)", + "properties": { + "sdn_hide": false, + "label": "002" + }, + "widgets_values": [ + "Blue cloth" + ] + }, + { + "id": 6, + "type": "CLIPTextEncode", + "pos": [ + -129, + 764 + ], + "size": { + "0": 306, + "1": 30 + }, + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 2, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 1 + ], + "slot_index": 0 + } + ], + "title": "CLIPTextEncode(Negative)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "embedding:EasyNegative" + ] + }, + { + "id": 7, + "type": "EmptyLatentImage", + "pos": [ + 389, + 1336 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 4 + ], + "slot_index": 0 + } + ], + "title": "空Latent图像", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1024, + 1024, + 1 + ] + }, + { + "id": 8, + "type": "VAEDecode", + "pos": [ + 1176, + 867 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [ + { + "name": "samples", + "type": "LATENT", + "link": 5, + "label": "samples" + }, + { + "name": "vae", + "type": "VAE", + "link": 7, + "label": "vae" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 6, + 10 + ], + "slot_index": 0 + } + ], + "title": "VAE解码", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 9, + "type": "PreviewImage", + "pos": [ + 1476, + 602 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 6, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + } + ], + "links": [ + [ + 0, + 4, + 1, + 5, + 0, + "CLIP" + ], + [ + 1, + 6, + 0, + 3, + 2, + "CONDITIONING" + ], + [ + 2, + 4, + 1, + 6, + 0, + "CLIP" + ], + [ + 3, + 4, + 0, + 3, + 0, + "MODEL" + ], + [ + 4, + 7, + 0, + 3, + 3, + "LATENT" + ], + [ + 5, + 3, + 0, + 8, + 0, + "LATENT" + ], + [ + 6, + 8, + 0, + 9, + 0, + "IMAGE" + ], + [ + 7, + 10, + 0, + 8, + 1, + "VAE" + ], + [ + 8, + 13, + 0, + 14, + 1, + "CONTROL_NET" + ], + [ + 9, + 14, + 0, + 3, + 1, + "CONDITIONING" + ], + [ + 10, + 8, + 0, + 16, + 0, + "IMAGE" + ], + [ + 11, + 12, + 0, + 14, + 2, + "IMAGE" + ], + [ + 12, + 17, + 0, + 14, + 0, + "CONDITIONING" + ], + [ + 13, + 5, + 0, + 17, + 0, + "CONDITIONING" + ], + [ + 14, + 18, + 0, + 17, + 1, + "CONTROL_NET" + ], + [ + 15, + 19, + 0, + 17, + 2, + "IMAGE" + ] + ], + "groups": [], + "config": {}, + "extra": { + "groupNodes": {} + }, + "version": 0.4 +} \ No newline at end of file diff --git a/SDNode/resource/solutions/EN/Gen Metal(Depth&Normal).blend b/SDNode/resource/solutions/EN/Gen Metal(Depth&Normal).blend new file mode 100644 index 0000000..93d177a Binary files /dev/null and b/SDNode/resource/solutions/EN/Gen Metal(Depth&Normal).blend differ diff --git a/SDNode/resource/solutions/EN/Gen Metal(Depth&Normal).jpg b/SDNode/resource/solutions/EN/Gen Metal(Depth&Normal).jpg new file mode 100644 index 0000000..092f706 Binary files /dev/null and b/SDNode/resource/solutions/EN/Gen Metal(Depth&Normal).jpg differ diff --git a/SDNode/resource/solutions/EN/Gen Metal(Depth&Normal).json b/SDNode/resource/solutions/EN/Gen Metal(Depth&Normal).json new file mode 100644 index 0000000..88b80ea --- /dev/null +++ b/SDNode/resource/solutions/EN/Gen Metal(Depth&Normal).json @@ -0,0 +1,763 @@ +{ + "last_node_id": 19, + "last_link_id": 16, + "nodes": [ + { + "id": 10, + "type": "VAELoader", + "pos": [ + 853, + 983 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "VAE", + "type": "VAE", + "links": [ + 7 + ], + "slot_index": 0 + } + ], + "title": "VAE加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "pastel-waifu-diffusion.vae.pt" + ] + }, + { + "id": 12, + "type": "输入图像", + "pos": [ + -17, + 1501 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 11 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像", + "properties": { + "sdn_hide": false, + "label": "(NORMAL)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_球体_Copyff875_NORMAL.png", + "输入" + ] + }, + { + "id": 13, + "type": "ControlNetLoader", + "pos": [ + -2, + 1281 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 8 + ], + "slot_index": 0 + } + ], + "title": "ControlNetLoader", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_normalbae.pth" + ] + }, + { + "id": 14, + "type": "ControlNetApply", + "pos": [ + 389, + 1138 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 12, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 8, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 11, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 9 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 16, + "type": "存储", + "pos": [ + 1476, + 402 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 14, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 10, + "label": "images" + } + ], + "outputs": [], + "title": "ToMatImage", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "ComfyUI", + "" + ] + }, + { + "id": 17, + "type": "ControlNetApply", + "pos": [ + 6, + 1105 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 13, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 14, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 15, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 12 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 18, + "type": "ControlNetLoader", + "pos": [ + -384, + 1191 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 14 + ], + "slot_index": 0 + } + ], + "title": "ControlNetLoader.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_depth.pth" + ] + }, + { + "id": 19, + "type": "输入图像", + "pos": [ + -443, + 1409 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 15 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像.001", + "properties": { + "sdn_hide": false, + "label": "(DEPTH)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_球体_Copyff875_DEPTH.png", + "输入" + ] + }, + { + "id": 3, + "type": "KSampler", + "pos": [ + 824, + 511 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 11, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 3, + "label": "model" + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": 9, + "label": "positive" + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": 1, + "label": "negative" + }, + { + "name": "latent_image", + "type": "LATENT", + "link": 4, + "label": "latent_image" + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 5 + ], + "slot_index": 0 + } + ], + "title": "K采样器", + "properties": { + "sdn_hide": false, + "label": "003" + }, + "widgets_values": [ + "3856068742", + "fixed", + 20, + 8.0, + "euler", + "karras", + 1.0 + ] + }, + { + "id": 4, + "type": "CheckpointLoaderSimple", + "pos": [ + -698, + 823 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 3 + ], + "slot_index": 0 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [ + 0, + 2 + ], + "slot_index": 1 + }, + { + "name": "VAE", + "type": "VAE", + "links": [], + "slot_index": 2 + } + ], + "title": "CheckpointLoaderSimple", + "properties": { + "sdn_hide": false, + "label": "001" + }, + "widgets_values": [ + "GuoFeng3.2_f16.safetensors" + ] + }, + { + "id": 5, + "type": "CLIPTextEncode", + "pos": [ + -459, + 1008 + ], + "size": { + "0": 347, + "1": 30 + }, + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 0, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 13 + ], + "slot_index": 0 + } + ], + "title": "CLIPTextEncode(Positive)", + "properties": { + "sdn_hide": false, + "label": "002" + }, + "widgets_values": [ + "stainless steel, ruins" + ] + }, + { + "id": 6, + "type": "CLIPTextEncode", + "pos": [ + -129, + 764 + ], + "size": { + "0": 306, + "1": 30 + }, + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 2, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 1 + ], + "slot_index": 0 + } + ], + "title": "CLIPTextEncode(Negative)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "embedding:EasyNegative" + ] + }, + { + "id": 7, + "type": "EmptyLatentImage", + "pos": [ + 389, + 1336 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 4 + ], + "slot_index": 0 + } + ], + "title": "空Latent图像", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1024, + 1024, + 1 + ] + }, + { + "id": 8, + "type": "VAEDecode", + "pos": [ + 1176, + 867 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [ + { + "name": "samples", + "type": "LATENT", + "link": 5, + "label": "samples" + }, + { + "name": "vae", + "type": "VAE", + "link": 7, + "label": "vae" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 6, + 10 + ], + "slot_index": 0 + } + ], + "title": "VAE解码", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 9, + "type": "PreviewImage", + "pos": [ + 1476, + 602 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 6, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + } + ], + "links": [ + [ + 0, + 4, + 1, + 5, + 0, + "CLIP" + ], + [ + 1, + 6, + 0, + 3, + 2, + "CONDITIONING" + ], + [ + 2, + 4, + 1, + 6, + 0, + "CLIP" + ], + [ + 3, + 4, + 0, + 3, + 0, + "MODEL" + ], + [ + 4, + 7, + 0, + 3, + 3, + "LATENT" + ], + [ + 5, + 3, + 0, + 8, + 0, + "LATENT" + ], + [ + 6, + 8, + 0, + 9, + 0, + "IMAGE" + ], + [ + 7, + 10, + 0, + 8, + 1, + "VAE" + ], + [ + 8, + 13, + 0, + 14, + 1, + "CONTROL_NET" + ], + [ + 9, + 14, + 0, + 3, + 1, + "CONDITIONING" + ], + [ + 10, + 8, + 0, + 16, + 0, + "IMAGE" + ], + [ + 11, + 12, + 0, + 14, + 2, + "IMAGE" + ], + [ + 12, + 17, + 0, + 14, + 0, + "CONDITIONING" + ], + [ + 13, + 5, + 0, + 17, + 0, + "CONDITIONING" + ], + [ + 14, + 18, + 0, + 17, + 1, + "CONTROL_NET" + ], + [ + 15, + 19, + 0, + 17, + 2, + "IMAGE" + ] + ], + "groups": [], + "config": {}, + "extra": { + "groupNodes": {} + }, + "version": 0.4 +} \ No newline at end of file diff --git a/SDNode/resource/solutions/EN/Mat2Metal(Depth&Canny).blend b/SDNode/resource/solutions/EN/Mat2Metal(Depth&Canny).blend new file mode 100644 index 0000000..b2ecfd3 Binary files /dev/null and b/SDNode/resource/solutions/EN/Mat2Metal(Depth&Canny).blend differ diff --git a/SDNode/resource/solutions/EN/Mat2Metal(Depth&Canny).jpg b/SDNode/resource/solutions/EN/Mat2Metal(Depth&Canny).jpg new file mode 100644 index 0000000..4a39219 Binary files /dev/null and b/SDNode/resource/solutions/EN/Mat2Metal(Depth&Canny).jpg differ diff --git a/SDNode/resource/solutions/EN/Mat2Metal(Depth&Canny).json b/SDNode/resource/solutions/EN/Mat2Metal(Depth&Canny).json new file mode 100644 index 0000000..926790d --- /dev/null +++ b/SDNode/resource/solutions/EN/Mat2Metal(Depth&Canny).json @@ -0,0 +1,957 @@ +{ + "last_node_id": 22, + "last_link_id": 22, + "nodes": [ + { + "id": 10, + "type": "VAELoader", + "pos": [ + 724, + 1154 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "VAE", + "type": "VAE", + "links": [ + 5, + 18 + ], + "slot_index": 0 + } + ], + "title": "VAE加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "pastel-waifu-diffusion.vae.pt" + ] + }, + { + "id": 11, + "type": "AIO_Preprocessor", + "pos": [ + -485, + 1474 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 12, + "label": "image" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 11, + 15 + ], + "slot_index": 0 + } + ], + "title": "AIO_Preprocessor", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "DepthAnythingPreprocessor", + 512 + ] + }, + { + "id": 12, + "type": "AIO_Preprocessor", + "pos": [ + -117, + 1692 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 13, + "label": "image" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 14, + 16 + ], + "slot_index": 0 + } + ], + "title": "AIO_Preprocessor.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "CannyEdgePreprocessor", + 1024 + ] + }, + { + "id": 13, + "type": "ControlNetLoader", + "pos": [ + -7, + 1349 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 6 + ], + "slot_index": 0 + } + ], + "title": "ControlNetLoader", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_canny.pth" + ] + }, + { + "id": 14, + "type": "ControlNetApply", + "pos": [ + 381, + 1197 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 14, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 8, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 6, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 14, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 19 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 15, + "type": "PreviewImage", + "pos": [ + -446, + 1666 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 11, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 15, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用).001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 16, + "type": "存储", + "pos": [ + 1468, + 461 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 18, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 7, + "label": "images" + } + ], + "outputs": [], + "title": "ToMatImage", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "ComfyUI", + "" + ] + }, + { + "id": 17, + "type": "ControlNetApply", + "pos": [ + -7, + 1164 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 9, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 10, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 11, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 8 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 18, + "type": "ControlNetLoader", + "pos": [ + -482, + 1264 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 10 + ], + "slot_index": 0 + } + ], + "title": "ControlNetLoader.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_depth.pth" + ] + }, + { + "id": 19, + "type": "输入图像", + "pos": [ + -855, + 1464 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 12, + 13, + 17 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像.001", + "properties": { + "sdn_hide": false, + "label": "(COLOR)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_大理石胸像01_Copyac241_COLOR.png", + "输入" + ] + }, + { + "id": 20, + "type": "PreviewImage", + "pos": [ + 149, + 1632 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 16, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用).002", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 22, + "type": "VAEEncode", + "pos": [ + 559, + 1683 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "pixels", + "type": "IMAGE", + "link": 17, + "label": "pixels" + }, + { + "name": "vae", + "type": "VAE", + "link": 18, + "label": "vae" + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [], + "slot_index": 0 + } + ], + "title": "VAE编码", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 3, + "type": "KSampler", + "pos": [ + 816, + 570 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 15, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 2, + "label": "model" + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": 19, + "label": "positive" + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": 20, + "label": "negative" + }, + { + "name": "latent_image", + "type": "LATENT", + "link": 21, + "label": "latent_image" + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 3 + ], + "slot_index": 0 + } + ], + "title": "K采样器", + "properties": { + "sdn_hide": false, + "label": "003" + }, + "widgets_values": [ + "1481012336", + "fixed", + 20, + 8.0, + "euler", + "karras", + 1.0 + ] + }, + { + "id": 4, + "type": "CheckpointLoaderSimple", + "pos": [ + -705, + 882 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 2 + ], + "slot_index": 0 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [ + 0, + 1 + ], + "slot_index": 1 + }, + { + "name": "VAE", + "type": "VAE", + "links": [], + "slot_index": 2 + } + ], + "title": "CheckpointLoaderSimple", + "properties": { + "sdn_hide": false, + "label": "001" + }, + "widgets_values": [ + "GuoFeng3.2_f16.safetensors" + ] + }, + { + "id": 5, + "type": "CLIPTextEncode", + "pos": [ + -356, + 610 + ], + "size": { + "0": 347, + "1": 30 + }, + "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 0, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 9 + ], + "slot_index": 0 + } + ], + "title": "CLIPTextEncode(Positive)", + "properties": { + "sdn_hide": false, + "label": "002" + }, + "widgets_values": [ + "Stainless steel products, metallic material, anisotropic" + ] + }, + { + "id": 6, + "type": "CLIPTextEncode", + "pos": [ + 20, + 991 + ], + "size": { + "0": 306, + "1": 30 + }, + "flags": {}, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 1, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 20 + ], + "slot_index": 0 + } + ], + "title": "CLIPTextEncode(Negative)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "embedding:EasyNegative" + ] + }, + { + "id": 7, + "type": "EmptyLatentImage", + "pos": [ + 381, + 1395 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 21 + ], + "slot_index": 0 + } + ], + "title": "空Latent图像", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1024, + 1024, + 1 + ] + }, + { + "id": 8, + "type": "VAEDecode", + "pos": [ + 1168, + 926 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 16, + "mode": 0, + "inputs": [ + { + "name": "samples", + "type": "LATENT", + "link": 3, + "label": "samples" + }, + { + "name": "vae", + "type": "VAE", + "link": 5, + "label": "vae" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 4, + 7 + ], + "slot_index": 0 + } + ], + "title": "VAE解码", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 9, + "type": "PreviewImage", + "pos": [ + 1468, + 661 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 17, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 4, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + } + ], + "links": [ + [ + 0, + 4, + 1, + 5, + 0, + "CLIP" + ], + [ + 1, + 4, + 1, + 6, + 0, + "CLIP" + ], + [ + 2, + 4, + 0, + 3, + 0, + "MODEL" + ], + [ + 3, + 3, + 0, + 8, + 0, + "LATENT" + ], + [ + 4, + 8, + 0, + 9, + 0, + "IMAGE" + ], + [ + 5, + 10, + 0, + 8, + 1, + "VAE" + ], + [ + 6, + 13, + 0, + 14, + 1, + "CONTROL_NET" + ], + [ + 7, + 8, + 0, + 16, + 0, + "IMAGE" + ], + [ + 8, + 17, + 0, + 14, + 0, + "CONDITIONING" + ], + [ + 9, + 5, + 0, + 17, + 0, + "CONDITIONING" + ], + [ + 10, + 18, + 0, + 17, + 1, + "CONTROL_NET" + ], + [ + 11, + 11, + 0, + 17, + 2, + "IMAGE" + ], + [ + 12, + 19, + 0, + 11, + 0, + "IMAGE" + ], + [ + 13, + 19, + 0, + 12, + 0, + "IMAGE" + ], + [ + 14, + 12, + 0, + 14, + 2, + "IMAGE" + ], + [ + 15, + 11, + 0, + 15, + 0, + "IMAGE" + ], + [ + 16, + 12, + 0, + 20, + 0, + "IMAGE" + ], + [ + 17, + 19, + 0, + 22, + 0, + "IMAGE" + ], + [ + 18, + 10, + 0, + 22, + 1, + "VAE" + ], + [ + 19, + 14, + 0, + 3, + 1, + "CONDITIONING" + ], + [ + 20, + 6, + 0, + 3, + 2, + "CONDITIONING" + ], + [ + 21, + 7, + 0, + 3, + 3, + "LATENT" + ] + ], + "groups": [], + "config": {}, + "extra": { + "groupNodes": {} + }, + "version": 0.4 +} \ No newline at end of file diff --git a/SDNode/resource/solutions/EN/Mat2Stone(Canny&Tile).blend b/SDNode/resource/solutions/EN/Mat2Stone(Canny&Tile).blend new file mode 100644 index 0000000..5c79a58 Binary files /dev/null and b/SDNode/resource/solutions/EN/Mat2Stone(Canny&Tile).blend differ diff --git a/SDNode/resource/solutions/EN/Mat2Stone(Canny&Tile).jpg b/SDNode/resource/solutions/EN/Mat2Stone(Canny&Tile).jpg new file mode 100644 index 0000000..a9dcf39 Binary files /dev/null and b/SDNode/resource/solutions/EN/Mat2Stone(Canny&Tile).jpg differ diff --git a/SDNode/resource/solutions/EN/Mat2Stone(Canny&Tile).json b/SDNode/resource/solutions/EN/Mat2Stone(Canny&Tile).json new file mode 100644 index 0000000..04623d9 --- /dev/null +++ b/SDNode/resource/solutions/EN/Mat2Stone(Canny&Tile).json @@ -0,0 +1,957 @@ +{ + "last_node_id": 22, + "last_link_id": 22, + "nodes": [ + { + "id": 10, + "type": "VAELoader", + "pos": [ + 724, + 1154 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "VAE", + "type": "VAE", + "links": [ + 5, + 18 + ], + "slot_index": 0 + } + ], + "title": "VAE加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "pastel-waifu-diffusion.vae.pt" + ] + }, + { + "id": 11, + "type": "AIO_Preprocessor", + "pos": [ + -485, + 1474 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 12, + "label": "image" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 11, + 15 + ], + "slot_index": 0 + } + ], + "title": "AIO_Preprocessor", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "CannyEdgePreprocessor", + 512 + ] + }, + { + "id": 12, + "type": "AIO_Preprocessor", + "pos": [ + -117, + 1692 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 13, + "label": "image" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 14, + 16 + ], + "slot_index": 0 + } + ], + "title": "AIO_Preprocessor.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "TilePreprocessor", + 1024 + ] + }, + { + "id": 13, + "type": "ControlNetLoader", + "pos": [ + -7, + 1349 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 6 + ], + "slot_index": 0 + } + ], + "title": "ControlNetLoader", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11f1e_sd15_tile.pth" + ] + }, + { + "id": 14, + "type": "ControlNetApply", + "pos": [ + 381, + 1197 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 14, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 8, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 6, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 14, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 19 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 15, + "type": "PreviewImage", + "pos": [ + -509, + 1661 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 11, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 15, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用).001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 16, + "type": "存储", + "pos": [ + 1468, + 461 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 18, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 7, + "label": "images" + } + ], + "outputs": [], + "title": "ToMatImage", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "ComfyUI", + "" + ] + }, + { + "id": 17, + "type": "ControlNetApply", + "pos": [ + -7, + 1164 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 9, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 10, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 11, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 8 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 18, + "type": "ControlNetLoader", + "pos": [ + -482, + 1264 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 10 + ], + "slot_index": 0 + } + ], + "title": "ControlNetLoader.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_canny.pth" + ] + }, + { + "id": 19, + "type": "输入图像", + "pos": [ + -855, + 1464 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 12, + 13, + 17 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像.001", + "properties": { + "sdn_hide": false, + "label": "(COLOR)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_大理石胸像01_Copyac241_COLOR.png", + "输入" + ] + }, + { + "id": 20, + "type": "PreviewImage", + "pos": [ + 149, + 1632 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 16, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用).002", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 22, + "type": "VAEEncode", + "pos": [ + 559, + 1683 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "pixels", + "type": "IMAGE", + "link": 17, + "label": "pixels" + }, + { + "name": "vae", + "type": "VAE", + "link": 18, + "label": "vae" + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [], + "slot_index": 0 + } + ], + "title": "VAE编码", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 3, + "type": "KSampler", + "pos": [ + 816, + 570 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 15, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 2, + "label": "model" + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": 19, + "label": "positive" + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": 20, + "label": "negative" + }, + { + "name": "latent_image", + "type": "LATENT", + "link": 21, + "label": "latent_image" + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 3 + ], + "slot_index": 0 + } + ], + "title": "K采样器", + "properties": { + "sdn_hide": false, + "label": "003" + }, + "widgets_values": [ + "2445975910", + "fixed", + 20, + 8.0, + "euler", + "karras", + 1.0 + ] + }, + { + "id": 4, + "type": "CheckpointLoaderSimple", + "pos": [ + -705, + 882 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 2 + ], + "slot_index": 0 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [ + 0, + 1 + ], + "slot_index": 1 + }, + { + "name": "VAE", + "type": "VAE", + "links": [], + "slot_index": 2 + } + ], + "title": "CheckpointLoaderSimple", + "properties": { + "sdn_hide": false, + "label": "001" + }, + "widgets_values": [ + "GuoFeng3.2_f16.safetensors" + ] + }, + { + "id": 5, + "type": "CLIPTextEncode", + "pos": [ + -356, + 610 + ], + "size": { + "0": 347, + "1": 30 + }, + "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 0, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 9 + ], + "slot_index": 0 + } + ], + "title": "CLIPTextEncode(Positive)", + "properties": { + "sdn_hide": false, + "label": "002" + }, + "widgets_values": [ + "stone" + ] + }, + { + "id": 6, + "type": "CLIPTextEncode", + "pos": [ + 20, + 991 + ], + "size": { + "0": 306, + "1": 30 + }, + "flags": {}, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 1, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 20 + ], + "slot_index": 0 + } + ], + "title": "CLIPTextEncode(Negative)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "embedding:EasyNegative" + ] + }, + { + "id": 7, + "type": "EmptyLatentImage", + "pos": [ + 381, + 1395 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 21 + ], + "slot_index": 0 + } + ], + "title": "空Latent图像", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1024, + 1024, + 1 + ] + }, + { + "id": 8, + "type": "VAEDecode", + "pos": [ + 1168, + 926 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 16, + "mode": 0, + "inputs": [ + { + "name": "samples", + "type": "LATENT", + "link": 3, + "label": "samples" + }, + { + "name": "vae", + "type": "VAE", + "link": 5, + "label": "vae" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 4, + 7 + ], + "slot_index": 0 + } + ], + "title": "VAE解码", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 9, + "type": "PreviewImage", + "pos": [ + 1468, + 661 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 17, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 4, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + } + ], + "links": [ + [ + 0, + 4, + 1, + 5, + 0, + "CLIP" + ], + [ + 1, + 4, + 1, + 6, + 0, + "CLIP" + ], + [ + 2, + 4, + 0, + 3, + 0, + "MODEL" + ], + [ + 3, + 3, + 0, + 8, + 0, + "LATENT" + ], + [ + 4, + 8, + 0, + 9, + 0, + "IMAGE" + ], + [ + 5, + 10, + 0, + 8, + 1, + "VAE" + ], + [ + 6, + 13, + 0, + 14, + 1, + "CONTROL_NET" + ], + [ + 7, + 8, + 0, + 16, + 0, + "IMAGE" + ], + [ + 8, + 17, + 0, + 14, + 0, + "CONDITIONING" + ], + [ + 9, + 5, + 0, + 17, + 0, + "CONDITIONING" + ], + [ + 10, + 18, + 0, + 17, + 1, + "CONTROL_NET" + ], + [ + 11, + 11, + 0, + 17, + 2, + "IMAGE" + ], + [ + 12, + 19, + 0, + 11, + 0, + "IMAGE" + ], + [ + 13, + 19, + 0, + 12, + 0, + "IMAGE" + ], + [ + 14, + 12, + 0, + 14, + 2, + "IMAGE" + ], + [ + 15, + 11, + 0, + 15, + 0, + "IMAGE" + ], + [ + 16, + 12, + 0, + 20, + 0, + "IMAGE" + ], + [ + 17, + 19, + 0, + 22, + 0, + "IMAGE" + ], + [ + 18, + 10, + 0, + 22, + 1, + "VAE" + ], + [ + 19, + 14, + 0, + 3, + 1, + "CONDITIONING" + ], + [ + 20, + 6, + 0, + 3, + 2, + "CONDITIONING" + ], + [ + 21, + 7, + 0, + 3, + 3, + "LATENT" + ] + ], + "groups": [], + "config": {}, + "extra": { + "groupNodes": {} + }, + "version": 0.4 +} \ No newline at end of file diff --git a/SDNode/resource/solutions/EN/_default.json b/SDNode/resource/solutions/EN/_default.json new file mode 100644 index 0000000..c123d7e --- /dev/null +++ b/SDNode/resource/solutions/EN/_default.json @@ -0,0 +1,763 @@ +{ + "last_node_id": 19, + "last_link_id": 16, + "nodes": [ + { + "id": 10, + "type": "VAELoader", + "pos": [ + 817, + 1253 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "VAE", + "type": "VAE", + "links": [ + 7 + ], + "slot_index": 0 + } + ], + "title": "VAE加载器", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "pastel-waifu-diffusion.vae.pt" + ] + }, + { + "id": 12, + "type": "输入图像", + "pos": [ + -17, + 1501 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 11 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像", + "properties": { + "sdn_hide": false, + "label": "(NORMAL)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_大理石胸像01_Copyac241_NORMAL.png", + "输入" + ] + }, + { + "id": 13, + "type": "ControlNetLoader", + "pos": [ + -2, + 1281 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 8 + ], + "slot_index": 0 + } + ], + "title": "ControlNetLoader", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_normalbae.pth" + ] + }, + { + "id": 14, + "type": "ControlNetApply", + "pos": [ + 389, + 1138 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 12, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 8, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 11, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 9 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 16, + "type": "存储", + "pos": [ + 1476, + 402 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 14, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 10, + "label": "images" + } + ], + "outputs": [], + "title": "ToMatImage", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "ComfyUI", + "" + ] + }, + { + "id": 17, + "type": "ControlNetApply", + "pos": [ + 6, + 1105 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "conditioning", + "type": "CONDITIONING", + "link": 13, + "label": "conditioning" + }, + { + "name": "control_net", + "type": "CONTROL_NET", + "link": 14, + "label": "control_net" + }, + { + "name": "image", + "type": "IMAGE", + "link": 15, + "label": "image" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 12 + ], + "slot_index": 0 + } + ], + "title": "ControlNet应用.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1.0 + ] + }, + { + "id": 18, + "type": "ControlNetLoader", + "pos": [ + -384, + 1191 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "CONTROL_NET", + "type": "CONTROL_NET", + "links": [ + 14 + ], + "slot_index": 0 + } + ], + "title": "ControlNetLoader.001", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "SD1.5\\control_v11p_sd15_depth.pth" + ] + }, + { + "id": 19, + "type": "输入图像", + "pos": [ + -443, + 1409 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 15 + ], + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "slot_index": 1 + } + ], + "title": "输入图像.001", + "properties": { + "sdn_hide": false, + "label": "(DEPTH)" + }, + "widgets_values": [ + "C:/Users/NIER/AppData/Local/Temp/_gen_大理石胸像01_Copyac241_DEPTH.png", + "输入" + ] + }, + { + "id": 3, + "type": "KSampler", + "pos": [ + 824, + 511 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 11, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 3, + "label": "model" + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": 9, + "label": "positive" + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": 1, + "label": "negative" + }, + { + "name": "latent_image", + "type": "LATENT", + "link": 4, + "label": "latent_image" + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 5 + ], + "slot_index": 0 + } + ], + "title": "K采样器", + "properties": { + "sdn_hide": false, + "label": "003" + }, + "widgets_values": [ + "2791066226", + "fixed", + 20, + 8.0, + "euler", + "karras", + 1.0 + ] + }, + { + "id": 4, + "type": "CheckpointLoaderSimple", + "pos": [ + -698, + 823 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 3 + ], + "slot_index": 0 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [ + 0, + 2 + ], + "slot_index": 1 + }, + { + "name": "VAE", + "type": "VAE", + "links": [], + "slot_index": 2 + } + ], + "title": "CheckpointLoaderSimple", + "properties": { + "sdn_hide": false, + "label": "001" + }, + "widgets_values": [ + "GuoFeng3.2_f16.safetensors" + ] + }, + { + "id": 5, + "type": "CLIPTextEncode", + "pos": [ + -459, + 1008 + ], + "size": { + "0": 347, + "1": 30 + }, + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 0, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 13 + ], + "slot_index": 0 + } + ], + "title": "CLIPTextEncode(Positive)", + "properties": { + "sdn_hide": false, + "label": "002" + }, + "widgets_values": [ + "Model, Masterpiece, Best Quality, Octane Rendering, UE5 Rendering, Realistic, Film and Television Grade" + ] + }, + { + "id": 6, + "type": "CLIPTextEncode", + "pos": [ + -129, + 764 + ], + "size": { + "0": 306, + "1": 30 + }, + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 2, + "label": "clip" + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 1 + ], + "slot_index": 0 + } + ], + "title": "CLIPTextEncode(Negative)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + "embedding:EasyNegative" + ] + }, + { + "id": 7, + "type": "EmptyLatentImage", + "pos": [ + 389, + 1336 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 4 + ], + "slot_index": 0 + } + ], + "title": "空Latent图像", + "properties": { + "sdn_hide": false + }, + "widgets_values": [ + 1024, + 1024, + 1 + ] + }, + { + "id": 8, + "type": "VAEDecode", + "pos": [ + 1176, + 867 + ], + "size": { + "0": 200, + "1": 30 + }, + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [ + { + "name": "samples", + "type": "LATENT", + "link": 5, + "label": "samples" + }, + { + "name": "vae", + "type": "VAE", + "link": 7, + "label": "vae" + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 6, + 10 + ], + "slot_index": 0 + } + ], + "title": "VAE解码", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + }, + { + "id": 9, + "type": "PreviewImage", + "pos": [ + 1476, + 602 + ], + "size": { + "0": 256, + "1": 30 + }, + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 6, + "label": "images" + } + ], + "outputs": [], + "title": "预览(Blender专用)", + "properties": { + "sdn_hide": false + }, + "widgets_values": [] + } + ], + "links": [ + [ + 0, + 4, + 1, + 5, + 0, + "CLIP" + ], + [ + 1, + 6, + 0, + 3, + 2, + "CONDITIONING" + ], + [ + 2, + 4, + 1, + 6, + 0, + "CLIP" + ], + [ + 3, + 4, + 0, + 3, + 0, + "MODEL" + ], + [ + 4, + 7, + 0, + 3, + 3, + "LATENT" + ], + [ + 5, + 3, + 0, + 8, + 0, + "LATENT" + ], + [ + 6, + 8, + 0, + 9, + 0, + "IMAGE" + ], + [ + 7, + 10, + 0, + 8, + 1, + "VAE" + ], + [ + 8, + 13, + 0, + 14, + 1, + "CONTROL_NET" + ], + [ + 9, + 14, + 0, + 3, + 1, + "CONDITIONING" + ], + [ + 10, + 8, + 0, + 16, + 0, + "IMAGE" + ], + [ + 11, + 12, + 0, + 14, + 2, + "IMAGE" + ], + [ + 12, + 17, + 0, + 14, + 0, + "CONDITIONING" + ], + [ + 13, + 5, + 0, + 17, + 0, + "CONDITIONING" + ], + [ + 14, + 18, + 0, + 17, + 1, + "CONTROL_NET" + ], + [ + 15, + 19, + 0, + 17, + 2, + "IMAGE" + ] + ], + "groups": [], + "config": {}, + "extra": { + "groupNodes": {} + }, + "version": 0.4 +} \ No newline at end of file diff --git a/SDNode/rt_tracker.py b/SDNode/rt_tracker.py index 57e167b..0577774 100644 --- a/SDNode/rt_tracker.py +++ b/SDNode/rt_tracker.py @@ -4,6 +4,7 @@ from functools import lru_cache from time import time from ..preference import get_pref +from .manager import TaskManager from .utils import get_default_tree @@ -22,7 +23,9 @@ def __init__(self) -> None: self.last_time = 0 self._init = True - def update_deps(self, depsgraph): + def update_deps(self, depsgraph: bpy.types.Depsgraph): + if depsgraph.id_type_updated("NODETREE"): + return check_list = ["MESH", "OBJECT", "COLLECTION"] for i in check_list: if not depsgraph.id_type_updated(i): @@ -57,7 +60,6 @@ def exec(self): tstatus = self.get_status() if not tstatus: return - from .manager import TaskManager qr_num = len(TaskManager.query_server_task().get('queue_running', [])) qp_num = TaskManager.get_task_num() if qp_num or qr_num: diff --git a/SDNode/tree.py b/SDNode/tree.py index c9ddc4f..dc95bf7 100644 --- a/SDNode/tree.py +++ b/SDNode/tree.py @@ -105,8 +105,15 @@ class CFNodeTree(NodeTree): outUpdate: bpy.props.BoolProperty(default=False) root: bpy.props.BoolProperty(default=True) freeze: bpy.props.BoolProperty(default=False, description="冻结更新") + sdn_time_code: bpy.props.StringProperty(default="0") __metadata__ = {} + def set_sdn_time_code(self): + if self.sdn_time_code != "0": + return + self.sdn_time_code = str(time.time_ns()) + logger.info(f"Set Tree Time Code {self.sdn_time_code}") + class Pool: def __init__(self, tree: CFNodeTree) -> None: self.tree = tree @@ -693,6 +700,7 @@ def update_tick(self): self.primitive_node_update(node) self.dirty_nodes_update(node) self.group_nodes_update(node) + self.set_width_update(node) def id_clear_update(self): ids = set() @@ -707,6 +715,10 @@ def id_clear_update(self): pool.clear() pool.update(ids) + def set_width_update(self, node: NodeBase): + bp = node.get_blueprints() + bp.set_width(node) + def primitive_node_update(self, node: NodeBase): from .nodes import get_reg_name if node.bl_idname != "PrimitiveNode": @@ -916,6 +928,7 @@ def switch_tree_update(): group: CFNodeTree = group if group.bl_idname != TREE_TYPE: continue + group.set_sdn_time_code() for node in group.get_nodes(): node.update() @@ -933,6 +946,22 @@ def reg_switch_update(): def unreg_switch_update(): bpy.msgbus.clear_by_owner(CFNodeTree) + @staticmethod + def update_tree_handler(): + try: + for group in bpy.data.node_groups: + group: CFNodeTree = group + if group.bl_idname != TREE_TYPE: + continue + group.update_tick() + except ReferenceError: + ... + except Exception as e: + # logger.warn(str(e)) + traceback.print_exc() + logger.error(f"{type(e).__name__}: {e}") + return 1 + class CFNodeCategory(NodeCategory): @@ -1114,22 +1143,6 @@ def reg_class_internal(): bpy.types.NodeFrame.class_type = "NodeFrame" -def update_tree_handler(): - try: - for group in bpy.data.node_groups: - group: CFNodeTree = group - if group.bl_idname != TREE_TYPE: - continue - group.update_tick() - except ReferenceError: - ... - except Exception as e: - # logger.warn(str(e)) - traceback.print_exc() - logger.error(f"{type(e).__name__}: {e}") - return 1 - - def draw_intern(self, context): layout: bpy.types.UILayout = self.layout props = layout.operator("node.add_node", text="NodeFrame", text_ctxt=ctxt) @@ -1209,12 +1222,11 @@ def rtnode_reg(): set_draw_intern(reg=True) if CFNodeTree.reinit not in bpy.app.handlers.load_post: bpy.app.handlers.load_post.append(CFNodeTree.reinit) - if not bpy.app.timers.is_registered(update_tree_handler): - bpy.app.timers.register(update_tree_handler, persistent=True) + if not bpy.app.timers.is_registered(CFNodeTree.update_tree_handler): + bpy.app.timers.register(CFNodeTree.update_tree_handler, persistent=True) def rtnode_unreg(): - # bpy.app.timers.unregister(update_tree_handler) if CFNodeTree.reinit in bpy.app.handlers.load_post: bpy.app.handlers.load_post.remove(CFNodeTree.reinit) set_draw_intern(reg=False) diff --git a/SDNode/utils.py b/SDNode/utils.py index 9d3e324..939c773 100644 --- a/SDNode/utils.py +++ b/SDNode/utils.py @@ -307,6 +307,58 @@ def find_node_ex(self, link: bpy.types.NodeLink, is_from, find_link=False, with_ return link if find_link else node +class WindowLogger: + _logs = [] + _window = None + + @classmethod + def push_log(cls, pattern, *msg): + s = pattern % msg + cls._logs.append(s) + cls.move_cursor_to_last() + text = cls.get_text() + text.write(s + "\n") + + @classmethod + def move_cursor_to_last(cls): + text = cls.get_text() + if not text: + return + text.cursor_set(len(text.lines), character=2**30) + + @classmethod + def clear(cls): + text = cls.get_text() + text.clear() + cls._logs.clear() + cls._window = None + + @classmethod + def init(cls): + text = cls.get_text() + text.clear() + + @classmethod + def get_text(cls) -> bpy.types.Text: + if "ComfyUI Log" not in bpy.data.texts: + bpy.data.texts.new("ComfyUI Log") + return bpy.data.texts.get("ComfyUI Log") + + @classmethod + def open_window(cls): + text = cls.get_text() + cls.move_cursor_to_last() + if not text: + return + bpy.ops.wm.window_new() + cls._window = bpy.context.window_manager.windows[-1] + area = cls._window.screen.areas[0] + area.type = "TEXT_EDITOR" + area.spaces[0].text = text + area.spaces[0].show_word_wrap = True + bpy.ops.text.jump(line=1) + + def get_default_tree(context=None) -> bpy.types.NodeTree: if context is None: context = bpy.context diff --git a/__init__.py b/__init__.py index ceb76a5..c367687 100644 --- a/__init__.py +++ b/__init__.py @@ -1,7 +1,7 @@ bl_info = { 'name': 'ComfyUI Node Editor', 'author': '幻之境开发小组-会飞的键盘侠、只剩一瓶辣椒酱、a-One-Fan、DorotaLuna、hugeproblem、heredos、ra100', - 'version': (1, 5, 7), + 'version': (1, 6, 0), 'blender': (3, 0, 0), 'location': '3DView->Panel', 'category': 'AI', @@ -38,22 +38,25 @@ def clear_pyc(path=None, depth=2): from .SDNode import rtnode_unreg, TaskManager from .MultiLineText import EnableMLT -from .utils import Icon, FSWatcher, ScopeTimer +from .utils import Icon, FSWatcher, ScopeTimer, addon_bl_info from .timer import timer_reg, timer_unreg from .preference import pref_register, pref_unregister -from .ops import Ops, Ops_Mask, Load_History, Popup_Load, Copy_Tree, Load_Batch, Fetch_Node_Status, Clear_Node_Cache, Sync_Stencil_Image, NodeSearch, SDNode_To_Image, Image_To_SDNode, Image_Set_Channel_Packed +from .ops import Ops, Ops_Mask, Load_History, Popup_Load, Copy_Tree, Load_Batch, Fetch_Node_Status, Clear_Node_Cache, Sync_Stencil_Image, NodeSearch, SDNode_To_Image, Image_To_SDNode, Image_Set_Channel_Packed, Open_Log_Window from .ui import ui_reg, ui_unreg, Panel, HISTORY_UL_UIList, HistoryItem from .SDNode.history import History from .SDNode.rt_tracker import reg_tracker, unreg_tracker from .SDNode.nodegroup import nodegroup_reg, nodegroup_unreg +from .SDNode.operators import ops_register, ops_unregister from .SDNode.custom_support import custom_support_reg, custom_support_unreg from .prop import RenderLayerString, MLTWord, Prop from .Linker import linker_register, linker_unregister from .hook import use_hook -clss = [Panel, Ops, RenderLayerString, MLTWord, Prop, HISTORY_UL_UIList, HistoryItem, Ops_Mask, Load_History, Popup_Load, Copy_Tree, Load_Batch, Fetch_Node_Status, Clear_Node_Cache, Sync_Stencil_Image, NodeSearch, SDNode_To_Image, Image_To_SDNode, Image_Set_Channel_Packed, EnableMLT] +clss = [Panel, Ops, RenderLayerString, MLTWord, Prop, HISTORY_UL_UIList, HistoryItem, Ops_Mask, Load_History, Popup_Load, Copy_Tree, Load_Batch, Fetch_Node_Status, Clear_Node_Cache, Sync_Stencil_Image, NodeSearch, SDNode_To_Image, Image_To_SDNode, Image_Set_Channel_Packed, Open_Log_Window, EnableMLT] reg, unreg = bpy.utils.register_classes_factory(clss) from platform import system +addon_bl_info.update(bl_info) + def dump_info(): import json @@ -124,12 +127,14 @@ def register(): bpy.types.Scene.sdn = bpy.props.PointerProperty(type=Prop) bpy.types.Scene.sdn_history_item = bpy.props.CollectionProperty(type=HistoryItem) bpy.types.Scene.sdn_history_item_index = bpy.props.IntProperty(default=0) + bpy.types.Node.ac_expand = bpy.props.BoolProperty(name="Expand", default=True) History.register_timer() linker_register() use_hook() FSWatcher.init() disable_reload() nodegroup_reg() + ops_register() custom_support_reg() print(f"{__package__} Launch Time: {time.time() - ts:.4f}s") @@ -153,6 +158,7 @@ def unregister(): modules_update() linker_unregister() use_hook(False) + ops_unregister() nodegroup_unreg() custom_support_unreg() FSWatcher.stop() diff --git a/ops.py b/ops.py index ba4bb48..33e5cf8 100644 --- a/ops.py +++ b/ops.py @@ -17,7 +17,7 @@ from .SDNode import TaskManager from .SDNode.history import History from .SDNode.tree import InvalidNodeType, CFNodeTree, TREE_TYPE, rtnode_reg, rtnode_unreg -from .SDNode.utils import get_default_tree +from .SDNode.utils import get_default_tree, WindowLogger from .datas import IMG_SUFFIX from .preference import get_pref @@ -190,6 +190,7 @@ def submit(self): return tree.reset_error_mark() + WindowLogger.clear() if bpy.context.scene.sdn.advanced_exe and not Ops.is_advanced_enable: Ops.is_advanced_enable = True @@ -1104,6 +1105,15 @@ def execute(self, context): return {'FINISHED'} +class Open_Log_Window(bpy.types.Operator): + bl_idname = "sdn.open_log_window" + bl_label = "" + + def execute(self, context: bpy.types.Context): + WindowLogger.open_window() + return {'FINISHED'} + + @bpy.app.handlers.persistent def clear(_): Ops.is_advanced_enable = False diff --git a/preference.py b/preference.py index 4c5776d..e13c354 100644 --- a/preference.py +++ b/preference.py @@ -196,7 +196,7 @@ def preview_method_update(self, context): disable_ipex_optimize: bpy.props.BoolProperty(default=False, name="disable ipex optimize", description="Disables ipex.optimize when loading models with Intel GPUs.") # --disable-ipex-optimize attn: bpy.props.EnumProperty(name="attn", - default="--use-pytorch-cross-attention", + default="default", items=[("default", "Auto", "", 0), ("--use-split-cross-attention", "split-cross-attention", "Use the split cross attention optimization. Ignored when xformers is used.", 1), ("--use-quad-cross-attention", "quad-cross-attention", "Use the sub-quadratic cross attention optimization . Ignored when xformers is used.", 2), @@ -413,6 +413,8 @@ def parse_server_args(self, server=None): args.append("--disable-metadata") if self.windows_standalone_build: args.append("--windows-standalone-build") + # args.append("--front-end-version") + # args.append("Comfy-Org/ComfyUI_frontend@latest") return args def update_count_page_next(self, context): diff --git a/prop.py b/prop.py index cd58e3f..c3d6d89 100644 --- a/prop.py +++ b/prop.py @@ -7,7 +7,7 @@ from .MultiLineText.trie import Trie from .preference import get_pref -from .utils import Icon, FSWatcher, ScopeTimer +from .utils import Icon, FSWatcher, ScopeTimer, popup_folder, get_bl_info, get_ai_mat_tree from .datas import PRESETS_DIR, PROP_CACHE, GROUPS_DIR, IMG_SUFFIX FSWatcher.register(PRESETS_DIR) @@ -26,13 +26,15 @@ class MLTWord(bpy.types.PropertyGroup): class Prop(bpy.types.PropertyGroup): cache = PROP_CACHE - def mark_dirty(): - Prop.cache["presets_dir"].clear() - Prop.cache["groups_dir"].clear() - Prop.cache["presets"].clear() - Prop.cache["groups"].clear() + @classmethod + def mark_dirty(cls): + cls.cache["presets_dir"].clear() + cls.cache["groups_dir"].clear() + cls.cache["presets"].clear() + cls.cache["groups"].clear() - def update_prop_cache(search_dir: list[Path], t="presets"): + @classmethod + def update_prop_cache(cls, search_dir: list[Path], t="presets"): items = [] for item in get_pref().pref_dirs: if not item.enabled: @@ -42,7 +44,7 @@ def update_prop_cache(search_dir: list[Path], t="presets"): continue search_dir.append(dirpath) changed = [FSWatcher.consume_change(dp) for dp in search_dir] - if Prop.cache[f"{t}_dir"] and not any(changed): # 没有改变 + if cls.cache[f"{t}_dir"] and not any(changed): # 没有改变 return # 有改变 for dirpath in search_dir: @@ -59,19 +61,20 @@ def update_prop_cache(search_dir: list[Path], t="presets"): items.append((fpath, f"{p.name} {dpn}", abspath, len(items))) if items: items.sort(key=lambda x: x[1]) - Prop.cache[f"{t}_dir"].clear() - Prop.cache[f"{t}_dir"].extend(items) + cls.cache[f"{t}_dir"].clear() + cls.cache[f"{t}_dir"].extend(items) def presets_dir_items(self, context): # t = ScopeTimer("presets_dir_items") - Prop.update_prop_cache([PRESETS_DIR], "presets") - return Prop.cache["presets_dir"] + self.update_prop_cache([PRESETS_DIR], "presets") + return self.cache["presets_dir"] + presets_dir: bpy.props.EnumProperty(items=presets_dir_items, name="Presets Directory") def presets_items(self, context): pd = FSWatcher.to_path(self.presets_dir) - if Prop.cache["presets"].get(pd) and not FSWatcher.consume_change(pd): - return Prop.cache["presets"][pd] + if self.cache["presets"].get(pd) and not FSWatcher.consume_change(pd): + return self.cache["presets"][pd] items = [] if not pd.exists(): return items @@ -85,27 +88,27 @@ def presets_items(self, context): icon_id = Icon.reg_icon(img) items.append((str(file), file.stem, "", icon_id, len(items))) items.sort(key=lambda x: x[1]) - Prop.cache["presets"][pd] = items - return Prop.cache["presets"][pd] + self.cache["presets"][pd] = items + return self.cache["presets"][pd] presets: bpy.props.EnumProperty(items=presets_items, name="Presets") def update_open_presets_dir(self, context): if self.open_presets_dir: self.open_presets_dir = False - os.startfile(str(PRESETS_DIR)) + popup_folder(PRESETS_DIR) open_presets_dir: bpy.props.BoolProperty(default=False, name="Open NodeGroup Presets Folder", update=update_open_presets_dir) def groups_dir_items(self, context): - Prop.update_prop_cache([GROUPS_DIR], "groups") - return Prop.cache["groups_dir"] + self.update_prop_cache([GROUPS_DIR], "groups") + return self.cache["groups_dir"] groups_dir: bpy.props.EnumProperty(items=groups_dir_items, name="Groups Directory") def groups_items(self, context): gd = FSWatcher.to_path(self.groups_dir) - if Prop.cache["groups"].get(gd) and not FSWatcher.consume_change(gd): - return Prop.cache["groups"][gd] + if self.cache["groups"].get(gd) and not FSWatcher.consume_change(gd): + return self.cache["groups"][gd] items = [] if not gd.exists(): return items @@ -119,19 +122,20 @@ def groups_items(self, context): icon_id = Icon.reg_icon(img) items.append((str(file), file.stem, "", icon_id, len(items))) items.sort(key=lambda x: x[1]) - Prop.cache["groups"][gd] = items - return Prop.cache["groups"][gd] + self.cache["groups"][gd] = items + return self.cache["groups"][gd] + groups: bpy.props.EnumProperty(items=groups_items, name="Presets") def update_open_groups_dir(self, context): if self.open_groups_dir: self.open_groups_dir = False - os.startfile(str(GROUPS_DIR)) + popup_folder(GROUPS_DIR) open_groups_dir: bpy.props.BoolProperty(default=False, name="Open NodeTree Presets Folder", update=update_open_groups_dir) def open_pref_update(self, context): - from . import bl_info + bl_info = get_bl_info() if self.open_pref: self.open_pref = False category = bl_info.get('category') @@ -229,7 +233,8 @@ def import_bookmark_update(self, context): def search_tag_update(self, context): from .MultiLineText.words_collection import words from .kclogger import logger - if not Trie.TRIE: return + if not Trie.TRIE: + return mtw = bpy.context.window_manager.mlt_words mtw.clear() ts = time.time() @@ -250,6 +255,107 @@ def search_tag_update(self, context): search_tag: bpy.props.StringProperty(update=search_tag_update) + LANG_SUFFIXES = { + "en_US": "EN", + "zh_CN": "CN", + "zh_HANS": "CN", + } + + @classmethod + def _get_locale(cls): + if not bpy.context.preferences.view.use_translate_interface: + return "en_US" + return bpy.app.translations.locale + + @classmethod + def _get_locale_suffix(cls): + return cls.LANG_SUFFIXES.get(cls._get_locale(), "EN") + + @classmethod + def get_resource_dir(cls) -> Path: + return Path(__file__).parent / "SDNode/resource" + + @classmethod + def get_solution_dir(cls) -> Path: + return cls.get_resource_dir() / "solutions" / cls._get_locale_suffix() + + @classmethod + def find_icon(cls, name: str, path: Path) -> Path: + SUFFIXES = [".png", ".jpg", ".jpeg", ".tiff"] + for suf in SUFFIXES: + img = path.joinpath(name).with_suffix(suf) + if not img.exists(): + continue + return img + return cls.get_resource_dir().joinpath("icons/none.jpeg") + + _ref_items = {} + + def ai_gen_solution_items(self, context): + rdir = self.get_solution_dir() + FSWatcher.register(rdir) + if not FSWatcher.consume_change(rdir) and rdir in self._ref_items: + return self._ref_items.get(rdir, []) + items = [] + self._ref_items[rdir] = items + for f in sorted(rdir.glob("*.blend"), key=lambda x: x.name): + icon_path = self.find_icon(f.stem, rdir) + Icon.reg_icon(icon_path.as_posix(), hq=True) + icon_id = Icon.get_icon_id(icon_path) + items.append((f.as_posix(), f.stem, f.stem, icon_id, len(items))) + return self._ref_items.get(rdir, []) + + ai_gen_solution: bpy.props.EnumProperty(name="AI Mat Solution", items=ai_gen_solution_items) + clear_material_slots: bpy.props.BoolProperty(name="Clear Material Slots", default=True) + + def update_open_ai_sol_dir(self, context): + if self.open_ai_sol_dir: + self.open_ai_sol_dir = False + popup_folder(self.get_solution_dir()) + + open_ai_sol_dir: bpy.props.BoolProperty(default=False, name="Open NodeTree Presets Folder", update=update_open_ai_sol_dir) + + def update_ai_mat_tex_size(self, context): + if self.ai_mat_tex_size % 32 == 0: + return + self.ai_mat_tex_size = self.ai_mat_tex_size // 32 * 32 + + ai_mat_tex_size: bpy.props.IntProperty(name="AI Mat Tex Size", default=1024, min=64, max=2**16, step=32, update=update_ai_mat_tex_size) + + _bake_trees = [] + + def tree_items(self, context): + trees = [] + for node_group in bpy.data.node_groups: + if node_group.bl_idname != "BakeNodeTree": + continue + trees.append((node_group.name, node_group.name, node_group.name)) + if trees: + self._bake_trees.clear() + self._bake_trees.extend(trees) + return self._bake_trees + + bake_tree: bpy.props.EnumProperty(items=tree_items) + + send_ai_tree_to_editor: bpy.props.BoolProperty(name="Sync AI Mat Tree to Editor", default=False) + + apply_bake_pass: bpy.props.EnumProperty(items=[("COMBINED", "Combined", "", "NONE", 2 ** 0), + ("AO", "Ambient Occlusion", "", "NONE", 2 ** 1), + ("SHADOW", "Shadow", "", "NONE", 2 ** 2), + ("POSITION", "Position", "", "NONE", 2 ** 3), + ("NORMAL", "Normal", "", "NONE", 2 ** 4), + ("UV", "UV", "", "NONE", 2 ** 5), + ("ROUGHNESS", "Roughness", "", "NONE", 2 ** 6), + ("EMIT", "Emit", "", "NONE", 2 ** 7), + ("ENVIRONMENT", "Environment", "", "NONE", 2 ** 8), + ("DIFFUSE", "Diffuse", "", "NONE", 2 ** 9), + ("GLOSSY", "Glossy", "", "NONE", 2 ** 10), + ("TRANSMISSION", "Transmission", "", "NONE", 2 ** 11), + ], + default="COMBINED", + name="Pass") + + def render_layer_update(): try: bpy.context.scene.sdn.render_layer.clear() @@ -265,4 +371,32 @@ def render_layer_update(): return 1 +def send_ai_tree_to_editor(): + if not bpy.context.object: + return 1 + node_tree = get_ai_mat_tree(bpy.context.object) + if not bpy.context.scene.sdn.send_ai_tree_to_editor or not node_tree: + return 1 + + from .SDNode.tree import TREE_TYPE + for area in bpy.context.screen.areas: + for space in area.spaces: + if space.type != "NODE_EDITOR" or space.tree_type != TREE_TYPE: + continue + try: + if space.node_tree != node_tree: + space.node_tree = node_tree + except BaseException: + ... + return 1 + + +@bpy.app.handlers.persistent +def clear_cache(_): + Icon.clear() + Prop._ref_items.clear() + + bpy.app.timers.register(render_layer_update, persistent=True) +bpy.app.timers.register(send_ai_tree_to_editor, persistent=True) +bpy.app.handlers.load_post.append(clear_cache) diff --git a/timer.py b/timer.py index 0c9c465..3aa0752 100644 --- a/timer.py +++ b/timer.py @@ -8,37 +8,49 @@ class Timer: TimerQueue = Queue() TimerQueue2 = Queue() - - @staticmethod - def put(delegate: Any): - Timer.TimerQueue.put(delegate) - - @staticmethod - def put2(delegate: Any): - Timer.TimerQueue2.put(delegate) - - @staticmethod - def executor(t): + stoped = False + + @classmethod + def put(cls, delegate: Any): + if cls.stoped: + return + cls.TimerQueue.put(delegate) + + @classmethod + def put2(cls, delegate: Any): + if cls.stoped: + return + cls.TimerQueue2.put(delegate) + + @classmethod + def executor(cls, t): if type(t) in {list, tuple}: t[0](*t[1:]) else: t() - @staticmethod - def run1(): - return Timer.run_ex(Timer.TimerQueue) + @classmethod + def stop_added(cls): + cls.stoped = True - @staticmethod - def run2(): - return Timer.run_ex(Timer.TimerQueue2) + @classmethod + def start_added(cls): + cls.stoped = False - @staticmethod - def run_ex(queue: Queue): + @classmethod + def run1(cls): + return cls.run_ex(cls.TimerQueue) + + @classmethod + def run2(cls): + return cls.run_ex(cls.TimerQueue2) + + @classmethod + def run_ex(cls, queue: Queue): while not queue.empty(): t = queue.get() - # Timer.executor(t) try: - Timer.executor(t) + cls.executor(t) except Exception as e: traceback.print_exc() logger.error("%s: %s", type(e).__name__, e) @@ -46,15 +58,15 @@ def run_ex(queue: Queue): ... return 0.016666666666666666 - @staticmethod - def clear(): - while not Timer.TimerQueue.empty(): - Timer.TimerQueue.get() - while not Timer.TimerQueue2.empty(): - Timer.TimerQueue2.get() + @classmethod + def clear(cls): + while not cls.TimerQueue.empty(): + cls.TimerQueue.get() + while not cls.TimerQueue2.empty(): + cls.TimerQueue2.get() - @staticmethod - def wait_run(func): + @classmethod + def wait_run(cls, func): def wrap(*args, **kwargs): q = Queue() @@ -65,7 +77,7 @@ def wrap_job(q): except Exception as e: q.put(e) - Timer.put((wrap_job, q)) + cls.put((wrap_job, q)) res = q.get() if isinstance(res, Exception): raise res @@ -73,17 +85,17 @@ def wrap_job(q): return wrap - @staticmethod - def reg(): - bpy.app.timers.register(Timer.run1, persistent=True) - bpy.app.timers.register(Timer.run2, persistent=True) + @classmethod + def reg(cls): + bpy.app.timers.register(cls.run1, persistent=True) + bpy.app.timers.register(cls.run2, persistent=True) - @staticmethod - def unreg(): - Timer.clear() + @classmethod + def unreg(cls): + cls.clear() try: - bpy.app.timers.unregister(Timer.run1) - bpy.app.timers.unregister(Timer.run2) + bpy.app.timers.unregister(cls.run1) + bpy.app.timers.unregister(cls.run2) except Exception: ... diff --git a/translations/translation.py b/translations/translation.py index d6ec2fd..46206e2 100644 --- a/translations/translation.py +++ b/translations/translation.py @@ -154,6 +154,29 @@ def get_ori_name(inp_name): "STDOUT Listen Thread Exit": "输出监听线程关闭", "Time Elapsed": "已耗时", "Error when playing sound:": "播放声音出错:", + "Node Error Parse": "节点错误解析", + "Prompt has no outputs": "提示词没有输出节点", + "No Image Provided": "未提供图像", + "Image Not Found": "未找到图像", + # SDNode/operators.py + "AI Mat Solution Load": "AI材质方案载入", + "Load AI Mat Solution": "载入AI材质方案预设", + "Save AI Mat Solution": "保存AI材质方案预设", + "Delete AI Mat Solution": "删除AI材质方案预设", + "Run AI Mat Solution": "生成", + "Can't find CFNodeTree": "未找到ComfyUI节点树", + "No active material": "当前物体没有材质", + "Use depth and normal map to Gen Mesh Mat": "使用深度图和法线图生成网格材质", + "Backups": "备份", + "Clear Material Slots": "清空材质槽", + "00-Default": "00-默认", + "Apply": "应用", + "Restore": "还原", + "AI Mat already exists, Overwrite?": "已存在AI Mat,是否覆盖?", + "Already exists, Overwrite?": "已存在,是否覆盖?", + "Can't find ComfyUI Node Tree": "未找到ComfyUI节点树", + # SDNode/rt_tracker.py + "Tracker Loop": "循环生成", # SDNode/node_process.py "Executing": "执行中", # SDNode/nodes.py @@ -310,6 +333,7 @@ def get_ori_name(inp_name): "Show General Setting": "显示启动设置", "Image not found or format error(png/json)": "魔法图鉴不存在或格式不正确(仅png/json)", "Load Preset from Image Error -> MetaData Not Found in": "从图鉴加载失败, 元数据为", + "Sync AI Mat Tree to Editor": "同步AI材质生成树到编辑器", # ops.py "No NodeTree Found": "节点树为空", "Node Not Found: ": "节点未找到", @@ -363,6 +387,8 @@ def get_ori_name(inp_name): "From Image Editor": "来自图像编辑器", "To ComfyUI Node Editor": "导出到 ComfyUI 节点编辑器", "From ComfyUI Node Editor": "从 ComfyUI 节点编辑器导入", + "Bake Tree": "烘焙节点树", + "No Bake Tree Found": "未找到烘焙节点树", # preference.py "Server Type": "服务类型", "LocalServer": "本机启动", diff --git a/ui.py b/ui.py index 69c4acf..567ff0e 100644 --- a/ui.py +++ b/ui.py @@ -2,13 +2,16 @@ import platform from bl_ui.properties_paint_common import UnifiedPaintPanel from bpy.types import Context -from .ops import Ops, Load_History, Copy_Tree, Load_Batch, Fetch_Node_Status, Clear_Node_Cache, SDNode_To_Image, Image_To_SDNode, Image_Set_Channel_Packed +from .ops import Ops, Load_History, Copy_Tree, Load_Batch, Fetch_Node_Status, Clear_Node_Cache, SDNode_To_Image, Image_To_SDNode, Image_Set_Channel_Packed, Open_Log_Window from .translations import ctxt from .SDNode import TaskManager, FakeServer from .SDNode.tree import TREE_TYPE +from .SDNode.nodes import NodeBase from .SDNode.rt_tracker import Tracker_Loop, is_looped +from .SDNode.operators import AIMatSolutionLoad, AIMatSolutionRun, AIMatSolutionSave, AIMatSolutionDel, AIMatSolutionApply, AIMatSolutionRestore +from .utils import Icon from .preference import get_pref, AddonPreference -from .utils import get_addon_name, _T +from .utils import get_addon_name, _T, get_ai_mat_tree class Panel(bpy.types.Panel): @@ -31,7 +34,7 @@ def draw_header(self, context: Context): return sdn = bpy.context.scene.sdn row.prop(sdn, 'open_pref', text="", icon="PREFERENCES", text_ctxt=ctxt) - + def draw_header_preset(self, context: Context): row = self.layout.row(align=True) if not hasattr(bpy.context.scene, "sdn"): @@ -200,6 +203,7 @@ def show_error(self, layout): row.alert = True row.label(text=error_msg, icon="ERROR", text_ctxt=ctxt) + def draw_header_button(self, context): if context.space_data.tree_type == TREE_TYPE: layout = self.layout @@ -207,6 +211,7 @@ def draw_header_button(self, context): col.alert = True col.operator(Ops.bl_idname, text="", text_ctxt=ctxt, icon="PLAY").action = "Submit" + def draw_sdn_tofrom(self, context): layout = self.layout if context.space_data.tree_type == TREE_TYPE: @@ -215,10 +220,11 @@ def draw_sdn_tofrom(self, context): props = layout.operator(Image_To_SDNode.bl_idname, text="From Image Editor", text_ctxt=ctxt, icon="IMPORT") props.force_centered = True + def draw_imeditor_tofrom(self, context): layout = self.layout layout.separator() - layout.operator(Image_Set_Channel_Packed.bl_idname, text_ctxt=ctxt)#, icon="MOD_MASK") + layout.operator(Image_Set_Channel_Packed.bl_idname, text_ctxt=ctxt) # , icon="MOD_MASK") layout.operator(Image_To_SDNode.bl_idname, text="To ComfyUI Node Editor", text_ctxt=ctxt, icon="EXPORT") layout.operator(SDNode_To_Image.bl_idname, text="From ComfyUI Node Editor", text_ctxt=ctxt, icon="IMPORT") @@ -238,6 +244,154 @@ def draw_item(self, row.operator(Load_History.bl_idname, text="", icon="TIME").name = item.name +class AIPanelViewport(bpy.types.Panel): + bl_idname = "SDN_V3D_PT_UI" + bl_translation_context = ctxt + bl_label = get_addon_name() + bl_description = "" + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_category = "AI" + + def draw_header_preset(self, context: Context): + layout = self.layout + layout.prop(bpy.context.scene.sdn, "open_ai_sol_dir", text="", icon="FILE_FOLDER") + + def draw(self, context: Context): + layout = self.layout + if not hasattr(bpy.context.scene, "sdn"): + row = layout.row() + row.operator(Clear_Node_Cache.bl_idname, text="Clear Node Cache", icon="MODIFIER") + row.alert = True + row.scale_y = 2 + return + if TaskManager.server == FakeServer._instance: + self.show_launch_cnn(layout) + return + elif TaskManager.is_launching(): + box = layout.box() + box.alert = True + box.scale_y = 2 + row = box.row() + row.alignment = "CENTER" + row.label(text="ComfyUI Launching/Connecting...", icon="INFO") + row = box.row() + row.alignment = "CENTER" + row.label(text=TaskManager.server.get_running_info(), icon="TIME") + return + self.show_common(layout) + self.show_nodes(layout) + + def show_common(self, layout: bpy.types.UILayout): + row = layout.row(align=True) + row.prop(bpy.context.scene.sdn, "ai_gen_solution", text="") + row.prop(bpy.context.scene.sdn, "clear_material_slots", text="", icon="CON_TRANSLIKE") + row.operator(AIMatSolutionSave.bl_idname, text="", icon="FILE_TICK") + row.operator(AIMatSolutionDel.bl_idname, text="", icon="TRASH") + layout.template_icon_view(bpy.context.scene.sdn, "ai_gen_solution", show_labels=True, scale_popup=5) + row = layout.row(align=True) + row.prop(bpy.context.scene.sdn, "ai_mat_tex_size", text="") + row.operator(AIMatSolutionLoad.bl_idname, text_ctxt=ctxt) + col = layout.column(align=True) + col.scale_y = 1.5 + col.alert = bool(get_ai_mat_tree(bpy.context.object)) + crow = col.row(align=True) + crow.operator(AIMatSolutionRun.bl_idname, text_ctxt=ctxt, icon="PLAY") + crcol = crow.column(align=True) + crcol.enabled = bool(get_ai_mat_tree(bpy.context.object)) + crcol.prop(bpy.context.scene.sdn, "send_ai_tree_to_editor", text="", icon="FILE_REFRESH") + row = layout.row(align=True) + if bpy.context.object and bpy.context.object.get("AI_Mat_Gen_Applied", None): + row.alert = True + row.label(text="Applying...", icon="RECORD_ON") + row.label(text="", icon="RECORD_ON") + row.label(text="", icon="RECORD_ON") + row.label(text="", icon="RECORD_ON") + row.label(text="", icon="RECORD_ON") + row.label(text="", icon="RECORD_ON") + else: + row.operator(AIMatSolutionApply.bl_idname, text_ctxt=ctxt, icon="EVENT_RETURN") # KEY_RETURN_FILLED + row.operator(AIMatSolutionRestore.bl_idname, text_ctxt=ctxt, icon="LOOP_BACK") # KEY_BACKSPACE_FILLED + layout.prop(bpy.context.scene.sdn, "apply_bake_pass", text="") + self.show_progress(layout) + # if bpy.context.object and "AI_Mat_Gen_TexID" in bpy.context.object: + # layout.template_icon(bpy.context.object["AI_Mat_Gen_TexID"], scale=10) + # # layout.template_preview(bpy.context.object["AI_Mat_Gen_Tex"].preview.icon_id) + + def show_launch_cnn(self, layout: bpy.types.UILayout): + if TaskManager.server != FakeServer._instance: + return + row = layout.row() + row.alignment = "CENTER" + row.label(text="↓↓ComfyUI Not Launched, Click to Launch↓↓") + row = layout.row(align=True) + row.alert = True + row.scale_y = 2 + row.operator(Ops.bl_idname, text="Launch/Connect to ComfyUI", icon="PLAY").action = "Launch" + row.prop(bpy.context.scene.sdn, "show_pref_general", text="", icon="PREFERENCES") + if bpy.context.scene.sdn.show_pref_general: + AddonPreference.draw_general(get_pref(), layout.box()) + self.show_error(layout) + + def show_error(self, layout): + for error_msg in TaskManager.get_error_msg(): + row = layout.row() + row.alert = True + row.label(text=error_msg, icon="ERROR", text_ctxt=ctxt) + + def show_progress(self, layout: bpy.types.UILayout): + layout = layout.box() + from .SDNode.custom_support import cup_monitor + cup_monitor.draw(layout) + self.show_error(layout) + if TaskManager.get_error_msg(): + row = layout.box().row() + row.alignment = "CENTER" + row.alert = True + row.label(text="Adjust node tree and try again", text_ctxt=ctxt) + + def show_nodes(self, layout: bpy.types.UILayout): + tree = get_ai_mat_tree(bpy.context.object) + if not tree: + return + nodes: list[NodeBase] = [] + for node in tree.nodes: + if len(node.label) != 3: + continue + # 判断 label 为 001 - 999 之间的字符串 + if not node.label.isdigit() or int(node.label) < 1 or int(node.label) > 999: + continue + nodes.append(node) + nodes.sort(key=lambda x: x.label) + for node in nodes: + box = layout.box() + row = box.row() + row.prop(node, "ac_expand", icon="TRIA_DOWN" if node.ac_expand else "TRIA_RIGHT", text="", emboss=False) + if node.type != "GROUP": + row.label(text=node.name) + elif node.node_tree: + row.label(text=node.node_tree.name) + if node.ac_expand is False: + continue + if bpy.app.version >= (4, 2): + box.separator(type="LINE") + else: + box.separator() + node.draw_buttons(bpy.context, box) + + def find_node_input(self, node) -> list[bpy.types.NodeSocket]: + sockets = [] + for inp in node.inputs: + if inp.is_linked: + continue + if inp.enabled is False or inp.hide: + continue + if inp.type == "RGBA" and inp.hide_value: + continue + sockets.append(inp) + return sockets + + class PanelViewport(bpy.types.Panel): bl_idname = "SDNV_PT_UI" bl_translation_context = ctxt @@ -299,12 +453,34 @@ def f(brush, length, width, height): brush.stencil_dimension = (length / 2, length / 2) Timer.put((f, brush, length, area.width, area.height)) + +def status_bar_draw(self: bpy.types.UILayout, context: bpy.types.Context): + layout = self.layout + layout.label(text="[") + from .SDNode.custom_support import cup_monitor + cup_monitor.draw(layout, use_region_width=False) + layout.operator(Open_Log_Window.bl_idname, text="", icon="WORDWRAP_ON") + layout.label(text="]") + + +clss = ( + AIPanelViewport, +) + +register, unregister = bpy.utils.register_classes_factory(clss) + + def ui_reg(): + register() bpy.types.NODE_HT_header.append(draw_header_button) bpy.types.IMAGE_MT_image.append(draw_imeditor_tofrom) bpy.types.NODE_MT_node.append(draw_sdn_tofrom) + bpy.types.STATUSBAR_HT_header.append(status_bar_draw) + def ui_unreg(): + bpy.types.STATUSBAR_HT_header.remove(status_bar_draw) bpy.types.NODE_HT_header.remove(draw_header_button) bpy.types.IMAGE_MT_image.remove(draw_imeditor_tofrom) - bpy.types.NODE_MT_node.remove(draw_sdn_tofrom) \ No newline at end of file + bpy.types.NODE_MT_node.remove(draw_sdn_tofrom) + unregister() diff --git a/utils.py b/utils.py index fa3fbb8..16cd443 100644 --- a/utils.py +++ b/utils.py @@ -4,6 +4,7 @@ import time import re import json +import bpy from pathlib import Path from threading import Thread from functools import lru_cache @@ -15,6 +16,47 @@ from .datas import IMG_SUFFIX, get_bl_version translation = {} +addon_bl_info = {} + + +def get_bl_info(): + return addon_bl_info + + +def popup_folder(path: Path): + import os + if platform.system() == "Windows": + if path.is_file(): + path = path.parent + path = path.as_posix() + os.startfile(path) + else: + os.system(f"open {path}") + + +def get_ai_mat_tree(obj: bpy.types.Object): + if not obj or obj.type != "MESH": + return None + if hasattr(obj, "ai_mat_tree"): + return getattr(obj, "ai_mat_tree") + tree_name = obj.get("AI_Mat_Gen", "") + if not tree_name: + return None + sdn_time_code = obj.get("AI_Mat_Gen_Id", "-1") + tree = bpy.data.node_groups.get(tree_name, None) + if not tree or tree.get("sdn_time_code", "0") != sdn_time_code: + for ng in bpy.data.node_groups: + if ng.get("sdn_time_code", "0") == sdn_time_code: + return ng + return None + return tree + + +def set_ai_mat_tree(obj: bpy.types.Object, tree: bpy.types.NodeTree): + obj["AI_Mat_Gen"] = tree.name + tree.set_sdn_time_code() + obj["AI_Mat_Gen_Id"] = tree.sdn_time_code + def read_json(path: Path | str) -> dict: import json @@ -76,6 +118,7 @@ def update_screen(): import bpy for area in bpy.context.screen.areas: area.tag_redraw() + bpy.context.workspace.status_text_set_internal(None) except BaseException: ... @@ -297,7 +340,9 @@ def load_icon(path): import bpy p = FSWatcher.to_path(path) path = FSWatcher.to_str(path) - + # ctrl + z 导致bpy.data中的图像被删除 + if path not in Icon.PATH2BPY: + Icon.IMG_STATUS.pop(path, None) if not Icon.can_mark_image(path): return