diff --git a/blueprints/Chromatic Aberration.json b/blueprints/Chromatic Aberration.json new file mode 100644 index 000000000..8c811dd2e --- /dev/null +++ b/blueprints/Chromatic Aberration.json @@ -0,0 +1 @@ +{"revision":0,"last_node_id":19,"last_link_id":0,"nodes":[{"id":19,"type":"2c5ef154-2bde-496d-bc8b-9dcf42f2913f","pos":[3710,-2070],"size":[260,82],"flags":{},"order":4,"mode":0,"inputs":[{"label":"image","localized_name":"images.image0","name":"images.image0","type":"IMAGE","link":null}],"outputs":[{"label":"IMAGE","localized_name":"IMAGE0","name":"IMAGE0","type":"IMAGE","links":[]}],"title":"Chromatic Aberration","properties":{"proxyWidgets":[["17","choice"],["18","value"]]},"widgets_values":[]}],"links":[],"version":0.4,"definitions":{"subgraphs":[{"id":"2c5ef154-2bde-496d-bc8b-9dcf42f2913f","version":1,"state":{"lastGroupId":0,"lastNodeId":18,"lastLinkId":23,"lastRerouteId":0},"revision":0,"config":{},"name":"Chromatic Aberration","inputNode":{"id":-10,"bounding":[3270,-2050,120,60]},"outputNode":{"id":-20,"bounding":[4260,-2050,120,60]},"inputs":[{"id":"3b33ac46-93a6-4b1c-896a-ed6fbd24e59c","name":"images.image0","type":"IMAGE","linkIds":[20],"localized_name":"images.image0","label":"image","pos":[3370,-2030]}],"outputs":[{"id":"abe7cd79-a87b-4bd0-8923-d79a57d81a6e","name":"IMAGE0","type":"IMAGE","linkIds":[23],"localized_name":"IMAGE0","label":"IMAGE","pos":[4280,-2030]}],"widgets":[],"nodes":[{"id":16,"type":"GLSLShader","pos":[3810,-2320],"size":[390,212],"flags":{},"order":2,"mode":0,"inputs":[{"label":"image0","localized_name":"images.image0","name":"images.image0","type":"IMAGE","link":20},{"label":"image1","localized_name":"images.image1","name":"images.image1","shape":7,"type":"IMAGE","link":null},{"label":"u_float0","localized_name":"floats.u_float0","name":"floats.u_float0","shape":7,"type":"FLOAT","link":22},{"label":"u_float1","localized_name":"floats.u_float1","name":"floats.u_float1","shape":7,"type":"FLOAT","link":null},{"label":"u_int0","localized_name":"ints.u_int0","name":"ints.u_int0","shape":7,"type":"INT","link":21},{"label":"u_int1","localized_name":"ints.u_int1","name":"ints.u_int1","shape":7,"type":"INT","link":null},{"localized_name":"fragment_shader","name":"fragment_shader","type":"STRING","widget":{"name":"fragment_shader"},"link":null},{"localized_name":"size_mode","name":"size_mode","type":"COMFY_DYNAMICCOMBO_V3","widget":{"name":"size_mode"},"link":null}],"outputs":[{"localized_name":"IMAGE0","name":"IMAGE0","type":"IMAGE","links":[23]},{"localized_name":"IMAGE1","name":"IMAGE1","type":"IMAGE","links":null},{"localized_name":"IMAGE2","name":"IMAGE2","type":"IMAGE","links":null},{"localized_name":"IMAGE3","name":"IMAGE3","type":"IMAGE","links":null}],"properties":{"Node name for S&R":"GLSLShader"},"widgets_values":["#version 300 es\nprecision highp float;\n\nuniform sampler2D u_image0;\nuniform int u_int0; // Mode\nuniform float u_float0; // Amount (0 to 100)\n\nin vec2 v_texCoord;\nout vec4 fragColor;\n\nconst int MODE_LINEAR = 0;\nconst int MODE_RADIAL = 1;\nconst int MODE_BARREL = 2;\nconst int MODE_SWIRL = 3;\nconst int MODE_DIAGONAL = 4;\n\nvoid main() {\n vec2 uv = v_texCoord;\n vec4 original = texture(u_image0, uv);\n \n float amount = u_float0 * 0.0005;\n \n if (amount == 0.0) {\n fragColor = original;\n return;\n }\n \n vec2 centered = uv - 0.5;\n float r = length(centered);\n vec2 dir = normalize(centered + 0.001);\n vec2 offset;\n \n if (u_int0 == MODE_LINEAR) {\n // Horizontal shift\n offset = vec2(amount, 0.0);\n }\n else if (u_int0 == MODE_RADIAL) {\n // Outward from center, stronger at edges\n offset = dir * r * amount * 4.0;\n }\n else if (u_int0 == MODE_BARREL) {\n // Lens distortion simulation (r² falloff)\n offset = dir * r * r * amount * 8.0;\n }\n else if (u_int0 == MODE_SWIRL) {\n // Perpendicular to radial (rotational aberration)\n vec2 perp = vec2(-dir.y, dir.x);\n offset = perp * r * amount * 4.0;\n }\n else if (u_int0 == MODE_DIAGONAL) {\n // 45° offset\n offset = vec2(amount, amount) * 0.707;\n }\n \n float red = texture(u_image0, uv + offset).r;\n float green = original.g;\n float blue = texture(u_image0, uv - offset).b;\n \n fragColor = vec4(red, green, blue, original.a);\n}","from_input"]},{"id":18,"type":"PrimitiveFloat","pos":[3810,-2430],"size":[270,58],"flags":{},"order":0,"mode":0,"inputs":[{"label":"amount","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[22]}],"properties":{"Node name for S&R":"PrimitiveFloat","min":0,"max":100,"step":1},"widgets_values":[30]},{"id":17,"type":"CustomCombo","pos":[3520,-2320],"size":[270,222],"flags":{},"order":1,"mode":0,"inputs":[{"label":"mode","localized_name":"choice","name":"choice","type":"COMBO","widget":{"name":"choice"},"link":null}],"outputs":[{"localized_name":"STRING","name":"STRING","type":"STRING","links":null},{"localized_name":"INDEX","name":"INDEX","type":"INT","links":[21]}],"properties":{"Node name for S&R":"CustomCombo"},"widgets_values":["Linear",0,"Linear","Radial","Barrel","Swirl","Diagonal",""]}],"groups":[],"links":[{"id":22,"origin_id":18,"origin_slot":0,"target_id":16,"target_slot":2,"type":"FLOAT"},{"id":21,"origin_id":17,"origin_slot":1,"target_id":16,"target_slot":4,"type":"INT"},{"id":20,"origin_id":-10,"origin_slot":0,"target_id":16,"target_slot":0,"type":"IMAGE"},{"id":23,"origin_id":16,"origin_slot":0,"target_id":-20,"target_slot":0,"type":"IMAGE"}],"extra":{"workflowRendererVersion":"LG"}}]}} \ No newline at end of file diff --git a/blueprints/Color Adjustment.json b/blueprints/Color Adjustment.json new file mode 100644 index 000000000..86133a573 --- /dev/null +++ b/blueprints/Color Adjustment.json @@ -0,0 +1 @@ +{"revision":0,"last_node_id":14,"last_link_id":0,"nodes":[{"id":14,"type":"36677b92-5dd8-47a5-9380-4da982c1894f","pos":[3610,-2630],"size":[270,150],"flags":{},"order":3,"mode":0,"inputs":[{"label":"image","localized_name":"images.image0","name":"images.image0","type":"IMAGE","link":null}],"outputs":[{"label":"IMAGE","localized_name":"IMAGE0","name":"IMAGE0","type":"IMAGE","links":[]}],"properties":{"proxyWidgets":[["4","value"],["5","value"],["7","value"],["6","value"]]},"widgets_values":[],"title":"Color Adjustment"}],"links":[],"version":0.4,"definitions":{"subgraphs":[{"id":"36677b92-5dd8-47a5-9380-4da982c1894f","version":1,"state":{"lastGroupId":0,"lastNodeId":16,"lastLinkId":36,"lastRerouteId":0},"revision":0,"config":{},"name":"Color Adjustment","inputNode":{"id":-10,"bounding":[3110,-3560,120,60]},"outputNode":{"id":-20,"bounding":[4070,-3560,120,60]},"inputs":[{"id":"0431d493-5f28-4430-bd00-84733997fc08","name":"images.image0","type":"IMAGE","linkIds":[29],"localized_name":"images.image0","label":"image","pos":[3210,-3540]}],"outputs":[{"id":"bee8ea06-a114-4612-8937-939f2c927bdb","name":"IMAGE0","type":"IMAGE","linkIds":[28],"localized_name":"IMAGE0","label":"IMAGE","pos":[4090,-3540]}],"widgets":[],"nodes":[{"id":15,"type":"GLSLShader","pos":[3590,-3940],"size":[420,252],"flags":{},"order":4,"mode":0,"inputs":[{"label":"image0","localized_name":"images.image0","name":"images.image0","type":"IMAGE","link":29},{"label":"image1","localized_name":"images.image1","name":"images.image1","shape":7,"type":"IMAGE","link":null},{"label":"u_float0","localized_name":"floats.u_float0","name":"floats.u_float0","shape":7,"type":"FLOAT","link":34},{"label":"u_float1","localized_name":"floats.u_float1","name":"floats.u_float1","shape":7,"type":"FLOAT","link":30},{"label":"u_float2","localized_name":"floats.u_float2","name":"floats.u_float2","shape":7,"type":"FLOAT","link":31},{"label":"u_float3","localized_name":"floats.u_float3","name":"floats.u_float3","shape":7,"type":"FLOAT","link":33},{"label":"u_float4","localized_name":"floats.u_float4","name":"floats.u_float4","shape":7,"type":"FLOAT","link":null},{"label":"u_int0","localized_name":"ints.u_int0","name":"ints.u_int0","shape":7,"type":"INT","link":null},{"localized_name":"fragment_shader","name":"fragment_shader","type":"STRING","widget":{"name":"fragment_shader"},"link":null},{"localized_name":"size_mode","name":"size_mode","type":"COMFY_DYNAMICCOMBO_V3","widget":{"name":"size_mode"},"link":null}],"outputs":[{"localized_name":"IMAGE0","name":"IMAGE0","type":"IMAGE","links":[28]},{"localized_name":"IMAGE1","name":"IMAGE1","type":"IMAGE","links":null},{"localized_name":"IMAGE2","name":"IMAGE2","type":"IMAGE","links":null},{"localized_name":"IMAGE3","name":"IMAGE3","type":"IMAGE","links":null}],"properties":{"Node name for S&R":"GLSLShader"},"widgets_values":["#version 300 es\nprecision highp float;\n\nuniform sampler2D u_image0;\nuniform float u_float0; // temperature (-100 to 100)\nuniform float u_float1; // tint (-100 to 100)\nuniform float u_float2; // vibrance (-100 to 100)\nuniform float u_float3; // saturation (-100 to 100)\n\nin vec2 v_texCoord;\nout vec4 fragColor;\n\nvoid main() {\n vec4 tex = texture(u_image0, v_texCoord);\n vec3 color = tex.rgb;\n \n // Scale inputs: -100/100 → -1/1\n float temperature = u_float0 * 0.01;\n float tint = u_float1 * 0.01;\n float vibrance = u_float2 * 0.01;\n float saturation = u_float3 * 0.01;\n \n // Temperature (warm/cool): positive = warm, negative = cool\n color.r = clamp(color.r + temperature * 0.3, 0.0, 1.0);\n color.b = clamp(color.b - temperature * 0.3, 0.0, 1.0);\n \n // Tint (green/magenta): positive = green, negative = magenta\n color.g = clamp(color.g + tint * 0.3, 0.0, 1.0);\n color.r = clamp(color.r - tint * 0.15, 0.0, 1.0);\n color.b = clamp(color.b - tint * 0.15, 0.0, 1.0);\n \n // Vibrance Pro with skin protection\n if (vibrance != 0.0) {\n float maxC = max(color.r, max(color.g, color.b));\n float minC = min(color.r, min(color.g, color.b));\n float sat = maxC - minC;\n float gray = dot(color, vec3(0.299, 0.587, 0.114));\n \n if (vibrance < 0.0) {\n // Desaturate: -100 → gray\n color = mix(vec3(gray), color, 1.0 + vibrance);\n } else {\n // Boost less saturated colors more\n float vibranceAmt = vibrance * (1.0 - sat);\n \n // Skin tone protection (hardcoded 0.5)\n float skinTone = 0.0;\n if (color.r > color.g && color.g > color.b) {\n float warmth = (color.r - color.b) / max(maxC, 0.001);\n skinTone = warmth * sat * (1.0 - sat);\n }\n vibranceAmt *= (1.0 - skinTone * 0.5);\n \n color = mix(vec3(gray), color, 1.0 + vibranceAmt * 2.0);\n }\n }\n \n // Saturation\n if (saturation != 0.0) {\n float gray = dot(color, vec3(0.299, 0.587, 0.114));\n float satMix = saturation < 0.0\n ? 1.0 + saturation // -100 → gray\n : 1.0 + saturation * 2.0; // +100 → 3x boost\n color = mix(vec3(gray), color, satMix);\n }\n \n fragColor = vec4(clamp(color, 0.0, 1.0), tex.a);\n}","from_input"]},{"id":6,"type":"PrimitiveFloat","pos":[3290,-3610],"size":[270,58],"flags":{},"order":0,"mode":0,"inputs":[{"label":"vibrance","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[26,31]}],"title":"Vibrance","properties":{"Node name for S&R":"PrimitiveFloat","max":100,"min":-100,"step":1},"widgets_values":[0]},{"id":7,"type":"PrimitiveFloat","pos":[3290,-3720],"size":[270,58],"flags":{},"order":1,"mode":0,"inputs":[{"label":"saturation","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[33]}],"title":"Saturation","properties":{"Node name for S&R":"PrimitiveFloat","max":100,"min":-100,"step":1},"widgets_values":[0]},{"id":5,"type":"PrimitiveFloat","pos":[3290,-3830],"size":[270,58],"flags":{},"order":2,"mode":0,"inputs":[{"label":"tint","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[30]}],"title":"Tint","properties":{"Node name for S&R":"PrimitiveFloat","max":100,"min":-100,"step":1},"widgets_values":[0]},{"id":4,"type":"PrimitiveFloat","pos":[3290,-3940],"size":[270,58],"flags":{},"order":3,"mode":0,"inputs":[{"label":"temperature","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[34]}],"title":"Temperature","properties":{"Node name for S&R":"PrimitiveFloat","max":100,"min":-100,"step":1},"widgets_values":[100]}],"groups":[],"links":[{"id":34,"origin_id":4,"origin_slot":0,"target_id":15,"target_slot":2,"type":"FLOAT"},{"id":30,"origin_id":5,"origin_slot":0,"target_id":15,"target_slot":3,"type":"FLOAT"},{"id":31,"origin_id":6,"origin_slot":0,"target_id":15,"target_slot":4,"type":"FLOAT"},{"id":33,"origin_id":7,"origin_slot":0,"target_id":15,"target_slot":5,"type":"FLOAT"},{"id":29,"origin_id":-10,"origin_slot":0,"target_id":15,"target_slot":0,"type":"IMAGE"},{"id":28,"origin_id":15,"origin_slot":0,"target_id":-20,"target_slot":0,"type":"IMAGE"}],"extra":{"workflowRendererVersion":"LG"}}]}} \ No newline at end of file diff --git a/blueprints/Film Grain.json b/blueprints/Film Grain.json new file mode 100644 index 000000000..bc88b08f8 --- /dev/null +++ b/blueprints/Film Grain.json @@ -0,0 +1 @@ +{"revision":0,"last_node_id":22,"last_link_id":0,"nodes":[{"id":22,"type":"3324cf54-bcff-405f-a4bf-c5122c72fe56","pos":[4800,-1180],"size":[250,154],"flags":{},"order":4,"mode":0,"inputs":[{"label":"image","localized_name":"images.image0","name":"images.image0","type":"IMAGE","link":null}],"outputs":[{"label":"IMAGE","localized_name":"IMAGE0","name":"IMAGE0","type":"IMAGE","links":[]}],"title":"Film Grain","properties":{"proxyWidgets":[["17","value"],["18","value"],["19","value"],["20","value"],["21","choice"]]},"widgets_values":[]}],"links":[],"version":0.4,"definitions":{"subgraphs":[{"id":"3324cf54-bcff-405f-a4bf-c5122c72fe56","version":1,"state":{"lastGroupId":0,"lastNodeId":21,"lastLinkId":30,"lastRerouteId":0},"revision":0,"config":{},"name":"Film Grain","inputNode":{"id":-10,"bounding":[4096.671470760602,-948.2184031393472,120,60]},"outputNode":{"id":-20,"bounding":[4900,-948.2184031393472,120,60]},"inputs":[{"id":"062968ea-da25-47e7-a180-d913c267f148","name":"images.image0","type":"IMAGE","linkIds":[22],"localized_name":"images.image0","label":"image","pos":[4196.671470760602,-928.2184031393472]}],"outputs":[{"id":"43247d06-a39f-4733-9828-c39400fe02a4","name":"IMAGE0","type":"IMAGE","linkIds":[23],"localized_name":"IMAGE0","label":"IMAGE","pos":[4920,-928.2184031393472]}],"widgets":[],"nodes":[{"id":15,"type":"GLSLShader","pos":[4510,-1180],"size":[330,272],"flags":{},"order":5,"mode":0,"inputs":[{"label":"image0","localized_name":"images.image0","name":"images.image0","type":"IMAGE","link":22},{"label":"image1","localized_name":"images.image1","name":"images.image1","shape":7,"type":"IMAGE","link":null},{"label":"u_float0","localized_name":"floats.u_float0","name":"floats.u_float0","shape":7,"type":"FLOAT","link":26},{"label":"u_float1","localized_name":"floats.u_float1","name":"floats.u_float1","shape":7,"type":"FLOAT","link":27},{"label":"u_float2","localized_name":"floats.u_float2","name":"floats.u_float2","shape":7,"type":"FLOAT","link":28},{"label":"u_float3","localized_name":"floats.u_float3","name":"floats.u_float3","shape":7,"type":"FLOAT","link":29},{"label":"u_float4","localized_name":"floats.u_float4","name":"floats.u_float4","shape":7,"type":"FLOAT","link":null},{"label":"u_int0","localized_name":"ints.u_int0","name":"ints.u_int0","shape":7,"type":"INT","link":30},{"label":"u_int1","localized_name":"ints.u_int1","name":"ints.u_int1","shape":7,"type":"INT","link":null},{"localized_name":"fragment_shader","name":"fragment_shader","type":"STRING","widget":{"name":"fragment_shader"},"link":null},{"localized_name":"size_mode","name":"size_mode","type":"COMFY_DYNAMICCOMBO_V3","widget":{"name":"size_mode"},"link":null}],"outputs":[{"localized_name":"IMAGE0","name":"IMAGE0","type":"IMAGE","links":[23]},{"localized_name":"IMAGE1","name":"IMAGE1","type":"IMAGE","links":null},{"localized_name":"IMAGE2","name":"IMAGE2","type":"IMAGE","links":null},{"localized_name":"IMAGE3","name":"IMAGE3","type":"IMAGE","links":null}],"properties":{"Node name for S&R":"GLSLShader"},"widgets_values":["#version 300 es\nprecision highp float;\n\nuniform sampler2D u_image0;\nuniform vec2 u_resolution;\nuniform float u_float0; // grain amount [0.0 – 1.0] typical: 0.2–0.8\nuniform float u_float1; // grain size [0.3 – 3.0] lower = finer grain\nuniform float u_float2; // color amount [0.0 – 1.0] 0 = monochrome, 1 = RGB grain\nuniform float u_float3; // luminance bias [0.0 – 1.0] 0 = uniform, 1 = shadows only\nuniform int u_int0; // noise mode [0 or 1] 0 = smooth, 1 = grainy\n\nin vec2 v_texCoord;\nlayout(location = 0) out vec4 fragColor0;\n\n// High-quality integer hash (pcg-like)\nuint pcg(uint v) {\n uint state = v * 747796405u + 2891336453u;\n uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;\n return (word >> 22u) ^ word;\n}\n\n// 2D -> 1D hash input\nuint hash2d(uvec2 p) {\n return pcg(p.x + pcg(p.y));\n}\n\n// Hash to float [0, 1]\nfloat hashf(uvec2 p) {\n return float(hash2d(p)) / float(0xffffffffu);\n}\n\n// Hash to float with offset (for RGB channels)\nfloat hashf(uvec2 p, uint offset) {\n return float(pcg(hash2d(p) + offset)) / float(0xffffffffu);\n}\n\n// Convert uniform [0,1] to roughly Gaussian distribution\n// Using simple approximation: average of multiple samples\nfloat toGaussian(uvec2 p) {\n float sum = hashf(p, 0u) + hashf(p, 1u) + hashf(p, 2u) + hashf(p, 3u);\n return (sum - 2.0) * 0.7; // Centered, scaled\n}\n\nfloat toGaussian(uvec2 p, uint offset) {\n float sum = hashf(p, offset) + hashf(p, offset + 1u) \n + hashf(p, offset + 2u) + hashf(p, offset + 3u);\n return (sum - 2.0) * 0.7;\n}\n\n// Smooth noise with better interpolation\nfloat smoothNoise(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n \n // Quintic interpolation (less banding than cubic)\n f = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);\n \n uvec2 ui = uvec2(i);\n float a = toGaussian(ui);\n float b = toGaussian(ui + uvec2(1u, 0u));\n float c = toGaussian(ui + uvec2(0u, 1u));\n float d = toGaussian(ui + uvec2(1u, 1u));\n \n return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);\n}\n\nfloat smoothNoise(vec2 p, uint offset) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n \n f = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);\n \n uvec2 ui = uvec2(i);\n float a = toGaussian(ui, offset);\n float b = toGaussian(ui + uvec2(1u, 0u), offset);\n float c = toGaussian(ui + uvec2(0u, 1u), offset);\n float d = toGaussian(ui + uvec2(1u, 1u), offset);\n \n return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);\n}\n\nvoid main() {\n vec4 color = texture(u_image0, v_texCoord);\n \n // Luminance (Rec.709)\n float luma = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));\n \n // Grain UV (resolution-independent)\n vec2 grainUV = v_texCoord * u_resolution / max(u_float1, 0.001);\n uvec2 grainPixel = uvec2(grainUV);\n \n float g;\n vec3 grainRGB;\n \n if (u_int0 == 1) {\n // Grainy mode: pure hash noise (no interpolation = no banding)\n g = toGaussian(grainPixel);\n grainRGB = vec3(\n toGaussian(grainPixel, 100u),\n toGaussian(grainPixel, 200u),\n toGaussian(grainPixel, 300u)\n );\n } else {\n // Smooth mode: interpolated with quintic curve\n g = smoothNoise(grainUV);\n grainRGB = vec3(\n smoothNoise(grainUV, 100u),\n smoothNoise(grainUV, 200u),\n smoothNoise(grainUV, 300u)\n );\n }\n \n // Luminance weighting (less grain in highlights)\n float lumWeight = mix(1.0, 1.0 - luma, clamp(u_float3, 0.0, 1.0));\n \n // Strength\n float strength = u_float0 * 0.15;\n \n // Color vs monochrome grain\n vec3 grainColor = mix(vec3(g), grainRGB, clamp(u_float2, 0.0, 1.0));\n \n color.rgb += grainColor * strength * lumWeight;\n fragColor0 = vec4(color.rgb, color.a);\n}\n","from_input"]},{"id":21,"type":"CustomCombo","pos":[4280,-780],"size":[210,153.8888931274414],"flags":{},"order":0,"mode":0,"inputs":[{"label":"grain_mode","localized_name":"choice","name":"choice","type":"COMBO","widget":{"name":"choice"},"link":null}],"outputs":[{"localized_name":"STRING","name":"STRING","type":"STRING","links":null},{"localized_name":"INDEX","name":"INDEX","type":"INT","links":[30]}],"properties":{"Node name for S&R":"CustomCombo"},"widgets_values":["Smooth",0,"Smooth","Grainy",""]},{"id":17,"type":"PrimitiveFloat","pos":[4276.671470760602,-1180.3256994061358],"size":[210,58],"flags":{},"order":1,"mode":0,"inputs":[{"label":"grain_amount","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[26]}],"title":"Grain amount","properties":{"Node name for S&R":"PrimitiveFloat","min":0,"max":1,"step":0.05,"precision":2},"widgets_values":[0.25]},{"id":18,"type":"PrimitiveFloat","pos":[4280,-1080],"size":[210,58],"flags":{},"order":2,"mode":0,"inputs":[{"label":"grain_size","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[27]}],"title":"Grain size","properties":{"Node name for S&R":"PrimitiveFloat","min":0.05,"max":3,"precision":2,"step":0.05},"widgets_values":[0.1]},{"id":19,"type":"PrimitiveFloat","pos":[4280,-980],"size":[210,58],"flags":{},"order":3,"mode":0,"inputs":[{"label":"color_amount","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[28]}],"title":"Color amount","properties":{"Node name for S&R":"PrimitiveFloat","min":0,"max":1,"precision":2,"step":0.05},"widgets_values":[0]},{"id":20,"type":"PrimitiveFloat","pos":[4280,-880],"size":[210,58],"flags":{},"order":4,"mode":0,"inputs":[{"label":"shadow_focus","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[29]}],"title":"Luminance bias","properties":{"Node name for S&R":"PrimitiveFloat","min":0,"max":1,"precision":2,"step":0.05},"widgets_values":[0]}],"groups":[],"links":[{"id":26,"origin_id":17,"origin_slot":0,"target_id":15,"target_slot":2,"type":"FLOAT"},{"id":27,"origin_id":18,"origin_slot":0,"target_id":15,"target_slot":3,"type":"FLOAT"},{"id":28,"origin_id":19,"origin_slot":0,"target_id":15,"target_slot":4,"type":"FLOAT"},{"id":29,"origin_id":20,"origin_slot":0,"target_id":15,"target_slot":5,"type":"FLOAT"},{"id":30,"origin_id":21,"origin_slot":1,"target_id":15,"target_slot":7,"type":"INT"},{"id":22,"origin_id":-10,"origin_slot":0,"target_id":15,"target_slot":0,"type":"IMAGE"},{"id":23,"origin_id":15,"origin_slot":0,"target_id":-20,"target_slot":0,"type":"IMAGE"}],"extra":{"workflowRendererVersion":"LG"}}]}} \ No newline at end of file diff --git a/blueprints/Image Blur.json b/blueprints/Image Blur.json new file mode 100644 index 000000000..a9f39ad3e --- /dev/null +++ b/blueprints/Image Blur.json @@ -0,0 +1 @@ +{"revision":0,"last_node_id":8,"last_link_id":0,"nodes":[{"id":8,"type":"198632a3-ee76-4aab-9ce7-a69c624eaff9","pos":[4470,-1840],"size":[210,82],"flags":{},"order":3,"mode":0,"inputs":[{"label":"image","localized_name":"images.image0","name":"images.image0","type":"IMAGE","link":null}],"outputs":[{"label":"blurred_image","localized_name":"IMAGE0","name":"IMAGE0","type":"IMAGE","links":[]}],"properties":{"proxyWidgets":[["12","choice"],["10","value"]]},"widgets_values":[],"title":"Image Blur"}],"links":[],"version":0.4,"definitions":{"subgraphs":[{"id":"198632a3-ee76-4aab-9ce7-a69c624eaff9","version":1,"state":{"lastGroupId":0,"lastNodeId":12,"lastLinkId":11,"lastRerouteId":0},"revision":0,"config":{},"name":"Image Blur","inputNode":{"id":-10,"bounding":[3540,-2445,120,60]},"outputNode":{"id":-20,"bounding":[4620,-2445,121.11666870117188,60]},"inputs":[{"id":"7ff2a402-6b11-45e8-a92a-7158d216520a","name":"images.image0","type":"IMAGE","linkIds":[9],"localized_name":"images.image0","label":"image","pos":[3640,-2425]}],"outputs":[{"id":"80a8e19e-ffd9-44a5-90f2-710815a5b063","name":"IMAGE0","type":"IMAGE","linkIds":[3],"localized_name":"IMAGE0","label":"blurred_image","pos":[4640,-2425]}],"widgets":[],"nodes":[{"id":12,"type":"CustomCombo","pos":[3720,-2620],"size":[270,174],"flags":{},"order":0,"mode":0,"inputs":[{"label":"blur_type","localized_name":"choice","name":"choice","type":"COMBO","widget":{"name":"choice"},"link":null}],"outputs":[{"localized_name":"STRING","name":"STRING","type":"STRING","links":null},{"localized_name":"INDEX","name":"INDEX","type":"INT","links":[11]}],"properties":{"Node name for S&R":"CustomCombo"},"widgets_values":["Gaussian",0,"Gaussian","Box","Radial",""]},{"id":10,"type":"PrimitiveFloat","pos":[4020,-2780],"size":[270,58],"flags":{},"order":1,"mode":0,"inputs":[{"label":"strength","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[10]}],"properties":{"Node name for S&R":"PrimitiveFloat","max":100,"min":0},"widgets_values":[20]},{"id":1,"type":"GLSLShader","pos":[4020,-2670],"size":[430,212],"flags":{},"order":2,"mode":0,"inputs":[{"label":"image0","localized_name":"images.image0","name":"images.image0","type":"IMAGE","link":9},{"label":"image1","localized_name":"images.image1","name":"images.image1","shape":7,"type":"IMAGE","link":null},{"label":"u_float0","localized_name":"floats.u_float0","name":"floats.u_float0","shape":7,"type":"FLOAT","link":10},{"label":"u_float1","localized_name":"floats.u_float1","name":"floats.u_float1","shape":7,"type":"FLOAT","link":null},{"label":"u_int0","localized_name":"ints.u_int0","name":"ints.u_int0","shape":7,"type":"INT","link":11},{"label":"u_int1","localized_name":"ints.u_int1","name":"ints.u_int1","shape":7,"type":"INT","link":null},{"localized_name":"fragment_shader","name":"fragment_shader","type":"STRING","widget":{"name":"fragment_shader"},"link":null},{"localized_name":"size_mode","name":"size_mode","type":"COMFY_DYNAMICCOMBO_V3","widget":{"name":"size_mode"},"link":null}],"outputs":[{"localized_name":"IMAGE0","name":"IMAGE0","type":"IMAGE","links":[3]},{"localized_name":"IMAGE1","name":"IMAGE1","type":"IMAGE","links":[]},{"localized_name":"IMAGE2","name":"IMAGE2","type":"IMAGE","links":[]},{"localized_name":"IMAGE3","name":"IMAGE3","type":"IMAGE","links":[]}],"properties":{"Node name for S&R":"GLSLShader"},"widgets_values":["#version 300 es\nprecision highp float;\n\n// Blur type constants\nconst int BLUR_GAUSSIAN = 0;\nconst int BLUR_BOX = 1;\nconst int BLUR_RADIAL = 2;\n\n// Radial blur config\nconst int RADIAL_SAMPLES = 12;\nconst float RADIAL_STRENGTH = 0.0003;\n\nuniform sampler2D u_image0;\nuniform vec2 u_resolution;\nuniform int u_int0; // Blur type (BLUR_GAUSSIAN, BLUR_BOX, BLUR_RADIAL)\nuniform float u_float0; // Blur radius/amount\n\nin vec2 v_texCoord;\nlayout(location = 0) out vec4 fragColor0;\n\nfloat gaussian(float x, float sigma) {\n return exp(-(x * x) / (2.0 * sigma * sigma));\n}\n\nvoid main() {\n vec2 texelSize = 1.0 / u_resolution;\n float radius = max(u_float0, 0.0);\n \n // Radial (angular) blur\n if (u_int0 == BLUR_RADIAL) {\n vec2 center = vec2(0.5);\n vec2 dir = v_texCoord - center;\n float dist = length(dir);\n \n // Avoid division by zero\n if (dist < 1e-4) {\n fragColor0 = texture(u_image0, v_texCoord);\n return;\n }\n \n vec4 sum = vec4(0.0);\n float totalWeight = 0.0;\n float angleStep = radius * RADIAL_STRENGTH;\n \n dir /= dist;\n \n for (int i = -RADIAL_SAMPLES; i <= RADIAL_SAMPLES; i++) {\n float a = float(i) * angleStep;\n float s = sin(a);\n float c = cos(a);\n vec2 rotatedDir = vec2(\n dir.x * c - dir.y * s,\n dir.x * s + dir.y * c\n );\n vec2 uv = center + rotatedDir * dist;\n float w = 1.0 - abs(float(i)) / float(RADIAL_SAMPLES);\n sum += texture(u_image0, uv) * w;\n totalWeight += w;\n }\n \n fragColor0 = sum / totalWeight;\n return;\n }\n \n // Gaussian / Box blur\n int samples = int(ceil(radius));\n \n if (samples == 0) {\n fragColor0 = texture(u_image0, v_texCoord);\n return;\n }\n \n vec4 color = vec4(0.0);\n float totalWeight = 0.0;\n float sigma = radius / 2.0;\n \n for (int x = -samples; x <= samples; x++) {\n for (int y = -samples; y <= samples; y++) {\n vec2 offset = vec2(float(x), float(y)) * texelSize;\n vec4 sample_color = texture(u_image0, v_texCoord + offset);\n \n float weight;\n if (u_int0 == BLUR_GAUSSIAN) {\n float dist = length(vec2(float(x), float(y)));\n weight = gaussian(dist, sigma);\n } else {\n // BLUR_BOX\n weight = 1.0;\n }\n \n color += sample_color * weight;\n totalWeight += weight;\n }\n }\n \n fragColor0 = color / totalWeight;\n}\n","from_input"]}],"groups":[],"links":[{"id":10,"origin_id":10,"origin_slot":0,"target_id":1,"target_slot":2,"type":"FLOAT"},{"id":11,"origin_id":12,"origin_slot":1,"target_id":1,"target_slot":4,"type":"INT"},{"id":9,"origin_id":-10,"origin_slot":0,"target_id":1,"target_slot":0,"type":"IMAGE"},{"id":3,"origin_id":1,"origin_slot":0,"target_id":-20,"target_slot":0,"type":"IMAGE"}],"extra":{"workflowRendererVersion":"LG"}}]}} \ No newline at end of file diff --git a/blueprints/Image Levels.json b/blueprints/Image Levels.json new file mode 100644 index 000000000..bc378df47 --- /dev/null +++ b/blueprints/Image Levels.json @@ -0,0 +1 @@ +{"revision":0,"last_node_id":12,"last_link_id":0,"nodes":[{"id":12,"type":"96a4f053-914f-4a57-82b5-efaddfb15b5a","pos":[4280,-3790],"size":[240,178],"flags":{},"order":1,"mode":0,"inputs":[{"label":"image","localized_name":"images.image0","name":"images.image0","type":"IMAGE","link":null}],"outputs":[{"label":"IMAGE","localized_name":"IMAGE0","name":"IMAGE0","type":"IMAGE","links":[]}],"title":"Image Levels","properties":{"proxyWidgets":[["5","choice"],["3","value"],["6","value"],["7","value"],["8","value"],["9","value"]]},"widgets_values":[]}],"links":[],"version":0.4,"definitions":{"subgraphs":[{"id":"96a4f053-914f-4a57-82b5-efaddfb15b5a","version":1,"state":{"lastGroupId":0,"lastNodeId":11,"lastLinkId":8,"lastRerouteId":0},"revision":0,"config":{},"name":"Image Levels","inputNode":{"id":-10,"bounding":[3840,-3430,120,60]},"outputNode":{"id":-20,"bounding":[4950,-3430,120,60]},"inputs":[{"id":"b53e5012-fa47-400f-a324-28c74854ccae","name":"images.image0","type":"IMAGE","linkIds":[1],"localized_name":"images.image0","label":"image","pos":[3940,-3410]}],"outputs":[{"id":"de7f2ffa-155f-41fd-b054-aa4d91ef49ca","name":"IMAGE0","type":"IMAGE","linkIds":[8],"localized_name":"IMAGE0","label":"IMAGE","pos":[4970,-3410]}],"widgets":[],"nodes":[{"id":5,"type":"CustomCombo","pos":[4020,-3350],"size":[270,198],"flags":{},"order":0,"mode":0,"inputs":[{"label":"channel","localized_name":"choice","name":"choice","type":"COMBO","widget":{"name":"choice"},"link":null}],"outputs":[{"localized_name":"STRING","name":"STRING","type":"STRING","links":null},{"localized_name":"INDEX","name":"INDEX","type":"INT","links":[3]}],"title":"Channel","properties":{"Node name for S&R":"CustomCombo"},"widgets_values":["RGB",0,"RGB","R","G","B",""]},{"id":8,"type":"PrimitiveFloat","pos":[4020,-3550],"size":[270,58],"flags":{},"order":1,"mode":0,"inputs":[{"label":"output_black","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[6]}],"title":"Output Black","properties":{"Node name for S&R":"PrimitiveFloat","max":255,"min":0,"step":1},"widgets_values":[0]},{"id":9,"type":"PrimitiveFloat","pos":[4020,-3450],"size":[270,58],"flags":{},"order":2,"mode":0,"inputs":[{"label":"output_white","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[7]}],"title":"Output White","properties":{"Node name for S&R":"PrimitiveFloat","max":255,"min":0,"step":1},"widgets_values":[255]},{"id":3,"type":"PrimitiveFloat","pos":[4020,-3850],"size":[270,58],"flags":{},"order":3,"mode":0,"inputs":[{"label":"input_black","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[2]}],"title":"Input Black","properties":{"Node name for S&R":"PrimitiveFloat","min":0,"max":255,"step":1},"widgets_values":[0]},{"id":6,"type":"PrimitiveFloat","pos":[4020,-3750],"size":[270,58],"flags":{},"order":4,"mode":0,"inputs":[{"label":"input_white","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[4]}],"title":"Input White","properties":{"Node name for S&R":"PrimitiveFloat","max":255,"min":0,"step":1},"widgets_values":[255]},{"id":7,"type":"PrimitiveFloat","pos":[4020,-3650],"size":[270,58],"flags":{},"order":5,"mode":0,"inputs":[{"label":"gamma","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[5]}],"title":"Gamma","properties":{"Node name for S&R":"PrimitiveFloat","max":10,"min":0,"step":0.01},"widgets_values":[1]},{"id":1,"type":"GLSLShader","pos":[4310,-3850],"size":[580,272],"flags":{},"order":6,"mode":0,"inputs":[{"label":"image0","localized_name":"images.image0","name":"images.image0","type":"IMAGE","link":1},{"label":"image1","localized_name":"images.image1","name":"images.image1","shape":7,"type":"IMAGE","link":null},{"label":"u_float0","localized_name":"floats.u_float0","name":"floats.u_float0","shape":7,"type":"FLOAT","link":2},{"label":"u_float1","localized_name":"floats.u_float1","name":"floats.u_float1","shape":7,"type":"FLOAT","link":4},{"label":"u_float2","localized_name":"floats.u_float2","name":"floats.u_float2","shape":7,"type":"FLOAT","link":5},{"label":"u_float3","localized_name":"floats.u_float3","name":"floats.u_float3","shape":7,"type":"FLOAT","link":6},{"label":"u_float4","localized_name":"floats.u_float4","name":"floats.u_float4","shape":7,"type":"FLOAT","link":7},{"label":"u_int0","localized_name":"ints.u_int0","name":"ints.u_int0","shape":7,"type":"INT","link":3},{"label":"u_int1","localized_name":"ints.u_int1","name":"ints.u_int1","shape":7,"type":"INT","link":null},{"localized_name":"fragment_shader","name":"fragment_shader","type":"STRING","widget":{"name":"fragment_shader"},"link":null},{"localized_name":"size_mode","name":"size_mode","type":"COMFY_DYNAMICCOMBO_V3","widget":{"name":"size_mode"},"link":null}],"outputs":[{"localized_name":"IMAGE0","name":"IMAGE0","type":"IMAGE","links":[8]},{"localized_name":"IMAGE1","name":"IMAGE1","type":"IMAGE","links":null},{"localized_name":"IMAGE2","name":"IMAGE2","type":"IMAGE","links":null},{"localized_name":"IMAGE3","name":"IMAGE3","type":"IMAGE","links":null}],"properties":{"Node name for S&R":"GLSLShader"},"widgets_values":["#version 300 es\nprecision highp float;\n\n// Levels Adjustment\n// u_int0: channel (0=RGB, 1=R, 2=G, 3=B) default: 0\n// u_float0: input black (0-255) default: 0\n// u_float1: input white (0-255) default: 255\n// u_float2: gamma (0.01-9.99) default: 1.0\n// u_float3: output black (0-255) default: 0\n// u_float4: output white (0-255) default: 255\n\nuniform sampler2D u_image0;\nuniform int u_int0;\nuniform float u_float0;\nuniform float u_float1;\nuniform float u_float2;\nuniform float u_float3;\nuniform float u_float4;\n\nin vec2 v_texCoord;\nout vec4 fragColor;\n\nvec3 applyLevels(vec3 color, float inBlack, float inWhite, float gamma, float outBlack, float outWhite) {\n float inRange = max(inWhite - inBlack, 0.0001);\n vec3 result = clamp((color - inBlack) / inRange, 0.0, 1.0);\n result = pow(result, vec3(1.0 / gamma));\n result = mix(vec3(outBlack), vec3(outWhite), result);\n return result;\n}\n\nfloat applySingleChannel(float value, float inBlack, float inWhite, float gamma, float outBlack, float outWhite) {\n float inRange = max(inWhite - inBlack, 0.0001);\n float result = clamp((value - inBlack) / inRange, 0.0, 1.0);\n result = pow(result, 1.0 / gamma);\n result = mix(outBlack, outWhite, result);\n return result;\n}\n\nvoid main() {\n vec4 texColor = texture(u_image0, v_texCoord);\n vec3 color = texColor.rgb;\n \n float inBlack = u_float0 / 255.0;\n float inWhite = u_float1 / 255.0;\n float gamma = u_float2;\n float outBlack = u_float3 / 255.0;\n float outWhite = u_float4 / 255.0;\n \n vec3 result;\n \n if (u_int0 == 0) {\n result = applyLevels(color, inBlack, inWhite, gamma, outBlack, outWhite);\n }\n else if (u_int0 == 1) {\n result = color;\n result.r = applySingleChannel(color.r, inBlack, inWhite, gamma, outBlack, outWhite);\n }\n else if (u_int0 == 2) {\n result = color;\n result.g = applySingleChannel(color.g, inBlack, inWhite, gamma, outBlack, outWhite);\n }\n else if (u_int0 == 3) {\n result = color;\n result.b = applySingleChannel(color.b, inBlack, inWhite, gamma, outBlack, outWhite);\n }\n else {\n result = color;\n }\n \n fragColor = vec4(result, texColor.a);\n}","from_input"]}],"groups":[],"links":[{"id":2,"origin_id":3,"origin_slot":0,"target_id":1,"target_slot":2,"type":"FLOAT"},{"id":4,"origin_id":6,"origin_slot":0,"target_id":1,"target_slot":3,"type":"FLOAT"},{"id":5,"origin_id":7,"origin_slot":0,"target_id":1,"target_slot":4,"type":"FLOAT"},{"id":6,"origin_id":8,"origin_slot":0,"target_id":1,"target_slot":5,"type":"FLOAT"},{"id":7,"origin_id":9,"origin_slot":0,"target_id":1,"target_slot":6,"type":"FLOAT"},{"id":3,"origin_id":5,"origin_slot":1,"target_id":1,"target_slot":7,"type":"INT"},{"id":1,"origin_id":-10,"origin_slot":0,"target_id":1,"target_slot":0,"type":"IMAGE"},{"id":8,"origin_id":1,"origin_slot":0,"target_id":-20,"target_slot":0,"type":"IMAGE"}],"extra":{"workflowRendererVersion":"LG"}}]}} \ No newline at end of file diff --git a/blueprints/Sharpen.json b/blueprints/Sharpen.json new file mode 100644 index 000000000..49a164eca --- /dev/null +++ b/blueprints/Sharpen.json @@ -0,0 +1 @@ +{"revision":0,"last_node_id":25,"last_link_id":0,"nodes":[{"id":25,"type":"621ba4e2-22a8-482d-a369-023753198b7b","pos":[4610,-790],"size":[230,58],"flags":{},"order":4,"mode":0,"inputs":[{"label":"image","localized_name":"images.image0","name":"images.image0","type":"IMAGE","link":null}],"outputs":[{"label":"IMAGE","localized_name":"IMAGE0","name":"IMAGE0","type":"IMAGE","links":[]}],"title":"Sharpen","properties":{"proxyWidgets":[["24","value"]]},"widgets_values":[]}],"links":[],"version":0.4,"definitions":{"subgraphs":[{"id":"621ba4e2-22a8-482d-a369-023753198b7b","version":1,"state":{"lastGroupId":0,"lastNodeId":24,"lastLinkId":36,"lastRerouteId":0},"revision":0,"config":{},"name":"Sharpen","inputNode":{"id":-10,"bounding":[4090,-825,120,60]},"outputNode":{"id":-20,"bounding":[5150,-825,120,60]},"inputs":[{"id":"37011fb7-14b7-4e0e-b1a0-6a02e8da1fd7","name":"images.image0","type":"IMAGE","linkIds":[34],"localized_name":"images.image0","label":"image","pos":[4190,-805]}],"outputs":[{"id":"e9182b3f-635c-4cd4-a152-4b4be17ae4b9","name":"IMAGE0","type":"IMAGE","linkIds":[35],"localized_name":"IMAGE0","label":"IMAGE","pos":[5170,-805]}],"widgets":[],"nodes":[{"id":24,"type":"PrimitiveFloat","pos":[4280,-1240],"size":[270,58],"flags":{},"order":0,"mode":0,"inputs":[{"label":"strength","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[36]}],"properties":{"Node name for S&R":"PrimitiveFloat","min":0,"max":3,"precision":2,"step":0.05},"widgets_values":[0.5]},{"id":23,"type":"GLSLShader","pos":[4570,-1240],"size":[370,192],"flags":{},"order":1,"mode":0,"inputs":[{"label":"image0","localized_name":"images.image0","name":"images.image0","type":"IMAGE","link":34},{"label":"image1","localized_name":"images.image1","name":"images.image1","shape":7,"type":"IMAGE","link":null},{"label":"u_float0","localized_name":"floats.u_float0","name":"floats.u_float0","shape":7,"type":"FLOAT","link":36},{"label":"u_float1","localized_name":"floats.u_float1","name":"floats.u_float1","shape":7,"type":"FLOAT","link":null},{"label":"u_int0","localized_name":"ints.u_int0","name":"ints.u_int0","shape":7,"type":"INT","link":null},{"localized_name":"fragment_shader","name":"fragment_shader","type":"STRING","widget":{"name":"fragment_shader"},"link":null},{"localized_name":"size_mode","name":"size_mode","type":"COMFY_DYNAMICCOMBO_V3","widget":{"name":"size_mode"},"link":null}],"outputs":[{"localized_name":"IMAGE0","name":"IMAGE0","type":"IMAGE","links":[35]},{"localized_name":"IMAGE1","name":"IMAGE1","type":"IMAGE","links":null},{"localized_name":"IMAGE2","name":"IMAGE2","type":"IMAGE","links":null},{"localized_name":"IMAGE3","name":"IMAGE3","type":"IMAGE","links":null}],"properties":{"Node name for S&R":"GLSLShader"},"widgets_values":["#version 300 es\nprecision highp float;\n\nuniform sampler2D u_image0;\nuniform vec2 u_resolution;\nuniform float u_float0; // strength [0.0 – 2.0] typical: 0.3–1.0\n\nin vec2 v_texCoord;\nlayout(location = 0) out vec4 fragColor0;\n\nvoid main() {\n vec2 texel = 1.0 / u_resolution;\n \n // Sample center and neighbors\n vec4 center = texture(u_image0, v_texCoord);\n vec4 top = texture(u_image0, v_texCoord + vec2( 0.0, -texel.y));\n vec4 bottom = texture(u_image0, v_texCoord + vec2( 0.0, texel.y));\n vec4 left = texture(u_image0, v_texCoord + vec2(-texel.x, 0.0));\n vec4 right = texture(u_image0, v_texCoord + vec2( texel.x, 0.0));\n \n // Edge enhancement (Laplacian)\n vec4 edges = center * 4.0 - top - bottom - left - right;\n \n // Add edges back scaled by strength\n vec4 sharpened = center + edges * u_float0;\n \n fragColor0 = vec4(clamp(sharpened.rgb, 0.0, 1.0), center.a);\n}","from_input"]}],"groups":[],"links":[{"id":36,"origin_id":24,"origin_slot":0,"target_id":23,"target_slot":2,"type":"FLOAT"},{"id":34,"origin_id":-10,"origin_slot":0,"target_id":23,"target_slot":0,"type":"IMAGE"},{"id":35,"origin_id":23,"origin_slot":0,"target_id":-20,"target_slot":0,"type":"IMAGE"}],"extra":{"workflowRendererVersion":"LG"}}]}} \ No newline at end of file diff --git a/blueprints/Unsharp Mask.json b/blueprints/Unsharp Mask.json new file mode 100644 index 000000000..0518f1dcc --- /dev/null +++ b/blueprints/Unsharp Mask.json @@ -0,0 +1 @@ +{"revision":0,"last_node_id":30,"last_link_id":0,"nodes":[{"id":30,"type":"d99ba3f5-8a56-4365-8e45-3f3ea7c572a1","pos":[4420,-370],"size":[210,106],"flags":{},"order":4,"mode":0,"inputs":[{"label":"image0","localized_name":"images.image0","name":"images.image0","type":"IMAGE","link":null}],"outputs":[{"localized_name":"IMAGE0","name":"IMAGE0","type":"IMAGE","links":[]}],"title":"Unsharp Mask","properties":{"proxyWidgets":[["27","value"],["28","value"],["29","value"]]},"widgets_values":[]}],"links":[],"version":0.4,"definitions":{"subgraphs":[{"id":"d99ba3f5-8a56-4365-8e45-3f3ea7c572a1","version":1,"state":{"lastGroupId":0,"lastNodeId":29,"lastLinkId":43,"lastRerouteId":0},"revision":0,"config":{},"name":"Unsharp Mask","inputNode":{"id":-10,"bounding":[3920,-405,120,60]},"outputNode":{"id":-20,"bounding":[4930,-405,120,60]},"inputs":[{"id":"75354555-d2f3-46b9-a3dd-b076dcfca561","name":"images.image0","type":"IMAGE","linkIds":[39],"localized_name":"images.image0","label":"image0","pos":[4020,-385]}],"outputs":[{"id":"04368b94-2a96-46ff-8c07-d0ce3235b40d","name":"IMAGE0","type":"IMAGE","linkIds":[40],"localized_name":"IMAGE0","pos":[4950,-385]}],"widgets":[],"nodes":[{"id":27,"type":"PrimitiveFloat","pos":[4100,-540],"size":[270,58],"flags":{},"order":0,"mode":0,"inputs":[{"label":"amount","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[41]}],"properties":{"Node name for S&R":"PrimitiveFloat","min":0,"max":3,"precision":2,"step":0.05},"widgets_values":[1]},{"id":28,"type":"PrimitiveFloat","pos":[4100,-430],"size":[270,58],"flags":{},"order":1,"mode":0,"inputs":[{"label":"radius","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[42]}],"properties":{"Node name for S&R":"PrimitiveFloat","min":0,"max":10,"precision":1,"step":0.5},"widgets_values":[3]},{"id":29,"type":"PrimitiveFloat","pos":[4100,-320],"size":[270,58],"flags":{},"order":2,"mode":0,"inputs":[{"label":"threshold","localized_name":"value","name":"value","type":"FLOAT","widget":{"name":"value"},"link":null}],"outputs":[{"localized_name":"FLOAT","name":"FLOAT","type":"FLOAT","links":[43]}],"properties":{"Node name for S&R":"PrimitiveFloat","min":0,"max":1,"precision":2,"step":0.05},"widgets_values":[0]},{"id":26,"type":"GLSLShader","pos":[4470,-580],"size":[400,232],"flags":{},"order":3,"mode":0,"inputs":[{"label":"image0","localized_name":"images.image0","name":"images.image0","type":"IMAGE","link":39},{"label":"image1","localized_name":"images.image1","name":"images.image1","shape":7,"type":"IMAGE","link":null},{"label":"u_float0","localized_name":"floats.u_float0","name":"floats.u_float0","shape":7,"type":"FLOAT","link":41},{"label":"u_float1","localized_name":"floats.u_float1","name":"floats.u_float1","shape":7,"type":"FLOAT","link":42},{"label":"u_float2","localized_name":"floats.u_float2","name":"floats.u_float2","shape":7,"type":"FLOAT","link":43},{"label":"u_float3","localized_name":"floats.u_float3","name":"floats.u_float3","shape":7,"type":"FLOAT","link":null},{"label":"u_int0","localized_name":"ints.u_int0","name":"ints.u_int0","shape":7,"type":"INT","link":null},{"localized_name":"fragment_shader","name":"fragment_shader","type":"STRING","widget":{"name":"fragment_shader"},"link":null},{"localized_name":"size_mode","name":"size_mode","type":"COMFY_DYNAMICCOMBO_V3","widget":{"name":"size_mode"},"link":null}],"outputs":[{"localized_name":"IMAGE0","name":"IMAGE0","type":"IMAGE","links":[40]},{"localized_name":"IMAGE1","name":"IMAGE1","type":"IMAGE","links":null},{"localized_name":"IMAGE2","name":"IMAGE2","type":"IMAGE","links":null},{"localized_name":"IMAGE3","name":"IMAGE3","type":"IMAGE","links":null}],"properties":{"Node name for S&R":"GLSLShader"},"widgets_values":["#version 300 es\nprecision highp float;\n\nuniform sampler2D u_image0;\nuniform vec2 u_resolution;\nuniform float u_float0; // amount [0.0 – 3.0] typical: 0.5–1.5\nuniform float u_float1; // radius [0.5 – 10.0] blur radius in pixels\nuniform float u_float2; // threshold [0.0 – 0.1] min difference to sharpen\n\nin vec2 v_texCoord;\nlayout(location = 0) out vec4 fragColor0;\n\nfloat gaussian(float x, float sigma) {\n return exp(-(x * x) / (2.0 * sigma * sigma));\n}\n\nfloat getLuminance(vec3 color) {\n return dot(color, vec3(0.2126, 0.7152, 0.0722));\n}\n\nvoid main() {\n vec2 texel = 1.0 / u_resolution;\n float radius = max(u_float1, 0.5);\n float amount = u_float0;\n float threshold = u_float2;\n \n vec4 original = texture(u_image0, v_texCoord);\n \n // Gaussian blur for the \"unsharp\" mask\n int samples = int(ceil(radius));\n float sigma = radius / 2.0;\n \n vec4 blurred = vec4(0.0);\n float totalWeight = 0.0;\n \n for (int x = -samples; x <= samples; x++) {\n for (int y = -samples; y <= samples; y++) {\n vec2 offset = vec2(float(x), float(y)) * texel;\n vec2 sampleCoord = v_texCoord + offset;\n \n // Boundary check - skip out-of-bounds samples\n if (sampleCoord.x < 0.0 || sampleCoord.x > 1.0 ||\n sampleCoord.y < 0.0 || sampleCoord.y > 1.0) {\n continue;\n }\n \n float dist = length(vec2(float(x), float(y)));\n float weight = gaussian(dist, sigma);\n blurred += texture(u_image0, sampleCoord) * weight;\n totalWeight += weight;\n }\n }\n blurred /= totalWeight;\n \n // Unsharp mask = original - blurred\n vec3 mask = original.rgb - blurred.rgb;\n \n // Luminance-based threshold (Photoshop-style)\n float lumaDelta = abs(getLuminance(original.rgb) - getLuminance(blurred.rgb));\n if (lumaDelta < threshold) {\n mask = vec3(0.0);\n }\n \n // Sharpen: original + mask * amount\n vec3 sharpened = original.rgb + mask * amount;\n \n fragColor0 = vec4(clamp(sharpened, 0.0, 1.0), original.a);\n}\n","from_input"]}],"groups":[],"links":[{"id":41,"origin_id":27,"origin_slot":0,"target_id":26,"target_slot":2,"type":"FLOAT"},{"id":42,"origin_id":28,"origin_slot":0,"target_id":26,"target_slot":3,"type":"FLOAT"},{"id":43,"origin_id":29,"origin_slot":0,"target_id":26,"target_slot":4,"type":"FLOAT"},{"id":39,"origin_id":-10,"origin_slot":0,"target_id":26,"target_slot":0,"type":"IMAGE"},{"id":40,"origin_id":26,"origin_slot":0,"target_id":-20,"target_slot":0,"type":"IMAGE"}],"extra":{"workflowRendererVersion":"LG"}}]}} \ No newline at end of file