#version 330 core out vec4 FragColor; in vec2 TexCoord; uniform sampler2D InputTexture; uniform float highlightsValue; // -100 to 100 uniform float shadowsValue; // -100 to 100 // More accurate perceptual luminance (Rec. 709) float luminance(vec3 color) { return dot(color, vec3(0.2126, 0.7152, 0.0722)); } // Smoothstep with better performance than quintic float smootherStep(float edge0, float edge1, float x) { float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); return t * t * (3.0 - 2.0 * t); } vec3 applyHighlightsShadows(vec3 color) { float lum = luminance(color); // Define threshold values similar to Lightroom float shadowThreshold = 0.3; float highlightThreshold = 0.7; // Calculate adjustment weights with smoother falloff float shadowWeight = 1.0 - smootherStep(0.0, shadowThreshold * 2.0, lum); float highlightWeight = smootherStep(highlightThreshold, 1.0, lum); // Calculate adaptive adjustment factors float shadowFactor = shadowsValue > 0.0 ? mix(1.0, 1.0 + (shadowsValue / 100.0), shadowWeight) : mix(1.0, 1.0 + (shadowsValue / 150.0), shadowWeight); float highlightFactor = highlightsValue > 0.0 ? mix(1.0, 1.0 - (highlightsValue / 150.0), highlightWeight) : mix(1.0, 1.0 - (highlightsValue / 100.0), highlightWeight); // Apply adjustments while preserving colors vec3 adjusted = color * shadowFactor * highlightFactor; // Preserve some saturation characteristics like Lightroom float newLum = luminance(adjusted); float saturationFactor = 1.0; // Boost saturation slightly when lifting shadows (like Lightroom) // if (shadowsValue > 0.0 && lum < shadowThreshold) { // saturationFactor = 1.0 + (shadowsValue / 300.0) * (1.0 - lum / shadowThreshold); // } // Reduce saturation slightly when recovering highlights (like Lightroom) if (highlightsValue > 0.0 && lum > highlightThreshold) { saturationFactor *= 1.0 - (highlightsValue / 400.0) * ((lum - highlightThreshold) / (1.0 - highlightThreshold)); } // Apply saturation adjustment while preserving luminance return mix(vec3(newLum), adjusted, saturationFactor); } void main() { vec4 color = texture(InputTexture, TexCoord); color.rgb = applyHighlightsShadows(color.rgb); FragColor = vec4(clamp(color.rgb, 0.0, 1.0), color.a); }