mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-02-04 02:30:21 +08:00
1 line
9.8 KiB
JSON
1 line
9.8 KiB
JSON
{"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.01);\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(clamp(color.rgb, 0.0, 1.0), 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"}}]}} |