From d2dcb35ec3488d727450b1cd7b902ac70990d342 Mon Sep 17 00:00:00 2001 From: Aevyrie Roessler Date: Sun, 20 Nov 2022 17:19:16 -0800 Subject: [PATCH 1/2] Fix missing sRGB conversion and improve accuracy --- .../src/tonemapping/tonemapping.wgsl | 10 +++++----- .../src/tonemapping/tonemapping_shared.wgsl | 17 ++++++++++++++++- crates/bevy_pbr/src/render/pbr.wgsl | 8 +++++++- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/crates/bevy_core_pipeline/src/tonemapping/tonemapping.wgsl b/crates/bevy_core_pipeline/src/tonemapping/tonemapping.wgsl index a4bc5d4be4364..8f3e7af1a8070 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/tonemapping.wgsl +++ b/crates/bevy_core_pipeline/src/tonemapping/tonemapping.wgsl @@ -10,15 +10,15 @@ var hdr_sampler: sampler; fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4 { let hdr_color = textureSample(hdr_texture, hdr_sampler, in.uv); - var output_rgb = reinhard_luminance(hdr_color.rgb); + var out = reinhard_luminance(hdr_color.rgb); #ifdef DEBAND_DITHER - output_rgb = pow(output_rgb.rgb, vec3(1.0 / 2.2)); - output_rgb = output_rgb + screen_space_dither(in.position.xy); + out = vec3(to_srgb(out.r), to_srgb(out.g), to_srgb(out.b)); + out = out + screen_space_dither(in.position.xy); // This conversion back to linear space is required because our output texture format is // SRGB; the GPU will assume our output is linear and will apply an SRGB conversion. - output_rgb = pow(output_rgb.rgb, vec3(2.2)); + out = vec3(to_linear(out.r), to_linear(out.g), to_linear(out.b)); #endif - return vec4(output_rgb, hdr_color.a); + return vec4(out, hdr_color.a); } diff --git a/crates/bevy_core_pipeline/src/tonemapping/tonemapping_shared.wgsl b/crates/bevy_core_pipeline/src/tonemapping/tonemapping_shared.wgsl index deafac0750d84..3ced1cf4efeb6 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/tonemapping_shared.wgsl +++ b/crates/bevy_core_pipeline/src/tonemapping/tonemapping_shared.wgsl @@ -34,4 +34,19 @@ fn screen_space_dither(frag_coord: vec2) -> vec3 { var dither = vec3(dot(vec2(171.0, 231.0), frag_coord)).xxx; dither = fract(dither.rgb / vec3(103.0, 71.0, 97.0)); return (dither - 0.5) / 255.0; -} \ No newline at end of file +} + +fn to_srgb(in: f32) -> f32 { + if in <= 0.0031308 { + return in * 12.92; + } else { + return pow(in, 1.0/2.4) * 1.055 - 0.055; + } +} +fn to_linear(in: f32) -> f32 { + if in <= 0.04045 { + return in / 12.92; + } else { + return pow((in + 0.055) / 1.055, 2.4); + } +} diff --git a/crates/bevy_pbr/src/render/pbr.wgsl b/crates/bevy_pbr/src/render/pbr.wgsl index 6f5d94edfbaf3..9daed91816023 100644 --- a/crates/bevy_pbr/src/render/pbr.wgsl +++ b/crates/bevy_pbr/src/render/pbr.wgsl @@ -99,7 +99,13 @@ fn fragment(in: FragmentInput) -> @location(0) vec4 { output_color = tone_mapping(output_color); #endif #ifdef DEBAND_DITHER - output_color = dither(output_color, in.frag_coord.xy); + var out = output_color.rgb; + out = vec3(to_srgb(out.r), to_srgb(out.g), to_srgb(out.b)); + out = out + screen_space_dither(in.frag_coord.xy); + // This conversion back to linear space is required because our output texture format is + // SRGB; the GPU will assume our output is linear and will apply an SRGB conversion. + out = vec3(to_linear(out.r), to_linear(out.g), to_linear(out.b)); + output_color = vec4(out, output_color.a); #endif return output_color; } From ce0ee55b95b977752c2b382a07f306944e3b7323 Mon Sep 17 00:00:00 2001 From: Aevyrie Roessler Date: Sun, 20 Nov 2022 17:37:52 -0800 Subject: [PATCH 2/2] use simplified sRGB conversion --- .../src/tonemapping/tonemapping.wgsl | 10 +++++----- .../src/tonemapping/tonemapping_shared.wgsl | 15 --------------- crates/bevy_pbr/src/render/pbr.wgsl | 10 +++++----- 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/crates/bevy_core_pipeline/src/tonemapping/tonemapping.wgsl b/crates/bevy_core_pipeline/src/tonemapping/tonemapping.wgsl index 8f3e7af1a8070..a4bc5d4be4364 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/tonemapping.wgsl +++ b/crates/bevy_core_pipeline/src/tonemapping/tonemapping.wgsl @@ -10,15 +10,15 @@ var hdr_sampler: sampler; fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4 { let hdr_color = textureSample(hdr_texture, hdr_sampler, in.uv); - var out = reinhard_luminance(hdr_color.rgb); + var output_rgb = reinhard_luminance(hdr_color.rgb); #ifdef DEBAND_DITHER - out = vec3(to_srgb(out.r), to_srgb(out.g), to_srgb(out.b)); - out = out + screen_space_dither(in.position.xy); + output_rgb = pow(output_rgb.rgb, vec3(1.0 / 2.2)); + output_rgb = output_rgb + screen_space_dither(in.position.xy); // This conversion back to linear space is required because our output texture format is // SRGB; the GPU will assume our output is linear and will apply an SRGB conversion. - out = vec3(to_linear(out.r), to_linear(out.g), to_linear(out.b)); + output_rgb = pow(output_rgb.rgb, vec3(2.2)); #endif - return vec4(out, hdr_color.a); + return vec4(output_rgb, hdr_color.a); } diff --git a/crates/bevy_core_pipeline/src/tonemapping/tonemapping_shared.wgsl b/crates/bevy_core_pipeline/src/tonemapping/tonemapping_shared.wgsl index 3ced1cf4efeb6..f538af1b2d812 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/tonemapping_shared.wgsl +++ b/crates/bevy_core_pipeline/src/tonemapping/tonemapping_shared.wgsl @@ -35,18 +35,3 @@ fn screen_space_dither(frag_coord: vec2) -> vec3 { dither = fract(dither.rgb / vec3(103.0, 71.0, 97.0)); return (dither - 0.5) / 255.0; } - -fn to_srgb(in: f32) -> f32 { - if in <= 0.0031308 { - return in * 12.92; - } else { - return pow(in, 1.0/2.4) * 1.055 - 0.055; - } -} -fn to_linear(in: f32) -> f32 { - if in <= 0.04045 { - return in / 12.92; - } else { - return pow((in + 0.055) / 1.055, 2.4); - } -} diff --git a/crates/bevy_pbr/src/render/pbr.wgsl b/crates/bevy_pbr/src/render/pbr.wgsl index 9daed91816023..cfe825190d2a5 100644 --- a/crates/bevy_pbr/src/render/pbr.wgsl +++ b/crates/bevy_pbr/src/render/pbr.wgsl @@ -99,13 +99,13 @@ fn fragment(in: FragmentInput) -> @location(0) vec4 { output_color = tone_mapping(output_color); #endif #ifdef DEBAND_DITHER - var out = output_color.rgb; - out = vec3(to_srgb(out.r), to_srgb(out.g), to_srgb(out.b)); - out = out + screen_space_dither(in.frag_coord.xy); + var output_rgb = output_color.rgb; + output_rgb = pow(output_rgb, vec3(1.0 / 2.2)); + output_rgb = output_rgb + screen_space_dither(in.frag_coord.xy); // This conversion back to linear space is required because our output texture format is // SRGB; the GPU will assume our output is linear and will apply an SRGB conversion. - out = vec3(to_linear(out.r), to_linear(out.g), to_linear(out.b)); - output_color = vec4(out, output_color.a); + output_rgb = pow(output_rgb, vec3(2.2)); + output_color = vec4(output_rgb, output_color.a); #endif return output_color; }