79 lines
2.8 KiB
GLSL
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);
|
|
} |