From 9d97caaef934bcc6c7b3a0328a36ec934ab4aea5 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Wed, 17 Mar 2021 00:12:58 +0100 Subject: [PATCH] Add support for contrast-adaptive sharpening in 3D This is an older, easier to implement variant of CAS as a pure fragment shader. It doesn't support upscaling, but the upscaling part of CAS has been superseded by FSR 1.0 anyway. The sharpening intensity can be adjusted on a per-Viewport basis. For the root viewport, it can be adjusted in the Project Settings. --- doc/classes/ProjectSettings.xml | 7 ++- doc/classes/RenderingServer.xml | 8 +++ doc/classes/Viewport.xml | 5 +- drivers/gles3/rasterizer_scene_gles3.cpp | 2 +- drivers/gles3/rasterizer_scene_gles3.h | 2 +- editor/plugins/node_3d_editor_plugin.cpp | 2 + scene/main/scene_tree.cpp | 3 + scene/main/viewport.cpp | 20 +++++++ scene/main/viewport.h | 4 ++ .../rendering/dummy/rasterizer_scene_dummy.h | 2 +- .../renderer_rd/effects/tone_mapper.cpp | 2 + .../renderer_rd/effects/tone_mapper.h | 4 ++ .../renderer_rd/renderer_scene_render_rd.cpp | 6 +- .../renderer_rd/renderer_scene_render_rd.h | 3 +- .../renderer_rd/shaders/effects/tonemap.glsl | 57 +++++++++++++++++++ servers/rendering/renderer_scene.h | 2 +- servers/rendering/renderer_scene_cull.h | 2 +- servers/rendering/renderer_scene_render.h | 2 +- servers/rendering/renderer_viewport.cpp | 13 ++++- servers/rendering/renderer_viewport.h | 4 ++ servers/rendering/rendering_server_default.h | 1 + servers/rendering_server.cpp | 4 ++ servers/rendering_server.h | 2 + 23 files changed, 145 insertions(+), 12 deletions(-) diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index ad95572bf183..4da823c0f86b 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -1591,10 +1591,13 @@ Sets the number of MSAA samples to use (as a power of two). MSAA is used to reduce aliasing around the edges of polygons. A higher MSAA value results in smoother edges but can be significantly slower on some hardware. See also bilinear scaling 3d [member rendering/scaling_3d/mode] for supersampling, which provides higher quality but is much more expensive. - Sets the screen-space antialiasing mode for the default screen [Viewport]. Screen-space antialiasing works by selectively blurring edges in a post-process shader. It differs from MSAA which takes multiple coverage samples while rendering objects. Screen-space AA methods are typically faster than MSAA and will smooth out specular aliasing, but tend to make scenes appear blurry. - Another way to combat specular aliasing is to enable [member rendering/anti_aliasing/screen_space_roughness_limiter/enabled]. + Sets the screen-space antialiasing mode for the default screen [Viewport]. Screen-space antialiasing works by selectively blurring edges in a post-process shader. It differs from MSAA which takes multiple coverage samples while rendering objects. Screen-space AA methods are typically faster than MSAA and will smooth out specular aliasing, but tend to make scenes appear blurry. Some of the lost sharpness can be recovered by enabling contrast-adaptive sharpening (see [member rendering/anti_aliasing/quality/sharpen_intensity]). + + + If set to a value greater than [code]0.0[/code], contrast-adaptive sharpening will be applied to the 3D viewport. This has a small GPU performance cost and can be used to recover some of the sharpness lost due to screen-space antialiasing. Values around [code]0.5[/code] generally give the best results. See also [member rendering/anti_aliasing/quality/screen_space_aa]. + If [code]true[/code], uses a fast post-processing filter to make banding significantly less visible. In some cases, debanding may introduce a slightly noticeable dithering pattern. It's recommended to enable debanding only when actually needed since the dithering pattern will make lossless-compressed screenshots larger. Enables Temporal Anti-Aliasing for the default screen [Viewport]. TAA works by jittering the camera and accumulating the images of the last rendered frames, motion vector rendering is used to account for camera and object motion. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index d92121a950b6..d175f491ad88 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -3287,6 +3287,14 @@ Sets the size of the shadow atlas's images (used for omni and spot lights). The value will be rounded up to the nearest power of 2. + + + + + + Sets the sharpening [code]intensity[/code] for the [code]viewport[/code]. If set to a value greater than [code]0.0[/code], contrast-adaptive sharpening will be applied to the 3D viewport. This has a small GPU performance cost and can be used to recover some of the sharpness lost due to screen-space antialiasing. Values around [code]0.5[/code] generally give the best results. + + diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index 4727bc389e02..63580007f337 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -242,7 +242,7 @@ To control this property on the root viewport, set the [member ProjectSettings.rendering/scaling_3d/scale] project setting. - Sets the screen-space antialiasing method used. Screen-space antialiasing works by selectively blurring edges in a post-process shader. It differs from MSAA which takes multiple coverage samples while rendering objects. Screen-space AA methods are typically faster than MSAA and will smooth out specular aliasing, but tend to make scenes appear blurry. + Sets the screen-space antialiasing method used. Screen-space antialiasing works by selectively blurring edges in a post-process shader. It differs from MSAA which takes multiple coverage samples while rendering objects. Screen-space AA methods are typically faster than MSAA and will smooth out specular aliasing, but tend to make scenes appear blurry. Some of the lost sharpness can be recovered by enabling contrast-adaptive sharpening (see [member sharpen_intensity]). @@ -266,6 +266,9 @@ The shadow atlas' resolution (used for omni and spot lights). The value will be rounded up to the nearest power of 2. [b]Note:[/b] If this is set to 0, shadows won't be visible. + + If set to a value greater than [code]0.0[/code], contrast-adaptive sharpening will be applied to the 3D viewport. This has a small GPU performance cost and can be used to recover some of the sharpness lost due to screen-space antialiasing. Values around [code]0.5[/code] generally give the best results. See also [member screen_space_aa]. + diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 94ae8ecc8a9d..11aa6d3f5ceb 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -2507,7 +2507,7 @@ RID RasterizerSceneGLES3::render_buffers_create() { return render_buffers_owner.make_rid(rb); } -void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) { +void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, float p_sharpen_intensity, uint32_t p_view_count) { GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 308ef36fa19c..f4222a2e9428 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -923,7 +923,7 @@ class RasterizerSceneGLES3 : public RendererSceneRender { } RID render_buffers_create() override; - void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override; + void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, float p_sharpen_intensity, uint32_t p_view_count) override; void gi_set_use_half_resolution(bool p_enable) override; void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override; diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 9f4842a5a191..cff81cb9331d 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -2406,6 +2406,8 @@ void Node3DEditorViewport::_project_settings_changed() { const bool use_debanding = GLOBAL_GET("rendering/anti_aliasing/quality/use_debanding"); viewport->set_use_debanding(use_debanding); + const float sharpen_intensity = GLOBAL_GET("rendering/anti_aliasing/quality/sharpen_intensity"); + viewport->set_sharpen_intensity(sharpen_intensity); const bool use_occlusion_culling = GLOBAL_GET("rendering/occlusion_culling/use_occlusion_culling"); viewport->set_use_occlusion_culling(use_occlusion_culling); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index f8abda35d26a..a3d4cedff1ae 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1387,6 +1387,9 @@ SceneTree::SceneTree() { const bool use_debanding = GLOBAL_DEF("rendering/anti_aliasing/quality/use_debanding", false); root->set_use_debanding(use_debanding); + const float sharpen_intensity = GLOBAL_GET("rendering/anti_aliasing/quality/sharpen_intensity"); + root->set_sharpen_intensity(sharpen_intensity); + const bool use_occlusion_culling = GLOBAL_DEF("rendering/occlusion_culling/use_occlusion_culling", false); root->set_use_occlusion_culling(use_occlusion_culling); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 1ad011f8675b..df861bce8e1d 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -2900,6 +2900,18 @@ bool Viewport::is_using_debanding() const { return use_debanding; } +void Viewport::set_sharpen_intensity(float p_intensity) { + if (sharpen_intensity == p_intensity) { + return; + } + sharpen_intensity = p_intensity; + RS::get_singleton()->viewport_set_sharpen_intensity(viewport, p_intensity); +} + +float Viewport::get_sharpen_intensity() const { + return sharpen_intensity; +} + void Viewport::set_mesh_lod_threshold(float p_pixels) { mesh_lod_threshold = p_pixels; RS::get_singleton()->viewport_set_mesh_lod_threshold(viewport, mesh_lod_threshold); @@ -3629,6 +3641,9 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_debanding", "enable"), &Viewport::set_use_debanding); ClassDB::bind_method(D_METHOD("is_using_debanding"), &Viewport::is_using_debanding); + ClassDB::bind_method(D_METHOD("set_sharpen_intensity", "intensity"), &Viewport::set_sharpen_intensity); + ClassDB::bind_method(D_METHOD("get_sharpen_intensity"), &Viewport::get_sharpen_intensity); + ClassDB::bind_method(D_METHOD("set_use_occlusion_culling", "enable"), &Viewport::set_use_occlusion_culling); ClassDB::bind_method(D_METHOD("is_using_occlusion_culling"), &Viewport::is_using_occlusion_culling); @@ -3751,11 +3766,13 @@ void Viewport::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handle_input_locally"), "set_handle_input_locally", "is_handling_input_locally"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_transforms_to_pixel"), "set_snap_2d_transforms_to_pixel", "is_snap_2d_transforms_to_pixel_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_vertices_to_pixel"), "set_snap_2d_vertices_to_pixel", "is_snap_2d_vertices_to_pixel_enabled"); + ADD_GROUP("Rendering", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")), "set_msaa", "get_msaa"); ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"), "set_screen_space_aa", "get_screen_space_aa"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_taa"), "set_use_taa", "is_using_taa"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sharpen_intensity"), "set_sharpen_intensity", "get_sharpen_intensity"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_occlusion_culling"), "set_use_occlusion_culling", "is_using_occlusion_culling"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mesh_lod_threshold", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_mesh_lod_threshold", "get_mesh_lod_threshold"); ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw"); @@ -3769,6 +3786,7 @@ void Viewport::_bind_methods() { ADD_GROUP("Canvas Items", "canvas_item_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Linear Mipmap,Nearest Mipmap"), "set_default_canvas_item_texture_filter", "get_default_canvas_item_texture_filter"); ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirror"), "set_default_canvas_item_texture_repeat", "get_default_canvas_item_texture_repeat"); + ADD_GROUP("Audio Listener", "audio_listener_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_listener_enable_2d"), "set_as_audio_listener_2d", "is_audio_listener_2d"); #ifndef _3D_DISABLED @@ -3776,6 +3794,7 @@ void Viewport::_bind_methods() { #endif ADD_GROUP("Physics", "physics_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "physics_object_picking"), "set_physics_object_picking", "get_physics_object_picking"); + ADD_GROUP("GUI", "gui_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_disable_input"), "set_disable_input", "is_input_disabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_snap_controls_to_pixels"), "set_snap_controls_to_pixels", "is_snap_controls_to_pixels_enabled"); @@ -3783,6 +3802,7 @@ void Viewport::_bind_methods() { ADD_GROUP("SDF", "sdf_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sdf_oversize", PROPERTY_HINT_ENUM, "100%,120%,150%,200%"), "set_sdf_oversize", "get_sdf_oversize"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sdf_scale", PROPERTY_HINT_ENUM, "100%,50%,25%"), "set_sdf_scale", "get_sdf_scale"); + ADD_GROUP("Shadow Atlas", "shadow_atlas_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_atlas_size"), "set_shadow_atlas_size", "get_shadow_atlas_size"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_atlas_16_bits"), "set_shadow_atlas_16_bits", "get_shadow_atlas_16_bits"); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index a22a2acf499e..32603bb43617 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -299,6 +299,7 @@ class Viewport : public Node { float fsr_sharpness = 0.2f; float fsr_mipmap_bias = 0.0f; bool use_debanding = false; + float sharpen_intensity = 0.0; float mesh_lod_threshold = 1.0; bool use_occlusion_culling = false; @@ -535,6 +536,9 @@ class Viewport : public Node { void set_use_debanding(bool p_use_debanding); bool is_using_debanding() const; + void set_sharpen_intensity(float p_intensity); + float get_sharpen_intensity() const; + void set_mesh_lod_threshold(float p_pixels); float get_mesh_lod_threshold() const; diff --git a/servers/rendering/dummy/rasterizer_scene_dummy.h b/servers/rendering/dummy/rasterizer_scene_dummy.h index e6d2b93f9971..b75bd98512cb 100644 --- a/servers/rendering/dummy/rasterizer_scene_dummy.h +++ b/servers/rendering/dummy/rasterizer_scene_dummy.h @@ -192,7 +192,7 @@ class RasterizerSceneDummy : public RendererSceneRender { void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) override {} RID render_buffers_create() override { return RID(); } - void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override {} + void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, float p_sharpen_intensity, uint32_t p_view_count) override {} void gi_set_use_half_resolution(bool p_enable) override {} void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override {} diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.cpp b/servers/rendering/renderer_rd/effects/tone_mapper.cpp index 38a4a37b8af7..89a4093883bf 100644 --- a/servers/rendering/renderer_rd/effects/tone_mapper.cpp +++ b/servers/rendering/renderer_rd/effects/tone_mapper.cpp @@ -124,6 +124,7 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton tonemap.push_constant.use_fxaa = p_settings.use_fxaa; tonemap.push_constant.use_debanding = p_settings.use_debanding; + tonemap.push_constant.sharpen_intensity = p_settings.sharpen_intensity; tonemap.push_constant.pixel_size[0] = 1.0 / p_settings.texture_size.x; tonemap.push_constant.pixel_size[1] = 1.0 / p_settings.texture_size.y; @@ -208,6 +209,7 @@ void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_col tonemap.push_constant.use_color_correction = p_settings.use_color_correction; tonemap.push_constant.use_debanding = p_settings.use_debanding; + tonemap.push_constant.sharpen_intensity = p_settings.sharpen_intensity; tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier; RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.h b/servers/rendering/renderer_rd/effects/tone_mapper.h index a90849dbeba2..556c9158d045 100644 --- a/servers/rendering/renderer_rd/effects/tone_mapper.h +++ b/servers/rendering/renderer_rd/effects/tone_mapper.h @@ -83,6 +83,9 @@ class ToneMapper { float pixel_size[2]; // 8 - 104 uint32_t use_fxaa; // 4 - 108 uint32_t use_debanding; // 4 - 112 + + uint32_t pad[3]; // 12 - 128 + float sharpen_intensity; // 4 - 116 }; /* tonemap actually writes to a framebuffer, which is @@ -139,6 +142,7 @@ class ToneMapper { bool use_fxaa = false; bool use_debanding = false; + float sharpen_intensity = 0.0; Vector2i texture_size; uint32_t view_count = 1; }; diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index ef959bc3c6be..edbe61a541fe 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -2610,6 +2610,8 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende } tonemap.use_debanding = rb->use_debanding; + tonemap.sharpen_intensity = rb->sharpen_intensity; + tonemap.texture_size = Vector2i(rb->internal_width, rb->internal_height); if (env) { @@ -2717,6 +2719,7 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr } tonemap.use_debanding = rb->use_debanding; + tonemap.sharpen_intensity = rb->sharpen_intensity; tonemap.texture_size = Vector2i(rb->width, rb->height); tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier(); @@ -3031,7 +3034,7 @@ bool RendererSceneRenderRD::_render_buffers_can_be_storage() { return true; } -void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) { +void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, float p_sharpen_intensity, uint32_t p_view_count) { RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); @@ -3061,6 +3064,7 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p rb->screen_space_aa = p_screen_space_aa; rb->use_taa = p_use_taa; rb->use_debanding = p_use_debanding; + rb->sharpen_intensity = p_sharpen_intensity; rb->view_count = p_view_count; if (is_clustered_enabled()) { diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 1b1df6469e3c..f92806e1b632 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -481,6 +481,7 @@ class RendererSceneRenderRD : public RendererSceneRender { RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED; bool use_taa = false; bool use_debanding = false; + float sharpen_intensity = 0.0; uint32_t view_count = 1; RID render_target; @@ -1397,7 +1398,7 @@ class RendererSceneRenderRD : public RendererSceneRender { virtual RD::DataFormat _render_buffers_get_color_format(); virtual bool _render_buffers_can_be_storage(); virtual RID render_buffers_create() override; - virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override; + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, float p_sharpen_intensity, uint32_t p_view_count) override; virtual void gi_set_use_half_resolution(bool p_enable) override; RID render_buffers_get_depth_texture(RID p_render_buffers); diff --git a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl index 62a7b0e7d7df..62b0602be6a4 100644 --- a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl @@ -81,6 +81,9 @@ layout(push_constant, std430) uniform Params { vec2 pixel_size; bool use_fxaa; bool use_debanding; + + uvec3 pad; + float sharpen_intensity; } params; @@ -409,6 +412,54 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { return rgbB; } } + +// Adapted from https://github.com/DadSchoorse/vkBasalt/blob/b929505ba71dea21d6c32a5a59f2d241592b30c4/src/shader/cas.frag.glsl +// (MIT license). +vec3 do_cas(vec3 color, float exposure, vec2 uv_interp, float sharpen_intensity) { + // Fetch a 3x3 neighborhood around the pixel 'e', + // a b c + // d(e)f + // g h i + vec3 a = textureLodOffset(source_color, uv_interp, 0.0, ivec2(-1, -1)).rgb * exposure; + vec3 b = textureLodOffset(source_color, uv_interp, 0.0, ivec2(0, -1)).rgb * exposure; + vec3 c = textureLodOffset(source_color, uv_interp, 0.0, ivec2(1, -1)).rgb * exposure; + vec3 d = textureLodOffset(source_color, uv_interp, 0.0, ivec2(-1, 0)).rgb * exposure; + vec3 e = color.rgb; + vec3 f = textureLodOffset(source_color, uv_interp, 0.0, ivec2(1, 0)).rgb * exposure; + vec3 g = textureLodOffset(source_color, uv_interp, 0.0, ivec2(-1, 1)).rgb * exposure; + vec3 h = textureLodOffset(source_color, uv_interp, 0.0, ivec2(0, 1)).rgb * exposure; + vec3 i = textureLodOffset(source_color, uv_interp, 0.0, ivec2(1, 1)).rgb * exposure; + + // Soft min and max. + // a b c b + // d e f * 0.5 + d e f * 0.5 + // g h i h + // These are 2.0x bigger (factored out the extra multiply). + vec3 min_rgb = min(min(min(d, e), min(f, b)), h); + vec3 min_rgb2 = min(min(min(min_rgb, a), min(g, c)), i); + min_rgb += min_rgb2; + + vec3 max_rgb = max(max(max(d, e), max(f, b)), h); + vec3 max_rgb2 = max(max(max(max_rgb, a), max(g, c)), i); + max_rgb += max_rgb2; + + // Smooth minimum distance to signal limit divided by smooth max. + vec3 rcp_max_rgb = vec3(1.0) / max_rgb; + vec3 amp_rgb = clamp((min(min_rgb, 2.0 - max_rgb) * rcp_max_rgb), 0.0, 1.0); + + // Shaping amount of sharpening. + amp_rgb = inversesqrt(amp_rgb); + float peak = 8.0 - 3.0 * sharpen_intensity; + vec3 w_rgb = -vec3(1) / (amp_rgb * peak); + vec3 rcp_weight_rgb = vec3(1.0) / (1.0 + 4.0 * w_rgb); + + // 0 w 0 + // Filter shape: w 1 w + // 0 w 0 + vec3 window = b + d + f + h; + + return max(vec3(0.0), (window * w_rgb + e) * rcp_weight_rgb); +} #endif // !SUBPASS // From https://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf @@ -460,6 +511,12 @@ void main() { } color.rgb = mix(color.rgb, glow, params.glow_intensity); } + + if (params.sharpen_intensity >= 0.001) { + // CAS gives best results when applied after tonemapping, but `source_color` isn't tonemapped. + // As a workaround, apply CAS before tonemapping so that the image still has a correct appearance when tonemapped. + color.rgb = do_cas(color.rgb, exposure, uv_interp, params.sharpen_intensity); + } #endif if (params.use_debanding) { diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h index b773ed61f42a..14663665ae3f 100644 --- a/servers/rendering/renderer_scene.h +++ b/servers/rendering/renderer_scene.h @@ -194,7 +194,7 @@ class RendererScene { virtual RID render_buffers_create() = 0; - virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) = 0; + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, float p_sharpen_intensity, uint32_t p_view_count) = 0; virtual void gi_set_use_half_resolution(bool p_enable) = 0; diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index d1d348487138..5a64f7316039 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -1158,7 +1158,7 @@ class RendererSceneCull : public RendererScene { /* Render Buffers */ PASS0R(RID, render_buffers_create) - PASS13(render_buffers_configure, RID, RID, int, int, int, int, float, float, RS::ViewportMSAA, RS::ViewportScreenSpaceAA, bool, bool, uint32_t) + PASS14(render_buffers_configure, RID, RID, int, int, int, int, float, float, RS::ViewportMSAA, RS::ViewportScreenSpaceAA, bool, bool, float, uint32_t) PASS1(gi_set_use_half_resolution, bool) /* Shadow Atlas */ diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index 280277c6d8d9..d2ccd420440c 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -259,7 +259,7 @@ class RendererSceneRender { virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0; virtual RID render_buffers_create() = 0; - virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) = 0; + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, float p_sharpen_intensity, uint32_t p_view_count) = 0; virtual void gi_set_use_half_resolution(bool p_enable) = 0; virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) = 0; diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 2e0c4e0f7955..2f75f449e5e9 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -138,7 +138,7 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) { p_viewport->internal_size = Size2(render_width, render_height); - RSG::scene->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, render_width, render_height, width, height, p_viewport->fsr_sharpness, p_viewport->fsr_mipmap_bias, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->get_view_count()); + RSG::scene->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, render_width, render_height, width, height, p_viewport->fsr_sharpness, p_viewport->fsr_mipmap_bias, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->sharpen_intensity, p_viewport->get_view_count()); } } } @@ -1077,6 +1077,17 @@ void RendererViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_deb _configure_3d_render_buffers(viewport); } +void RendererViewport::viewport_set_sharpen_intensity(RID p_viewport, float p_sharpen_intensity) { + Viewport *viewport = viewport_owner.get_or_null(p_viewport); + ERR_FAIL_COND(!viewport); + + if (viewport->sharpen_intensity == p_sharpen_intensity) { + return; + } + viewport->sharpen_intensity = p_sharpen_intensity; + _configure_3d_render_buffers(viewport); +} + void RendererViewport::viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling) { Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h index 18385d161331..855c29f0156f 100644 --- a/servers/rendering/renderer_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -69,6 +69,7 @@ class RendererViewport { RS::ViewportScreenSpaceAA screen_space_aa; bool use_taa; bool use_debanding; + float sharpen_intensity; RendererSceneRender::CameraData prev_camera_data; uint64_t prev_camera_data_frame = 0; @@ -159,6 +160,7 @@ class RendererViewport { msaa = RS::VIEWPORT_MSAA_DISABLED; screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED; use_debanding = false; + sharpen_intensity = 0.0; use_occlusion_culling = false; occlusion_buffer_dirty = true; @@ -262,6 +264,8 @@ class RendererViewport { void viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode); void viewport_set_use_taa(RID p_viewport, bool p_use_taa); void viewport_set_use_debanding(RID p_viewport, bool p_use_debanding); + void viewport_set_sharpen_intensity(RID p_viewport, float p_intensity); + void viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling); void viewport_set_occlusion_rays_per_thread(int p_rays_per_thread); void viewport_set_occlusion_culling_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality); diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 6008f2b00eaf..4e6aa6682e13 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -618,6 +618,7 @@ class RenderingServerDefault : public RenderingServer { FUNC2(viewport_set_screen_space_aa, RID, ViewportScreenSpaceAA) FUNC2(viewport_set_use_taa, RID, bool) FUNC2(viewport_set_use_debanding, RID, bool) + FUNC2(viewport_set_sharpen_intensity, RID, float) FUNC2(viewport_set_use_occlusion_culling, RID, bool) FUNC1(viewport_set_occlusion_rays_per_thread, int) FUNC1(viewport_set_occlusion_culling_build_quality, ViewportOcclusionCullingBuildQuality) diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 26ab8b659e98..b4fee3f0b2b2 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2213,6 +2213,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_set_screen_space_aa", "viewport", "mode"), &RenderingServer::viewport_set_screen_space_aa); ClassDB::bind_method(D_METHOD("viewport_set_use_taa", "viewport", "enable"), &RenderingServer::viewport_set_use_taa); ClassDB::bind_method(D_METHOD("viewport_set_use_debanding", "viewport", "enable"), &RenderingServer::viewport_set_use_debanding); + ClassDB::bind_method(D_METHOD("viewport_set_sharpen_intensity", "viewport", "intensity"), &RenderingServer::viewport_set_sharpen_intensity); ClassDB::bind_method(D_METHOD("viewport_set_use_occlusion_culling", "viewport", "enable"), &RenderingServer::viewport_set_use_occlusion_culling); ClassDB::bind_method(D_METHOD("viewport_set_occlusion_rays_per_thread", "rays_per_thread"), &RenderingServer::viewport_set_occlusion_rays_per_thread); ClassDB::bind_method(D_METHOD("viewport_set_occlusion_culling_build_quality", "quality"), &RenderingServer::viewport_set_occlusion_culling_build_quality); @@ -2934,6 +2935,9 @@ void RenderingServer::init() { ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/screen_space_roughness_limiter/amount", PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/amount", PROPERTY_HINT_RANGE, "0.01,4.0,0.01")); ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/screen_space_roughness_limiter/limit", PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/limit", PROPERTY_HINT_RANGE, "0.01,1.0,0.01")); + GLOBAL_DEF("rendering/anti_aliasing/quality/sharpen_intensity", 0.0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/sharpen_intensity", PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/quality/sharpen_intensity", PROPERTY_HINT_RANGE, "0,1")); + GLOBAL_DEF_RST("rendering/scaling_3d/mode", 0); GLOBAL_DEF_RST("rendering/scaling_3d/scale", 1.0); GLOBAL_DEF_RST("rendering/scaling_3d/fsr_sharpness", 0.2f); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 39484e532ae7..e48343b94446 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -881,6 +881,8 @@ class RenderingServer : public Object { virtual void viewport_set_use_debanding(RID p_viewport, bool p_use_debanding) = 0; + virtual void viewport_set_sharpen_intensity(RID p_viewport, float p_intensity) = 0; + virtual void viewport_set_mesh_lod_threshold(RID p_viewport, float p_pixels) = 0; virtual void viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling) = 0;