You've already forked godot
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:
@@ -36,19 +36,19 @@
|
||||
</methods>
|
||||
<members>
|
||||
<member name="adjustment_brightness" type="float" setter="set_adjustment_brightness" getter="get_adjustment_brightness" default="1.0">
|
||||
The global brightness value of the rendered scene. Effective only if [member adjustment_enabled] is [code]true[/code].
|
||||
Applies a simple brightness adjustment to the rendered image after tonemaping. To adjust scene brightness use [member tonemap_exposure] instead, which is applied before tonemapping and thus less prone to issues with bright colors. Effective only if [member adjustment_enabled] is [code]true[/code].
|
||||
</member>
|
||||
<member name="adjustment_color_correction" type="Texture" setter="set_adjustment_color_correction" getter="get_adjustment_color_correction">
|
||||
The [Texture2D] or [Texture3D] lookup table (LUT) to use for the built-in post-process color grading. Can use a [GradientTexture1D] for a 1-dimensional LUT, or a [Texture3D] for a more complex LUT. Effective only if [member adjustment_enabled] is [code]true[/code].
|
||||
</member>
|
||||
<member name="adjustment_contrast" type="float" setter="set_adjustment_contrast" getter="get_adjustment_contrast" default="1.0">
|
||||
The global contrast value of the rendered scene (default value is 1). Effective only if [member adjustment_enabled] is [code]true[/code].
|
||||
Increasing [member adjustment_contrast] will make dark values darker and bright values brighter. This simple adjustment is applied to the rendered image after tonemaping. When set to a value greater than [code]1.0[/code], [member adjustment_contrast] is prone to clipping colors that become too bright or too dark. Effective only if [member adjustment_enabled] is [code]true[/code].
|
||||
</member>
|
||||
<member name="adjustment_enabled" type="bool" setter="set_adjustment_enabled" getter="is_adjustment_enabled" default="false">
|
||||
If [code]true[/code], enables the [code]adjustment_*[/code] properties provided by this resource. If [code]false[/code], modifications to the [code]adjustment_*[/code] properties will have no effect on the rendered scene.
|
||||
</member>
|
||||
<member name="adjustment_saturation" type="float" setter="set_adjustment_saturation" getter="get_adjustment_saturation" default="1.0">
|
||||
The global color saturation value of the rendered scene (default value is 1). Effective only if [member adjustment_enabled] is [code]true[/code].
|
||||
Applies a simple saturation adjustment to the rendered image after tonemaping. When [member adjustment_saturation] is set to [code]0.0[/code], the rendered image will be fully converted to a grayscale image. Effective only if [member adjustment_enabled] is [code]true[/code].
|
||||
</member>
|
||||
<member name="ambient_light_color" type="Color" setter="set_ambient_light_color" getter="get_ambient_light_color" default="Color(0, 0, 0, 1)">
|
||||
The ambient light's [Color]. Only effective if [member ambient_light_sky_contribution] is lower than [code]1.0[/code] (exclusive).
|
||||
|
||||
@@ -86,16 +86,6 @@ vec3 apply_color_correction(vec3 color) {
|
||||
#endif // USE_1D_LUT
|
||||
#endif // USE_COLOR_CORRECTION
|
||||
|
||||
#ifdef USE_BCS
|
||||
vec3 apply_bcs(vec3 color) {
|
||||
color = mix(vec3(0.0), color, brightness);
|
||||
color = mix(vec3(0.5), color, contrast);
|
||||
color = mix(vec3(dot(vec3(1.0), color) * 0.33333), color, saturation);
|
||||
|
||||
return color;
|
||||
}
|
||||
#endif
|
||||
|
||||
in vec2 uv_interp;
|
||||
|
||||
layout(location = 0) out vec4 frag_color;
|
||||
@@ -140,12 +130,33 @@ void main() {
|
||||
#endif // USE_GLOW
|
||||
|
||||
color.rgb = srgb_to_linear(color.rgb);
|
||||
|
||||
color.rgb = apply_tonemapping(color.rgb, white);
|
||||
color.rgb = linear_to_srgb(color.rgb);
|
||||
|
||||
#ifdef USE_BCS
|
||||
color.rgb = apply_bcs(color.rgb);
|
||||
#endif
|
||||
// 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 * brightness;
|
||||
|
||||
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, contrast);
|
||||
|
||||
// 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, saturation);
|
||||
#else
|
||||
color.rgb = linear_to_srgb(color.rgb);
|
||||
#endif // USE_BCS
|
||||
|
||||
#ifdef USE_COLOR_CORRECTION
|
||||
color.rgb = apply_color_correction(color.rgb);
|
||||
|
||||
@@ -1246,7 +1246,7 @@ void Environment::_bind_methods() {
|
||||
|
||||
ADD_GROUP("Tonemap", "tonemap_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "tonemap_mode", PROPERTY_HINT_ENUM, "Linear,Reinhard,Filmic,ACES,AgX"), "set_tonemapper", "get_tonemapper");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tonemap_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_exposure", "get_tonemap_exposure");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tonemap_exposure", PROPERTY_HINT_RANGE, "0,4,0.01,or_greater"), "set_tonemap_exposure", "get_tonemap_exposure");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tonemap_white", PROPERTY_HINT_RANGE, "1,16,0.01,or_greater"), "set_tonemap_white", "get_tonemap_white");
|
||||
|
||||
// SSR
|
||||
@@ -1522,9 +1522,9 @@ void Environment::_bind_methods() {
|
||||
|
||||
ADD_GROUP("Adjustments", "adjustment_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "adjustment_enabled", PROPERTY_HINT_GROUP_ENABLE), "set_adjustment_enabled", "is_adjustment_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "adjustment_brightness", PROPERTY_HINT_RANGE, "0.01,8,0.01"), "set_adjustment_brightness", "get_adjustment_brightness");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "adjustment_contrast", PROPERTY_HINT_RANGE, "0.01,8,0.01"), "set_adjustment_contrast", "get_adjustment_contrast");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "adjustment_saturation", PROPERTY_HINT_RANGE, "0.01,8,0.01"), "set_adjustment_saturation", "get_adjustment_saturation");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "adjustment_brightness", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,or_greater"), "set_adjustment_brightness", "get_adjustment_brightness");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "adjustment_contrast", PROPERTY_HINT_RANGE, "0.75,1.25,0.005,or_less,or_greater"), "set_adjustment_contrast", "get_adjustment_contrast");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "adjustment_saturation", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,or_less,or_greater"), "set_adjustment_saturation", "get_adjustment_saturation");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "adjustment_color_correction", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D,Texture3D"), "set_adjustment_color_correction", "get_adjustment_color_correction");
|
||||
|
||||
// Constants
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user