-
-
Notifications
You must be signed in to change notification settings - Fork 22.8k
Always perform color correction and debanding on nonlinear sRGB values. #107782
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Always perform color correction and debanding on nonlinear sRGB values. #107782
Conversation
@beicause You mentioned an idea about how to better address the color correction bug. Thanks for sharing this! Please feel free to share more details here or open a new PR that builds off this one with me as a co-contributor if you'd like. |
4179398
to
5cd619b
Compare
Optimizes out one srgb->linear conversion by sampling sRGB texture: diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 2a037d241e..4d30f625ef 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -665,6 +665,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
tonemap.use_color_correction = false;
tonemap.use_1d_color_correction = false;
tonemap.color_correction_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
+ tonemap.convert_to_srgb = !texture_storage->render_target_is_using_hdr(render_target);
if (can_use_effects && p_render_data->environment.is_valid()) {
tonemap.use_bcs = environment_get_adjustments_enabled(p_render_data->environment);
@@ -674,15 +675,13 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
if (environment_get_adjustments_enabled(p_render_data->environment) && environment_get_color_correction(p_render_data->environment).is_valid()) {
tonemap.use_color_correction = true;
tonemap.use_1d_color_correction = environment_get_use_1d_color_correction(p_render_data->environment);
- tonemap.color_correction_texture = texture_storage->texture_get_rd_texture(environment_get_color_correction(p_render_data->environment));
+ tonemap.color_correction_texture = texture_storage->texture_get_rd_texture(environment_get_color_correction(p_render_data->environment), !tonemap.convert_to_srgb);
}
}
tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier();
tonemap.view_count = rb->get_view_count();
- tonemap.convert_to_srgb = !texture_storage->render_target_is_using_hdr(render_target);
-
RID dest_fb;
if (spatial_upscaler != nullptr || use_smaa) {
// If we use a spatial upscaler to upscale or SMAA to antialias we need to write our result into an intermediate buffer.
diff --git a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl
index c4ae4cb8b0..84c4a0fca8 100644
--- a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl
@@ -911,9 +911,6 @@ void main() {
color.rgb = linear_to_srgb(color.rgb);
}
color.rgb = apply_color_correction(color.rgb);
- if (!convert_to_srgb) {
- color.rgb = srgb_to_linear(color.rgb);
- }
}
if (bool(params.flags & FLAG_USE_DEBANDING) && convert_to_srgb) {
|
5cd619b
to
6bd11e0
Compare
This seems to work well -- very clever! Thanks @beicause! |
9985913
to
160c349
Compare
I've finished work on this, so it's now ready for review. (Sorry about the mistaken "ready for review" I made earlier!) |
Debanding is a per-viewport setting. I don't know why it should change to a RendererCompositor setting here. I think debanding has nothing to do with color space. It can be performed in linear space as long as it's done before writing the results to a lower-precision buffer. See also #87350. |
Hmm, I hadn’t thought about how debanding is exposed to scripting as a property of I’m not sure exactly what to do about this, so let me know if you have thoughts on how to handle this scenario.
I will take a look into #87350 and post on that PR if it exhibits the same issues as seen in #107730. The specific dither function that is used for debanding is designed to be applied to nonlinear encoded float values of the final encoding directly before quantization to an 8 bit buffer. Details about this and the consequences of applying it to an encoding that is different than the one used immediately before quantization (i.e. linear encoding) is described in #107730. The specific dithering function that Godot uses cannot be used on linear values. If you want to use a debanding technique that works on linear encoded values, you need to use a different function such as the one presented by Timothy Lottes in his GDC talk (See part 3: transfer functions and quantization). |
#87350 uses the same debanding algorithm with the viewport debanding. But sky shader uses a different one:
I'm not sure if these algorithms works in linear space (dividing by 255.0 seems a bit magical), but it's worth taking a look. |
There's actually a PDF linked from the Godot docs that talks about what floating point encoding your dithering should be applied in with these sorts of dithering effects: https://loopit.dk/banding_in_games.pdf (see page 35 onward where it states "convert first, dither afterwards… dither in whatever space the color will be quantized in."). I think it's easier to just read the dithering code to understand that it needs to be applied to nonlinear encoded values, but if anyone wants some "literature" on the subject, there it is. I will eventually look into the sky shader's debanding, but I noticed that the dithering is scaled by a I also now realize there is quite a bit in the docs that needs updating with this PR as well. I'll continue to update it to address all these cases. |
160c349
to
b193647
Compare
0825eed
to
f1d6012
Compare
I've fixed this so that debanding is still a property of the viewport and also always applied as the last step before 8-bit quantization. Just need to figure out how to add this to XR now... Edit: Hmm. It seems it would be better to store |
Fixes godotengine#107730 Co-authored-by: LuoZhihao <[email protected]>
f1d6012
to
a159151
Compare
OK, I've moved |
Fixes #107730
Screenshots at 4x magnification (view in a dark environment/surround to see the detail):

Notes to reviewers:
My test project
color-correction-debanding-fixed.zip