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

Add option to enable HDR rendering in 2D

This is needed to allow 2D to fully make use of 3D effects (e.g. glow), and can be used to substantially improve quality of 2D rendering at the cost of performance

Additionally, the 2D rendering pipeline is done in linear space (we skip linear_to_srgb conversion in 3D tonemapping) so the entire Viewport can be kept linear.
This is necessary for proper HDR screen support in the future.
This commit is contained in:
clayjohn
2023-08-03 14:10:01 +02:00
parent 237bd0a615
commit 57eb762bae
40 changed files with 309 additions and 105 deletions

View File

@@ -45,7 +45,7 @@ layout(push_constant, std140) uniform Pos {
float upscale;
float aspect_ratio;
uint layer;
uint pad1;
bool convert_to_srgb;
}
data;
@@ -59,6 +59,13 @@ layout(binding = 0) uniform sampler2DArray src_rt;
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)));
}
void main() {
#ifdef APPLY_LENS_DISTORTION
vec2 coords = uv * 2.0 - 1.0;
@@ -94,4 +101,8 @@ void main() {
#else
color = texture(src_rt, uv);
#endif
if (data.convert_to_srgb) {
color.rgb = linear_to_srgb(color.rgb); // Regular linear -> SRGB conversion.
}
}

View File

@@ -36,6 +36,12 @@ layout(set = 1, binding = 0, std140) uniform MaterialUniforms{
#GLOBALS
#ifdef USE_ATTRIBUTES
vec3 srgb_to_linear(vec3 color) {
return mix(pow((color.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), color.rgb * (1.0 / 12.92), lessThan(color.rgb, vec3(0.04045)));
}
#endif
void main() {
vec4 instance_custom = vec4(0.0);
#ifdef USE_PRIMITIVE
@@ -65,7 +71,11 @@ void main() {
#elif defined(USE_ATTRIBUTES)
vec2 vertex = vertex_attrib;
vec4 color = color_attrib * draw_data.modulation;
vec4 color = color_attrib;
if (bool(draw_data.flags & FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR)) {
color.rgb = srgb_to_linear(color.rgb);
}
color *= draw_data.modulation;
vec2 uv = uv_attrib;
uvec4 bones = bone_attrib;
@@ -563,9 +573,6 @@ void main() {
}
vec4 base_color = color;
if (bool(draw_data.flags & FLAGS_USING_LIGHT_MASK)) {
color = vec4(0.0); //invisible by default due to using light mask
}
#ifdef MODE_LIGHT_ONLY
float light_only_alpha = 0.0;

View File

@@ -12,7 +12,7 @@
#define FLAGS_CLIP_RECT_UV (1 << 9)
#define FLAGS_TRANSPOSE_RECT (1 << 10)
#define FLAGS_USING_LIGHT_MASK (1 << 11)
#define FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR (1 << 11)
#define FLAGS_NINEPACH_DRAW_CENTER (1 << 12)
#define FLAGS_USING_PARTICLES (1 << 13)

View File

@@ -57,7 +57,7 @@ layout(r32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffe
#elif defined(DST_IMAGE_8BIT)
layout(rgba8, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer;
#else
layout(rgba32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer;
layout(rgba16f, set = 3, binding = 0) uniform restrict writeonly image2D dest_buffer;
#endif
#ifdef MODE_GAUSSIAN_BLUR

View File

@@ -57,14 +57,21 @@ layout(set = 3, binding = 0) uniform sampler2D source_color_correction;
layout(set = 3, binding = 0) uniform sampler3D source_color_correction;
#endif
#define FLAG_USE_BCS (1 << 0)
#define FLAG_USE_GLOW (1 << 1)
#define FLAG_USE_AUTO_EXPOSURE (1 << 2)
#define FLAG_USE_COLOR_CORRECTION (1 << 3)
#define FLAG_USE_FXAA (1 << 4)
#define FLAG_USE_DEBANDING (1 << 5)
#define FLAG_CONVERT_TO_SRGB (1 << 6)
layout(push_constant, std430) uniform Params {
vec3 bcs;
bool use_bcs;
uint flags;
bool use_glow;
bool use_auto_exposure;
bool use_color_correction;
vec2 pixel_size;
uint tonemapper;
uint pad;
uvec2 glow_texture_size;
float glow_intensity;
@@ -77,10 +84,6 @@ layout(push_constant, std430) uniform Params {
float white;
float auto_exposure_scale;
float luminance_multiplier;
vec2 pixel_size;
bool use_fxaa;
bool use_debanding;
}
params;
@@ -318,10 +321,12 @@ vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blendi
if (params.glow_mode == GLOW_MODE_ADD) {
return color + glow;
} else if (params.glow_mode == GLOW_MODE_SCREEN) {
//need color clamping
// Needs color clamping.
glow.rgb = clamp(glow.rgb, vec3(0.0f), vec3(1.0f));
return max((color + glow) - (color * glow), vec3(0.0));
} else if (params.glow_mode == GLOW_MODE_SOFTLIGHT) {
//need color clamping
// Needs color clamping.
glow.rgb = clamp(glow.rgb, vec3(0.0f), vec3(1.0f));
glow = glow * vec3(0.5f) + vec3(0.5f);
color.r = (glow.r <= 0.5f) ? (color.r - (1.0f - 2.0f * glow.r) * color.r * (1.0f - color.r)) : (((glow.r > 0.5f) && (color.r <= 0.25f)) ? (color.r + (2.0f * glow.r - 1.0f) * (4.0f * color.r * (4.0f * color.r + 1.0f) * (color.r - 1.0f) + 7.0f * color.r)) : (color.r + (2.0f * glow.r - 1.0f) * (sqrt(color.r) - color.r)));
@@ -439,7 +444,7 @@ void main() {
float exposure = params.exposure;
#ifndef SUBPASS
if (params.use_auto_exposure) {
if (bool(params.flags & FLAG_USE_AUTO_EXPOSURE)) {
exposure *= 1.0 / (texelFetch(source_auto_exposure, ivec2(0, 0), 0).r * params.luminance_multiplier / params.auto_exposure_scale);
}
#endif
@@ -448,12 +453,12 @@ void main() {
// Early Tonemap & SRGB Conversion
#ifndef SUBPASS
if (params.use_fxaa) {
if (bool(params.flags & FLAG_USE_FXAA)) {
// FXAA must be performed before glow to preserve the "bleed" effect of glow.
color.rgb = do_fxaa(color.rgb, exposure, uv_interp);
}
if (params.use_glow && params.glow_mode == GLOW_MODE_MIX) {
if (bool(params.flags & FLAG_USE_GLOW) && params.glow_mode == GLOW_MODE_MIX) {
vec3 glow = gather_glow(source_glow, uv_interp) * params.luminance_multiplier;
if (params.glow_map_strength > 0.001) {
glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength);
@@ -464,11 +469,12 @@ void main() {
color.rgb = apply_tonemapping(color.rgb, params.white);
color.rgb = linear_to_srgb(color.rgb); // regular linear -> SRGB conversion
if (bool(params.flags & FLAG_CONVERT_TO_SRGB)) {
color.rgb = linear_to_srgb(color.rgb); // Regular linear -> SRGB conversion.
}
#ifndef SUBPASS
// Glow
if (params.use_glow && params.glow_mode != GLOW_MODE_MIX) {
if (bool(params.flags & FLAG_USE_GLOW) && params.glow_mode != GLOW_MODE_MIX) {
vec3 glow = gather_glow(source_glow, uv_interp) * params.glow_intensity * params.luminance_multiplier;
if (params.glow_map_strength > 0.001) {
glow = mix(glow, texture(glow_map, uv_interp).rgb * glow, params.glow_map_strength);
@@ -476,7 +482,9 @@ void main() {
// high dynamic range -> SRGB
glow = apply_tonemapping(glow, params.white);
glow = linear_to_srgb(glow);
if (bool(params.flags & FLAG_CONVERT_TO_SRGB)) {
glow = linear_to_srgb(glow);
}
color.rgb = apply_glow(color.rgb, glow);
}
@@ -484,15 +492,15 @@ void main() {
// Additional effects
if (params.use_bcs) {
if (bool(params.flags & FLAG_USE_BCS)) {
color.rgb = apply_bcs(color.rgb, params.bcs);
}
if (params.use_color_correction) {
if (bool(params.flags & FLAG_USE_COLOR_CORRECTION)) {
color.rgb = apply_color_correction(color.rgb);
}
if (params.use_debanding) {
if (bool(params.flags & FLAG_USE_DEBANDING)) {
// Debanding should be done at the end of tonemapping, but before writing to the LDR buffer.
// Otherwise, we're adding noise to an already-quantized image.
color.rgb += screen_space_dither(gl_FragCoord.xy);