1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-10 13:00:37 +00:00

Always perform color correction and debanding on nonlinear sRGB values.

Fixes #107730

Co-authored-by: LuoZhihao <luo_zhihao@outlook.com>
This commit is contained in:
Allen Pestaluky
2025-07-07 16:38:17 -04:00
parent 4d1f26e1fd
commit a1591512f8
15 changed files with 82 additions and 20 deletions

View File

@@ -10,7 +10,6 @@ layout(push_constant, std140) uniform Pos {
float rotation_sin;
float rotation_cos;
vec2 pad;
vec2 eye_center;
float k1;
@@ -20,6 +19,8 @@ layout(push_constant, std140) uniform Pos {
float aspect_ratio;
uint layer;
bool convert_to_srgb;
bool use_debanding;
float pad;
}
data;
@@ -50,7 +51,6 @@ layout(push_constant, std140) uniform Pos {
float rotation_sin;
float rotation_cos;
vec2 pad;
vec2 eye_center;
float k1;
@@ -60,6 +60,8 @@ layout(push_constant, std140) uniform Pos {
float aspect_ratio;
uint layer;
bool convert_to_srgb;
bool use_debanding;
float pad;
}
data;
@@ -74,12 +76,27 @@ layout(binding = 0) uniform sampler2D src_rt;
#endif
vec3 linear_to_srgb(vec3 color) {
// If going to srgb, clamp from 0 to 1.
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)));
}
// From https://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf
// and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom)
// NOTE: `frag_coord` is in pixels (i.e. not normalized UV).
// This dithering must be applied after encoding changes (linear/nonlinear) have been applied
// as the final step before quantization from floating point to integer values.
vec3 screen_space_dither(vec2 frag_coord) {
// Iestyn's RGB dither (7 asm instructions) from Portal 2 X360, slightly modified for VR.
// Removed the time component to avoid passing time into this shader.
vec3 dither = vec3(dot(vec2(171.0, 231.0), frag_coord));
dither.rgb = fract(dither.rgb / vec3(103.0, 71.0, 97.0));
// Subtract 0.5 to avoid slightly brightening the whole viewport.
// Use a dither strength of 100% rather than the 37.5% suggested by the original source.
// Divide by 255 to align to 8-bit quantization.
return (dither.rgb - 0.5) / 255.0;
}
void main() {
#ifdef APPLY_LENS_DISTORTION
vec2 coords = uv * 2.0 - 1.0;
@@ -118,5 +135,10 @@ void main() {
if (data.convert_to_srgb) {
color.rgb = linear_to_srgb(color.rgb); // Regular linear -> SRGB conversion.
// When convert_to_srgb is true, debanding was skipped in tonemap.glsl.
if (data.use_debanding) {
color.rgb += screen_space_dither(gl_FragCoord.xy);
}
color.rgb = clamp(color.rgb, vec3(0.0), vec3(1.0));
}
}