mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-02-07 03:52:32 +08:00
125 lines
3.8 KiB
GLSL
125 lines
3.8 KiB
GLSL
#version 300 es
|
||
precision highp float;
|
||
|
||
uniform sampler2D u_image0;
|
||
uniform vec2 u_resolution;
|
||
uniform float u_float0; // grain amount [0.0 – 1.0] typical: 0.2–0.8
|
||
uniform float u_float1; // grain size [0.3 – 3.0] lower = finer grain
|
||
uniform float u_float2; // color amount [0.0 – 1.0] 0 = monochrome, 1 = RGB grain
|
||
uniform float u_float3; // luminance bias [0.0 – 1.0] 0 = uniform, 1 = shadows only
|
||
uniform int u_int0; // noise mode [0 or 1] 0 = smooth, 1 = grainy
|
||
|
||
in vec2 v_texCoord;
|
||
layout(location = 0) out vec4 fragColor0;
|
||
|
||
// High-quality integer hash (pcg-like)
|
||
uint pcg(uint v) {
|
||
uint state = v * 747796405u + 2891336453u;
|
||
uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
|
||
return (word >> 22u) ^ word;
|
||
}
|
||
|
||
// 2D -> 1D hash input
|
||
uint hash2d(uvec2 p) {
|
||
return pcg(p.x + pcg(p.y));
|
||
}
|
||
|
||
// Hash to float [0, 1]
|
||
float hashf(uvec2 p) {
|
||
return float(hash2d(p)) / float(0xffffffffu);
|
||
}
|
||
|
||
// Hash to float with offset (for RGB channels)
|
||
float hashf(uvec2 p, uint offset) {
|
||
return float(pcg(hash2d(p) + offset)) / float(0xffffffffu);
|
||
}
|
||
|
||
// Convert uniform [0,1] to roughly Gaussian distribution
|
||
// Using simple approximation: average of multiple samples
|
||
float toGaussian(uvec2 p) {
|
||
float sum = hashf(p, 0u) + hashf(p, 1u) + hashf(p, 2u) + hashf(p, 3u);
|
||
return (sum - 2.0) * 0.7; // Centered, scaled
|
||
}
|
||
|
||
float toGaussian(uvec2 p, uint offset) {
|
||
float sum = hashf(p, offset) + hashf(p, offset + 1u)
|
||
+ hashf(p, offset + 2u) + hashf(p, offset + 3u);
|
||
return (sum - 2.0) * 0.7;
|
||
}
|
||
|
||
// Smooth noise with better interpolation
|
||
float smoothNoise(vec2 p) {
|
||
vec2 i = floor(p);
|
||
vec2 f = fract(p);
|
||
|
||
// Quintic interpolation (less banding than cubic)
|
||
f = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);
|
||
|
||
uvec2 ui = uvec2(i);
|
||
float a = toGaussian(ui);
|
||
float b = toGaussian(ui + uvec2(1u, 0u));
|
||
float c = toGaussian(ui + uvec2(0u, 1u));
|
||
float d = toGaussian(ui + uvec2(1u, 1u));
|
||
|
||
return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
|
||
}
|
||
|
||
float smoothNoise(vec2 p, uint offset) {
|
||
vec2 i = floor(p);
|
||
vec2 f = fract(p);
|
||
|
||
f = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);
|
||
|
||
uvec2 ui = uvec2(i);
|
||
float a = toGaussian(ui, offset);
|
||
float b = toGaussian(ui + uvec2(1u, 0u), offset);
|
||
float c = toGaussian(ui + uvec2(0u, 1u), offset);
|
||
float d = toGaussian(ui + uvec2(1u, 1u), offset);
|
||
|
||
return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
|
||
}
|
||
|
||
void main() {
|
||
vec4 color = texture(u_image0, v_texCoord);
|
||
|
||
// Luminance (Rec.709)
|
||
float luma = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
|
||
|
||
// Grain UV (resolution-independent)
|
||
vec2 grainUV = v_texCoord * u_resolution / max(u_float1, 0.01);
|
||
uvec2 grainPixel = uvec2(grainUV);
|
||
|
||
float g;
|
||
vec3 grainRGB;
|
||
|
||
if (u_int0 == 1) {
|
||
// Grainy mode: pure hash noise (no interpolation = no banding)
|
||
g = toGaussian(grainPixel);
|
||
grainRGB = vec3(
|
||
toGaussian(grainPixel, 100u),
|
||
toGaussian(grainPixel, 200u),
|
||
toGaussian(grainPixel, 300u)
|
||
);
|
||
} else {
|
||
// Smooth mode: interpolated with quintic curve
|
||
g = smoothNoise(grainUV);
|
||
grainRGB = vec3(
|
||
smoothNoise(grainUV, 100u),
|
||
smoothNoise(grainUV, 200u),
|
||
smoothNoise(grainUV, 300u)
|
||
);
|
||
}
|
||
|
||
// Luminance weighting (less grain in highlights)
|
||
float lumWeight = mix(1.0, 1.0 - luma, clamp(u_float3, 0.0, 1.0));
|
||
|
||
// Strength
|
||
float strength = u_float0 * 0.15;
|
||
|
||
// Color vs monochrome grain
|
||
vec3 grainColor = mix(vec3(g), grainRGB, clamp(u_float2, 0.0, 1.0));
|
||
|
||
color.rgb += grainColor * strength * lumWeight;
|
||
fragColor0 = vec4(clamp(color.rgb, 0.0, 1.0), color.a);
|
||
}
|