1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +00:00

Merge pull request #110671 from allenwp/environment-glow-consistent

Blend glow before tonemapping and change default to screen.
This commit is contained in:
Clay John
2025-10-14 21:29:43 -07:00
committed by GitHub
11 changed files with 150 additions and 80 deletions

View File

@@ -114,10 +114,10 @@ public:
GLOW_MODE_MIX
};
GlowMode glow_mode = GLOW_MODE_ADD;
float glow_intensity = 1.0;
GlowMode glow_mode = GLOW_MODE_SCREEN;
float glow_intensity = 0.3;
float glow_map_strength = 0.0f;
float glow_levels[7] = { 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0 };
float glow_levels[7] = { 1.0, 0.8, 0.4, 0.1, 0.0, 0.0, 0.0 };
Vector2i glow_texture_size;
bool glow_use_bicubic_upscale = false;
RID glow_texture;

View File

@@ -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);

View File

@@ -208,7 +208,13 @@ void RendererEnvironmentStorage::environment_set_tonemap(RID p_env, RS::Environm
ERR_FAIL_NULL(env);
env->exposure = p_exposure;
env->tone_mapper = p_tone_mapper;
env->white = p_white;
if (p_tone_mapper == RS::ENV_TONE_MAPPER_LINEAR) {
env->white = 1.0; // With HDR output, this should be the output max value instead.
} else if (p_tone_mapper == RS::ENV_TONE_MAPPER_AGX) {
env->white = 16.29;
} else {
env->white = MAX(1.0, p_white); // Glow with screen blend mode does not work when white < 1.0.
}
}
RS::EnvironmentToneMapper RendererEnvironmentStorage::environment_get_tone_mapper(RID p_env) const {
@@ -471,7 +477,7 @@ Vector<float> RendererEnvironmentStorage::environment_get_glow_levels(RID p_env)
float RendererEnvironmentStorage::environment_get_glow_intensity(RID p_env) const {
Environment *env = environment_owner.get_or_null(p_env);
ERR_FAIL_NULL_V(env, 0.8);
ERR_FAIL_NULL_V(env, 0.3);
return env->glow_intensity;
}
@@ -495,7 +501,7 @@ float RendererEnvironmentStorage::environment_get_glow_mix(RID p_env) const {
RS::EnvironmentGlowBlendMode RendererEnvironmentStorage::environment_get_glow_blend_mode(RID p_env) const {
Environment *env = environment_owner.get_or_null(p_env);
ERR_FAIL_NULL_V(env, RS::ENV_GLOW_BLEND_MODE_SOFTLIGHT);
ERR_FAIL_NULL_V(env, RS::ENV_GLOW_BLEND_MODE_SCREEN);
return env->glow_blend_mode;
}

View File

@@ -98,11 +98,11 @@ private:
// Glow
bool glow_enabled = false;
Vector<float> glow_levels;
float glow_intensity = 0.8;
float glow_intensity = 0.3;
float glow_strength = 1.0;
float glow_bloom = 0.0;
float glow_mix = 0.01;
RS::EnvironmentGlowBlendMode glow_blend_mode = RS::ENV_GLOW_BLEND_MODE_SOFTLIGHT;
RS::EnvironmentGlowBlendMode glow_blend_mode = RS::ENV_GLOW_BLEND_MODE_SCREEN;
float glow_hdr_bleed_threshold = 1.0;
float glow_hdr_luminance_cap = 12.0;
float glow_hdr_bleed_scale = 2.0;