ComfyUI/blueprints/Film Grain.json
linmoumou cc3e622d9f Add description field to all blueprint subgraphs
Sets the 'description' field on every subgraph blueprint node,
which will show on the node preview and tooltip. Covers all 51
blueprint files under blueprints/.
2026-05-08 10:20:49 +08:00

588 lines
18 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 \u2013 1.0] typical: 0.2\u20130.8\nuniform float u_float1; // grain size [0.3 \u2013 3.0] lower = finer grain\nuniform float u_float2; // color amount [0.0 \u2013 1.0] 0 = monochrome, 1 = RGB grain\nuniform float u_float3; // luminance bias [0.0 \u2013 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"
},
"category": "Image Tools/Color adjust",
"description": "Adds authentic film grain texture for a cinematic look."
}
]
}
}