tedit/shaders/vibrance.frag
2025-04-07 20:08:16 -04:00

79 lines
2.8 KiB
GLSL

#version 330 core
out vec4 FragColor;
in vec2 TexCoord;
uniform sampler2D InputTexture;
uniform float vibranceValue; // -100 to 100
const vec3 luminanceWeight = vec3(0.2126, 0.7152, 0.0722);
// Check if a color is potentially a skin tone (approximate)
float skinToneLikelihood(vec3 color) {
// Simple skin tone detection - check if in common skin tone range
// Based on normalized r/g ratio in RGB space
float total = color.r + color.g + color.b;
if (total < 0.001) return 0.0;
vec3 normalized = color / total;
// Detect skin tones based on red-green ratio and absolute red value
bool redEnough = normalized.r > 0.35;
bool redGreenRatio = normalized.r / normalized.g > 1.1 && normalized.r / normalized.g < 2.0;
bool notTooBlue = normalized.b < 0.4;
return (redEnough && redGreenRatio && notTooBlue) ? 1.0 - pow(normalized.b * 1.5, 2.0) : 0.0;
}
vec3 applyVibrance(vec3 color, float vibrance) {
float vibAmount = vibrance / 100.0; // Map to -1..1
// Calculate better saturation
float luma = dot(color, luminanceWeight);
vec3 chroma = max(color - luma, 0.0);
float sat = length(chroma) / (luma + 0.001);
// Get skin tone protection factor
float skinFactor = skinToneLikelihood(color);
// Calculate adjustment strength based on current saturation
// Less effect on already highly saturated colors
float satWeight = 1.0 - smoothstep(0.2, 0.8, sat);
// Apply less vibrance to skin tones
float adjustmentFactor = satWeight * (1.0 - skinFactor * 0.7);
// Create non-linear response curve for natural-looking adjustment
float strength = vibAmount > 0.0
? vibAmount * (1.0 - pow(sat, 2.0)) // Positive vibrance
: vibAmount; // Negative vibrance (desaturation)
// Fine-tune the saturation component-wise to preserve color relationships
vec3 satColor = color;
if (abs(vibAmount) > 0.001) {
// Get distance from gray for each channel
vec3 dist = color - luma;
// Adjust distance based on vibrance
dist *= (1.0 + strength * adjustmentFactor);
// Rebuild color from luma + adjusted chroma
satColor = luma + dist;
// Preserve color ratios for extreme adjustments
if (vibAmount > 0.5) {
float maxComponent = max(satColor.r, max(satColor.g, satColor.b));
if (maxComponent > 1.0) {
float scale = min(1.0 / maxComponent, 2.0); // Limit scaling
satColor = luma + (satColor - luma) * scale;
}
}
}
return satColor;
}
void main() {
vec4 color = texture(InputTexture, TexCoord);
color.rgb = applyVibrance(color.rgb, vibranceValue);
FragColor = vec4(max(color.rgb, vec3(0.0)), color.a);
}