You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-11 13:10:58 +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:
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,7 +328,8 @@ vec3 tonemap_agx(vec3 color) {
|
||||
}
|
||||
|
||||
vec3 linear_to_srgb(vec3 color) {
|
||||
//if going to srgb, clamp from 0 to 1.
|
||||
// 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)));
|
||||
@@ -816,12 +817,17 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -866,7 +872,8 @@ void main() {
|
||||
|
||||
color.rgb = apply_tonemapping(color.rgb, params.white);
|
||||
|
||||
if (bool(params.flags & FLAG_CONVERT_TO_SRGB)) {
|
||||
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
|
||||
@@ -879,7 +886,7 @@ void main() {
|
||||
|
||||
// high dynamic range -> SRGB
|
||||
glow = apply_tonemapping(glow, params.white);
|
||||
if (bool(params.flags & FLAG_CONVERT_TO_SRGB)) {
|
||||
if (convert_to_srgb) {
|
||||
glow = linear_to_srgb(glow);
|
||||
}
|
||||
|
||||
@@ -894,7 +901,13 @@ void main() {
|
||||
}
|
||||
|
||||
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 = 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.
|
||||
}
|
||||
|
||||
if (bool(params.flags & FLAG_USE_DEBANDING)) {
|
||||
|
||||
Reference in New Issue
Block a user