|
|
|
|
@ -393,6 +393,8 @@ vec3 gather_glow(sampler2D tex, vec2 uv) { // sample all selected glow levels
|
|
|
|
|
glow += GLOW_TEXTURE_SAMPLE(tex, uv, 6).rgb * params.glow_levels[6];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glow = glow * params.luminance_multiplier;
|
|
|
|
|
|
|
|
|
|
return glow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -402,21 +404,42 @@ vec3 gather_glow(sampler2D tex, vec2 uv) { // sample all selected glow levels
|
|
|
|
|
#define GLOW_MODE_REPLACE 3
|
|
|
|
|
#define GLOW_MODE_MIX 4
|
|
|
|
|
|
|
|
|
|
vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blending mode
|
|
|
|
|
// Applies glow using the selected blending mode. Does not handle the mix blend mode.
|
|
|
|
|
vec3 apply_glow(vec3 color, vec3 glow, float white) {
|
|
|
|
|
if (params.glow_mode == GLOW_MODE_ADD) {
|
|
|
|
|
return color + glow;
|
|
|
|
|
} else if (params.glow_mode == GLOW_MODE_SCREEN) {
|
|
|
|
|
// Needs color clamping.
|
|
|
|
|
glow.rgb = clamp(glow.rgb, vec3(0.0f), vec3(1.0f));
|
|
|
|
|
return max((color + glow) - (color * glow), vec3(0.0));
|
|
|
|
|
} else if (params.glow_mode == GLOW_MODE_SOFTLIGHT) {
|
|
|
|
|
// Needs color clamping.
|
|
|
|
|
glow.rgb = clamp(glow.rgb, vec3(0.0f), vec3(1.0f));
|
|
|
|
|
glow = glow * vec3(0.5f) + vec3(0.5f);
|
|
|
|
|
// Glow cannot be above 1.0 after normalizing and should be non-negative
|
|
|
|
|
// to produce expected results. It is possible that glow can be negative
|
|
|
|
|
// if negative lights were used in the scene.
|
|
|
|
|
// We clamp to white because glow will be normalized to this range.
|
|
|
|
|
// Note: white cannot be smaller than the maximum output value.
|
|
|
|
|
glow.rgb = clamp(glow.rgb, 0.0, white);
|
|
|
|
|
|
|
|
|
|
// Normalize to white range.
|
|
|
|
|
//glow.rgb /= white;
|
|
|
|
|
//color.rgb /= white;
|
|
|
|
|
//color.rgb = (color.rgb + glow.rgb) - (color.rgb * glow.rgb);
|
|
|
|
|
// Expand back to original range.
|
|
|
|
|
//color.rgb *= white;
|
|
|
|
|
|
|
|
|
|
// The following is a mathematically simplified version of the above.
|
|
|
|
|
color.rgb = color.rgb + glow.rgb - (color.rgb * glow.rgb / white);
|
|
|
|
|
|
|
|
|
|
return color;
|
|
|
|
|
} else if (params.glow_mode == GLOW_MODE_SOFTLIGHT) {
|
|
|
|
|
// Glow cannot be above 1.0 should be non-negative to produce
|
|
|
|
|
// expected results. It is possible that glow can be negative
|
|
|
|
|
// if negative lights were used in the scene.
|
|
|
|
|
// Note: This approach causes a discontinuity with scene values
|
|
|
|
|
// at 1.0, but because this glow should have its strongest influence
|
|
|
|
|
// anchored at 0.25 there is no way around this.
|
|
|
|
|
glow.rgb = clamp(glow.rgb, 0.0, 1.0);
|
|
|
|
|
|
|
|
|
|
color.r = color.r > 1.0 ? color.r : color.r + glow.r * ((color.r <= 0.25f ? ((16.0f * color.r - 12.0f) * color.r + 4.0f) * color.r : sqrt(color.r)) - color.r);
|
|
|
|
|
color.g = color.g > 1.0 ? color.g : color.g + glow.g * ((color.g <= 0.25f ? ((16.0f * color.g - 12.0f) * color.g + 4.0f) * color.g : sqrt(color.g)) - color.g);
|
|
|
|
|
color.b = color.b > 1.0 ? color.b : color.b + glow.b * ((color.b <= 0.25f ? ((16.0f * color.b - 12.0f) * color.b + 4.0f) * color.b : sqrt(color.b)) - color.b);
|
|
|
|
|
|
|
|
|
|
color.r = (glow.r <= 0.5f) ? (color.r - (1.0f - 2.0f * glow.r) * color.r * (1.0f - color.r)) : (((glow.r > 0.5f) && (color.r <= 0.25f)) ? (color.r + (2.0f * glow.r - 1.0f) * (4.0f * color.r * (4.0f * color.r + 1.0f) * (color.r - 1.0f) + 7.0f * color.r)) : (color.r + (2.0f * glow.r - 1.0f) * (sqrt(color.r) - color.r)));
|
|
|
|
|
color.g = (glow.g <= 0.5f) ? (color.g - (1.0f - 2.0f * glow.g) * color.g * (1.0f - color.g)) : (((glow.g > 0.5f) && (color.g <= 0.25f)) ? (color.g + (2.0f * glow.g - 1.0f) * (4.0f * color.g * (4.0f * color.g + 1.0f) * (color.g - 1.0f) + 7.0f * color.g)) : (color.g + (2.0f * glow.g - 1.0f) * (sqrt(color.g) - color.g)));
|
|
|
|
|
color.b = (glow.b <= 0.5f) ? (color.b - (1.0f - 2.0f * glow.b) * color.b * (1.0f - color.b)) : (((glow.b > 0.5f) && (color.b <= 0.25f)) ? (color.b + (2.0f * glow.b - 1.0f) * (4.0f * color.b * (4.0f * color.b + 1.0f) * (color.b - 1.0f) + 7.0f * color.b)) : (color.b + (2.0f * glow.b - 1.0f) * (sqrt(color.b) - color.b)));
|
|
|
|
|
return color;
|
|
|
|
|
} else { //replace
|
|
|
|
|
return glow;
|
|
|
|
|
@ -859,47 +882,56 @@ void main() {
|
|
|
|
|
|
|
|
|
|
color.rgb *= exposure;
|
|
|
|
|
|
|
|
|
|
// Early Tonemap & SRGB Conversion
|
|
|
|
|
// Single-pass FXAA and pre-tonemap glow.
|
|
|
|
|
|
|
|
|
|
#ifndef SUBPASS
|
|
|
|
|
if (bool(params.flags & FLAG_USE_FXAA)) {
|
|
|
|
|
// FXAA must be performed before glow to preserve the "bleed" effect of glow.
|
|
|
|
|
color.rgb = do_fxaa(color.rgb, exposure, uv_interp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bool(params.flags & FLAG_USE_GLOW) && params.glow_mode == GLOW_MODE_MIX) {
|
|
|
|
|
vec3 glow = gather_glow(source_glow, uv_interp) * params.luminance_multiplier;
|
|
|
|
|
if (params.glow_map_strength > 0.001) {
|
|
|
|
|
glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength);
|
|
|
|
|
if (bool(params.flags & FLAG_USE_GLOW) && params.glow_mode != GLOW_MODE_SOFTLIGHT) {
|
|
|
|
|
vec3 glow = gather_glow(source_glow, uv_interp);
|
|
|
|
|
if (params.glow_mode == GLOW_MODE_MIX) {
|
|
|
|
|
if (params.glow_map_strength > 0.001) {
|
|
|
|
|
glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength);
|
|
|
|
|
}
|
|
|
|
|
color.rgb = mix(color.rgb, glow, params.glow_intensity);
|
|
|
|
|
} else {
|
|
|
|
|
glow = glow * params.glow_intensity;
|
|
|
|
|
if (params.glow_map_strength > 0.001) {
|
|
|
|
|
glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength);
|
|
|
|
|
}
|
|
|
|
|
color.rgb = apply_glow(color.rgb, glow, params.white);
|
|
|
|
|
}
|
|
|
|
|
color.rgb = mix(color.rgb, glow, params.glow_intensity);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Tonemap to lower dynamic range.
|
|
|
|
|
|
|
|
|
|
color.rgb = apply_tonemapping(color.rgb, params.white);
|
|
|
|
|
|
|
|
|
|
// Additional effects.
|
|
|
|
|
|
|
|
|
|
#ifndef SUBPASS
|
|
|
|
|
if (bool(params.flags & FLAG_USE_GLOW) && params.glow_mode == GLOW_MODE_SOFTLIGHT) {
|
|
|
|
|
// Apply soft light after tonemapping to mitigate the issue of discontinuity
|
|
|
|
|
// at 1.0 and higher. This makes the issue only appear with HDR output that
|
|
|
|
|
// can exceed a 1.0 output value.
|
|
|
|
|
vec3 glow = gather_glow(source_glow, uv_interp);
|
|
|
|
|
glow = glow * params.glow_intensity;
|
|
|
|
|
if (params.glow_map_strength > 0.001) {
|
|
|
|
|
glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength);
|
|
|
|
|
}
|
|
|
|
|
glow = apply_tonemapping(glow, params.white);
|
|
|
|
|
color.rgb = apply_glow(color.rgb, glow, params.white);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
bool convert_to_srgb = bool(params.flags & FLAG_CONVERT_TO_SRGB);
|
|
|
|
|
if (convert_to_srgb) {
|
|
|
|
|
color.rgb = linear_to_srgb(color.rgb); // Regular linear -> SRGB conversion.
|
|
|
|
|
}
|
|
|
|
|
#ifndef SUBPASS
|
|
|
|
|
// Glow
|
|
|
|
|
if (bool(params.flags & FLAG_USE_GLOW) && params.glow_mode != GLOW_MODE_MIX) {
|
|
|
|
|
vec3 glow = gather_glow(source_glow, uv_interp) * params.glow_intensity * params.luminance_multiplier;
|
|
|
|
|
if (params.glow_map_strength > 0.001) {
|
|
|
|
|
glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// high dynamic range -> SRGB
|
|
|
|
|
glow = apply_tonemapping(glow, params.white);
|
|
|
|
|
if (convert_to_srgb) {
|
|
|
|
|
glow = linear_to_srgb(glow);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
color.rgb = apply_glow(color.rgb, glow);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Additional effects
|
|
|
|
|
|
|
|
|
|
if (bool(params.flags & FLAG_USE_BCS)) {
|
|
|
|
|
color.rgb = apply_bcs(color.rgb, params.bcs);
|
|
|
|
|
|