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

Improve Environment color adjustments; specifically brightness and HDR 2D contrast.

This commit changes adjustments to behave as follows for all rendering configurations:

- Apply brightness to linear-encoded values, preventing contrast, saturation, and hue from being affected.
- Apply contrast to perceptually uniform (nonlinear sRGB-encoded) values, matching existing behavior when HDR 2D is disabled and producing optimal visual quality.
- Apply saturation with even color channel weights. This causes brightness of certain colors to change, but matches existing behavior when HDR 2D is disabled.

Adjustments are applied after glow and tonemapping to match existing behavior.
This commit is contained in:
Allen Pestaluky
2025-10-23 11:02:57 -04:00
parent f50d7fa1e8
commit 0c7f013c55
5 changed files with 69 additions and 45 deletions

View File

@@ -329,13 +329,15 @@ vec3 tonemap_agx(vec3 color) {
}
vec3 linear_to_srgb(vec3 color) {
// Clamping is not strictly necessary for floating point nonlinear sRGB encoding,
// but many cases that call this function need the result clamped.
color = clamp(color, vec3(0.0), vec3(1.0));
const vec3 a = vec3(0.055f);
return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f)));
}
vec3 srgb_to_linear(vec3 color) {
const vec3 a = vec3(0.055f);
return mix(pow((color.rgb + a) * (1.0f / (vec3(1.0f) + a)), vec3(2.4f)), color.rgb * (1.0f / 12.92f), lessThan(color.rgb, vec3(0.04045f)));
}
#define TONEMAPPER_LINEAR 0
#define TONEMAPPER_REINHARD 1
#define TONEMAPPER_FILMIC 2
@@ -446,13 +448,6 @@ vec3 apply_glow(vec3 color, vec3 glow, float white) {
}
}
vec3 apply_bcs(vec3 color, vec3 bcs) {
color = mix(vec3(0.0f), color, bcs.x);
color = mix(vec3(0.5f), color, bcs.y);
color = mix(vec3(dot(vec3(1.0f), color) * 0.33333f), color, bcs.z);
return color;
}
#ifdef USE_1D_LUT
vec3 apply_color_correction(vec3 color) {
color.r = texture(source_color_correction, vec2(color.r, 0.0f)).r;
@@ -928,23 +923,39 @@ void main() {
}
#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.
}
if (bool(params.flags & FLAG_USE_BCS)) {
color.rgb = apply_bcs(color.rgb, params.bcs);
}
// Apply brightness:
// Apply to relative luminance. This ensures that the hue and saturation of
// colors is not affected by the adjustment, but requires the multiplication
// to be performed on linear-encoded values.
color.rgb = color.rgb * params.bcs.x;
if (bool(params.flags & FLAG_USE_COLOR_CORRECTION)) {
// apply_color_correction requires nonlinear sRGB encoding
if (!convert_to_srgb) {
color.rgb = linear_to_srgb(color.rgb);
color.rgb = linear_to_srgb(color.rgb);
// Apply contrast:
// By applying contrast to RGB values that are perceptually uniform (nonlinear),
// the darkest values are not hard-clipped as badly, which produces a
// higher quality contrast adjustment and maintains compatibility with
// existing projects.
color.rgb = mix(vec3(0.5), color.rgb, params.bcs.y);
// Apply saturation:
// By applying saturation adjustment to nonlinear sRGB-encoded values with
// even weights the preceived brightness of blues are affected, but this
// maintains compatibility with existing projects.
color.rgb = mix(vec3(dot(vec3(1.0), color.rgb) * (1.0 / 3.0)), color.rgb, params.bcs.z);
if (bool(params.flags & FLAG_USE_COLOR_CORRECTION)) {
color.rgb = clamp(color.rgb, vec3(0.0), vec3(1.0));
color.rgb = apply_color_correction(color.rgb);
// When using color correction and FLAG_CONVERT_TO_SRGB is false, there
// is no need to convert back to linear because the color correction
// texture sampling does this for us.
} else if (!bool(params.flags & FLAG_CONVERT_TO_SRGB)) {
color.rgb = srgb_to_linear(color.rgb);
}
color.rgb = apply_color_correction(color.rgb);
// When convert_to_srgb is false, there is no need to convert back to
// linear because the color correction texture sampling does this for us.
} else if (bool(params.flags & FLAG_CONVERT_TO_SRGB)) {
color.rgb = linear_to_srgb(color.rgb);
}
// Debanding should be done at the end of tonemapping, but before writing to the LDR buffer.

View File

@@ -793,7 +793,9 @@ void RendererEnvironmentStorage::environment_set_adjustment(RID p_env, bool p_en
ERR_FAIL_NULL(env);
env->adjustments_enabled = p_enable;
env->adjustments_brightness = p_brightness;
// Scale brightness via the nonlinear sRGB transfer function to provide a
// somewhat perceptually uniform brightness adjustment.
env->adjustments_brightness = p_brightness < 0.04045f ? p_brightness * (1.0f / 12.92f) : Math::pow(float((p_brightness + 0.055f) * (1.0f / (1.055f))), 2.4f);
env->adjustments_contrast = p_contrast;
env->adjustments_saturation = p_saturation;
env->use_1d_color_correction = p_use_1d_color_correction;