shader nit iteration

This commit is contained in:
pythongosssss 2026-01-31 16:03:47 -08:00
parent 0050b66a0b
commit 292a5918f4
16 changed files with 113 additions and 127 deletions

View File

@ -8,14 +8,15 @@ uniform float u_float1; // Contrast slider -100..100
in vec2 v_texCoord;
out vec4 fragColor;
const float EPSILON = 1e-5;
const float MID_GRAY = 0.18; // 18% reflectance
// sRGB gamma 2.2 approximation
vec3 srgbToLinear(vec3 c) {
return pow(c, vec3(2.2));
return pow(max(c, 0.0), vec3(2.2));
}
vec3 linearToSrgb(vec3 c) {
return pow(c, vec3(1.0/2.2));
return pow(max(c, 0.0), vec3(1.0/2.2));
}
float mapBrightness(float b) {
@ -32,15 +33,9 @@ void main() {
float brightness = mapBrightness(u_float0);
float contrast = mapContrast(u_float1);
// Early exit if no adjustment
if (abs(brightness) < EPSILON && abs(contrast - 1.0) < EPSILON) {
fragColor = orig;
return;
}
vec3 lin = srgbToLinear(orig.rgb);
lin = (lin - 0.5) * contrast + brightness + 0.5;
lin = (lin - MID_GRAY) * contrast + brightness + MID_GRAY;
// Convert back to sRGB
vec3 result = linearToSrgb(clamp(lin, 0.0, 1.0));

View File

@ -14,21 +14,26 @@ const int MODE_BARREL = 2;
const int MODE_SWIRL = 3;
const int MODE_DIAGONAL = 4;
const float AMOUNT_SCALE = 0.0005;
const float RADIAL_MULT = 4.0;
const float BARREL_MULT = 8.0;
const float INV_SQRT2 = 0.70710678118;
void main() {
vec2 uv = v_texCoord;
vec4 original = texture(u_image0, uv);
float amount = u_float0 * 0.0005;
float amount = u_float0 * AMOUNT_SCALE;
if (amount == 0.0) {
if (amount < 0.000001) {
fragColor = original;
return;
}
vec2 centered = uv - 0.5;
float r = length(centered);
vec2 dir = normalize(centered + 0.001);
vec2 offset;
vec2 dir = r > 0.0001 ? centered / r : vec2(0.0);
vec2 offset = vec2(0.0);
if (u_int0 == MODE_LINEAR) {
// Horizontal shift
@ -36,20 +41,20 @@ void main() {
}
else if (u_int0 == MODE_RADIAL) {
// Outward from center, stronger at edges
offset = dir * r * amount * 4.0;
offset = dir * r * amount * RADIAL_MULT;
}
else if (u_int0 == MODE_BARREL) {
// Lens distortion simulation (r² falloff)
offset = dir * r * r * amount * 8.0;
offset = dir * r * r * amount * BARREL_MULT;
}
else if (u_int0 == MODE_SWIRL) {
// Perpendicular to radial (rotational aberration)
vec2 perp = vec2(-dir.y, dir.x);
offset = perp * r * amount * 4.0;
offset = perp * r * amount * RADIAL_MULT;
}
else if (u_int0 == MODE_DIAGONAL) {
// 45° offset
offset = vec2(amount, amount) * 0.707;
offset = vec2(amount, amount) * INV_SQRT2;
}
float red = texture(u_image0, uv + offset).r;

View File

@ -10,31 +10,43 @@ uniform float u_float3; // saturation (-100 to 100)
in vec2 v_texCoord;
out vec4 fragColor;
const float INPUT_SCALE = 0.01;
const float TEMP_TINT_PRIMARY = 0.3;
const float TEMP_TINT_SECONDARY = 0.15;
const float VIBRANCE_BOOST = 2.0;
const float SATURATION_BOOST = 2.0;
const float SKIN_PROTECTION = 0.5;
const float EPSILON = 0.001;
const vec3 LUMA_WEIGHTS = vec3(0.299, 0.587, 0.114);
void main() {
vec4 tex = texture(u_image0, v_texCoord);
vec3 color = tex.rgb;
// Scale inputs: -100/100 → -1/1
float temperature = u_float0 * 0.01;
float tint = u_float1 * 0.01;
float vibrance = u_float2 * 0.01;
float saturation = u_float3 * 0.01;
float temperature = u_float0 * INPUT_SCALE;
float tint = u_float1 * INPUT_SCALE;
float vibrance = u_float2 * INPUT_SCALE;
float saturation = u_float3 * INPUT_SCALE;
// Temperature (warm/cool): positive = warm, negative = cool
color.r = clamp(color.r + temperature * 0.3, 0.0, 1.0);
color.b = clamp(color.b - temperature * 0.3, 0.0, 1.0);
color.r += temperature * TEMP_TINT_PRIMARY;
color.b -= temperature * TEMP_TINT_PRIMARY;
// Tint (green/magenta): positive = green, negative = magenta
color.g = clamp(color.g + tint * 0.3, 0.0, 1.0);
color.r = clamp(color.r - tint * 0.15, 0.0, 1.0);
color.b = clamp(color.b - tint * 0.15, 0.0, 1.0);
color.g += tint * TEMP_TINT_PRIMARY;
color.r -= tint * TEMP_TINT_SECONDARY;
color.b -= tint * TEMP_TINT_SECONDARY;
// Vibrance Pro with skin protection
// Single clamp after temperature/tint
color = clamp(color, 0.0, 1.0);
// Vibrance with skin protection
if (vibrance != 0.0) {
float maxC = max(color.r, max(color.g, color.b));
float minC = min(color.r, min(color.g, color.b));
float sat = maxC - minC;
float gray = dot(color, vec3(0.299, 0.587, 0.114));
float gray = dot(color, LUMA_WEIGHTS);
if (vibrance < 0.0) {
// Desaturate: -100 → gray
@ -43,24 +55,22 @@ void main() {
// Boost less saturated colors more
float vibranceAmt = vibrance * (1.0 - sat);
// Skin tone protection (hardcoded 0.5)
float skinTone = 0.0;
if (color.r > color.g && color.g > color.b) {
float warmth = (color.r - color.b) / max(maxC, 0.001);
skinTone = warmth * sat * (1.0 - sat);
}
vibranceAmt *= (1.0 - skinTone * 0.5);
// Branchless skin tone protection
float isWarmTone = step(color.b, color.g) * step(color.g, color.r);
float warmth = (color.r - color.b) / max(maxC, EPSILON);
float skinTone = isWarmTone * warmth * sat * (1.0 - sat);
vibranceAmt *= (1.0 - skinTone * SKIN_PROTECTION);
color = mix(vec3(gray), color, 1.0 + vibranceAmt * 2.0);
color = mix(vec3(gray), color, 1.0 + vibranceAmt * VIBRANCE_BOOST);
}
}
// Saturation
if (saturation != 0.0) {
float gray = dot(color, vec3(0.299, 0.587, 0.114));
float gray = dot(color, LUMA_WEIGHTS);
float satMix = saturation < 0.0
? 1.0 + saturation // -100 → gray
: 1.0 + saturation * 2.0; // +100 → 3x boost
? 1.0 + saturation // -100 → gray
: 1.0 + saturation * SATURATION_BOOST; // +100 → 3x boost
color = mix(vec3(gray), color, satMix);
}

View File

@ -86,7 +86,7 @@ void main() {
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.001);
vec2 grainUV = v_texCoord * u_resolution / max(u_float1, 0.01);
uvec2 grainPixel = uvec2(grainUV);
float g;
@ -120,5 +120,5 @@ void main() {
vec3 grainColor = mix(vec3(g), grainRGB, clamp(u_float2, 0.0, 1.0));
color.rgb += grainColor * strength * lumWeight;
fragColor0 = vec4(color.rgb, color.a);
fragColor0 = vec4(clamp(color.rgb, 0.0, 1.0), color.a);
}

View File

@ -76,6 +76,7 @@ void main() {
float t1 = threshold + 0.15;
vec2 texelSize = 1.0 / u_resolution;
float aspect = u_resolution.x / u_resolution.y;
float radius2 = radius * radius;
float sampleScale = clamp(radius * 0.75, 0.35, 1.0);
@ -103,7 +104,7 @@ void main() {
float fi = float(i);
float dist = sqrt(fi / float(samples)) * radius * radiusJitter;
vec2 offset = dir * dist * texelSize;
vec2 offset = dir * dist * texelSize * vec2(1.0, aspect);
vec3 c = texture(u_image0, v_texCoord + offset).rgb;
float mask = smoothstep(t0, t1, dot(c, LUMA));
@ -120,7 +121,7 @@ void main() {
);
}
glow *= intensity / totalWeight;
glow *= intensity / max(totalWeight, 0.001);
if (u_int1 > 0) {
glow *= hexToRgb(u_int1);

View File

@ -106,23 +106,8 @@ vec3 rgb2hsb(vec3 c) {
}
vec3 hsb2rgb(vec3 hsb) {
float h = hsb.x * 6.0;
float s = hsb.y;
float b = hsb.z;
float c = b * s;
float x = c * (1.0 - abs(mod(h, 2.0) - 1.0));
float m = b - c;
vec3 rgb;
if (h < 1.0) rgb = vec3(c, x, 0.0);
else if (h < 2.0) rgb = vec3(x, c, 0.0);
else if (h < 3.0) rgb = vec3(0.0, c, x);
else if (h < 4.0) rgb = vec3(0.0, x, c);
else if (h < 5.0) rgb = vec3(x, 0.0, c);
else rgb = vec3(c, 0.0, x);
return rgb + m;
vec3 rgb = clamp(abs(mod(hsb.x * 6.0 + vec3(0.0, 4.0, 2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0);
return hsb.z * mix(vec3(1.0), rgb, hsb.y);
}
//=============================================================================
@ -149,16 +134,6 @@ float getHueWeight(float hue, float center, float overlap) {
float getModeWeight(float hue, int mode, float overlap) {
if (mode == MODE_MASTER || mode == MODE_COLORIZE) return 1.0;
float centers[6];
centers[0] = 0.0;
centers[1] = 1.0/6.0;
centers[2] = 2.0/6.0;
centers[3] = 3.0/6.0;
centers[4] = 4.0/6.0;
centers[5] = 5.0/6.0;
int idx = mode - 1;
if (mode == MODE_RED) {
return max(
getHueWeight(hue, 0.0, overlap),
@ -166,7 +141,8 @@ float getModeWeight(float hue, int mode, float overlap) {
);
}
return getHueWeight(hue, centers[idx], overlap);
float center = float(mode - 1) / 6.0;
return getHueWeight(hue, center, overlap);
}
//=============================================================================

View File

@ -25,60 +25,66 @@ float gaussian(float x, float sigma) {
void main() {
vec2 texelSize = 1.0 / u_resolution;
float radius = max(u_float0, 0.0);
// Radial (angular) blur
// Radial (angular) blur with incremental rotation
if (u_int0 == BLUR_RADIAL) {
vec2 center = vec2(0.5);
vec2 dir = v_texCoord - center;
float dist = length(dir);
// Avoid division by zero
if (dist < 1e-4) {
fragColor0 = texture(u_image0, v_texCoord);
return;
}
vec4 sum = vec4(0.0);
float totalWeight = 0.0;
float angleStep = radius * RADIAL_STRENGTH;
dir /= dist;
float cosStep = cos(angleStep);
float sinStep = sin(angleStep);
float negAngle = -float(RADIAL_SAMPLES) * angleStep;
vec2 rotDir = vec2(
dir.x * cos(negAngle) - dir.y * sin(negAngle),
dir.x * sin(negAngle) + dir.y * cos(negAngle)
);
for (int i = -RADIAL_SAMPLES; i <= RADIAL_SAMPLES; i++) {
float a = float(i) * angleStep;
float s = sin(a);
float c = cos(a);
vec2 rotatedDir = vec2(
dir.x * c - dir.y * s,
dir.x * s + dir.y * c
);
vec2 uv = center + rotatedDir * dist;
vec2 uv = center + rotDir * dist;
float w = 1.0 - abs(float(i)) / float(RADIAL_SAMPLES);
sum += texture(u_image0, uv) * w;
totalWeight += w;
rotDir = vec2(
rotDir.x * cosStep - rotDir.y * sinStep,
rotDir.x * sinStep + rotDir.y * cosStep
);
}
fragColor0 = sum / totalWeight;
fragColor0 = sum / max(totalWeight, 0.001);
return;
}
// Gaussian / Box blur
// Gaussian / Box blur (grid sampling)
int samples = int(ceil(radius));
if (samples == 0) {
fragColor0 = texture(u_image0, v_texCoord);
return;
}
vec4 color = vec4(0.0);
float totalWeight = 0.0;
float sigma = radius / 2.0;
for (int x = -samples; x <= samples; x++) {
for (int y = -samples; y <= samples; y++) {
vec2 offset = vec2(float(x), float(y)) * texelSize;
vec4 sample_color = texture(u_image0, v_texCoord + offset);
float weight;
if (u_int0 == BLUR_GAUSSIAN) {
float dist = length(vec2(float(x), float(y)));
@ -87,11 +93,11 @@ void main() {
// BLUR_BOX
weight = 1.0;
}
color += sample_color * weight;
totalWeight += weight;
}
}
fragColor0 = color / totalWeight;
}

View File

@ -3,9 +3,9 @@ precision highp float;
uniform sampler2D u_image0;
uniform vec2 u_resolution;
uniform float u_float0; // amount [0.0 3.0] typical: 0.51.5
uniform float u_float1; // radius [0.5 10.0] blur radius in pixels
uniform float u_float2; // threshold [0.0 0.1] min difference to sharpen
uniform float u_float0; // amount [0.0 - 3.0] typical: 0.5-1.5
uniform float u_float1; // radius [0.5 - 10.0] blur radius in pixels
uniform float u_float2; // threshold [0.0 - 0.1] min difference to sharpen
in vec2 v_texCoord;
layout(location = 0) out vec4 fragColor0;
@ -23,27 +23,21 @@ void main() {
float radius = max(u_float1, 0.5);
float amount = u_float0;
float threshold = u_float2;
vec4 original = texture(u_image0, v_texCoord);
// Gaussian blur for the "unsharp" mask
int samples = int(ceil(radius));
float sigma = radius / 2.0;
vec4 blurred = vec4(0.0);
float totalWeight = 0.0;
for (int x = -samples; x <= samples; x++) {
for (int y = -samples; y <= samples; y++) {
vec2 offset = vec2(float(x), float(y)) * texel;
vec2 sampleCoord = v_texCoord + offset;
// Boundary check - skip out-of-bounds samples
if (sampleCoord.x < 0.0 || sampleCoord.x > 1.0 ||
sampleCoord.y < 0.0 || sampleCoord.y > 1.0) {
continue;
}
float dist = length(vec2(float(x), float(y)));
float weight = gaussian(dist, sigma);
blurred += texture(u_image0, sampleCoord) * weight;
@ -51,18 +45,17 @@ void main() {
}
}
blurred /= totalWeight;
// Unsharp mask = original - blurred
vec3 mask = original.rgb - blurred.rgb;
// Luminance-based threshold (Photoshop-style)
// Luminance-based threshold with smooth falloff
float lumaDelta = abs(getLuminance(original.rgb) - getLuminance(blurred.rgb));
if (lumaDelta < threshold) {
mask = vec3(0.0);
}
float thresholdScale = smoothstep(0.0, threshold, lumaDelta);
mask *= thresholdScale;
// Sharpen: original + mask * amount
vec3 sharpened = original.rgb + mask * amount;
fragColor0 = vec4(clamp(sharpened, 0.0, 1.0), original.a);
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long