From bd9d1bf070fc054c81477cc03a74e600cf4cf641 Mon Sep 17 00:00:00 2001 From: Allen Pestaluky Date: Mon, 7 Mar 2022 18:29:40 +0100 Subject: [PATCH] Add material debanding for use in Mobile rendering method. Co-authored-by: Hugo Locurcio --- doc/classes/ProjectSettings.xml | 4 ++-- doc/classes/RenderingServer.xml | 9 ++++++++ doc/classes/Viewport.xml | 6 ++--- drivers/gles3/rasterizer_scene_gles3.cpp | 4 ++++ drivers/gles3/rasterizer_scene_gles3.h | 1 + editor/editor_node.cpp | 1 + scene/main/scene_tree.cpp | 2 +- .../rendering/dummy/rasterizer_scene_dummy.h | 1 + .../forward_mobile/render_forward_mobile.cpp | 1 + .../scene_shader_forward_mobile.h | 8 ++++++- .../renderer_rd/renderer_scene_render_rd.cpp | 6 +++++ .../renderer_rd/renderer_scene_render_rd.h | 6 +++++ .../forward_mobile/scene_forward_mobile.glsl | 22 +++++++++++++++++++ .../scene_forward_mobile_inc.glsl | 18 +++++++++------ servers/rendering/renderer_scene_cull.h | 1 + servers/rendering/renderer_scene_render.h | 1 + servers/rendering/rendering_method.h | 1 + servers/rendering/rendering_server.cpp | 4 ++++ servers/rendering/rendering_server.h | 2 ++ servers/rendering/rendering_server_default.h | 1 + 20 files changed, 85 insertions(+), 14 deletions(-) diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 50e28967a32..8c6d2fb3eed 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -2770,9 +2770,9 @@ [b]Note:[/b] This property is only read when the project starts. There is currently no way to change this setting at run-time. - If [code]true[/code], uses a fast post-processing filter to make banding significantly less visible. If [member rendering/viewport/hdr_2d] is [code]false[/code], 2D rendering is [i]not[/i] affected by debanding unless the [member Environment.background_mode] is [constant Environment.BG_CANVAS]. If [member rendering/viewport/hdr_2d] is [code]true[/code], debanding will affect all 2D and 3D rendering, including canvas items. + If [code]true[/code], uses a fast dithering filter just before transforming floating point color values to integer color values to make banding significantly less visible. Debanding is applied at different steps of the rendering process depending on the rendering method and [member rendering/viewport/hdr_2d] setting. 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. - [b]Note:[/b] This property is only read when the project starts. To set debanding at runtime, set [member Viewport.use_debanding] on the root [Viewport] instead, or use [method RenderingServer.viewport_set_use_debanding]. + [b]Note:[/b] This property is only read when the project starts and configures [method RenderingServer.material_set_use_debanding] and [member Viewport.use_debanding] of the root [Viewport]. When [member rendering/viewport/hdr_2d] is disabled, you should additionally set the [member Viewport.use_debanding] of other viewports in your project. To set debanding at run-time, the property that should be set depends on the renderer: Forward+ only uses [member Viewport.use_debanding] and Mobile uses both [method RenderingServer.material_set_use_debanding] and [member Viewport.use_debanding]. Enables temporal antialiasing 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. Enabling TAA can make the image blurrier, which is partially counteracted by automatically using a negative mipmap LOD bias (see [member rendering/textures/default_filters/texture_mipmap_bias]). diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 058e8e61da9..60fa9fa159b 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -2360,6 +2360,15 @@ Sets a shader material's shader. + + + + + When using the Mobile renderer, [method material_set_use_debanding] can be used to enable or disable the debanding feature of 3D materials ([BaseMaterial3D] and [ShaderMaterial]). + [method material_set_use_debanding] has no effect when using the Compatibility or Forward+ renderer. In Forward+, [Viewport] debanding can be used instead. + See also [member ProjectSettings.rendering/anti_aliasing/quality/use_debanding] and [method RenderingServer.viewport_set_use_debanding]. + + diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index 3b58fc25a98..836f42dcc8d 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -457,9 +457,9 @@ [b]Note:[/b] Due to technical limitations, certain rendering features are disabled when a viewport has a transparent background. This currently applies to screen-space reflections, subsurface scattering, and depth of field. - If [code]true[/code], uses a fast post-processing filter to make banding significantly less visible. If [member use_hdr_2d] is [code]false[/code], 2D rendering is [i]not[/i] affected by debanding unless the [member Environment.background_mode] is [constant Environment.BG_CANVAS]. If [member use_hdr_2d] is [code]true[/code], debanding will only be applied if this is the root [Viewport] and will affect all 2D and 3D rendering, including canvas items. - 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. - See also [member ProjectSettings.rendering/anti_aliasing/quality/use_debanding] and [method RenderingServer.viewport_set_use_debanding]. + When using the Mobile or Forward+ renderers, set [member use_debanding] to enable or disable the debanding feature of this [Viewport]. If [member use_hdr_2d] is [code]false[/code], 2D rendering is [i]not[/i] affected by debanding unless the [member Environment.background_mode] is [constant Environment.BG_CANVAS]. If [member use_hdr_2d] is [code]true[/code], debanding will only be applied if this is the root [Viewport] and will affect all 2D and 3D rendering, including canvas items. + [member use_debanding] has no effect when using the Compatibility rendering method. The Mobile renderer can also use material debanding, which can be set with [method RenderingServer.material_set_use_debanding] or configured with [member ProjectSettings.rendering/anti_aliasing/quality/use_debanding]. + See also [member ProjectSettings.rendering/anti_aliasing/quality/use_debanding], [method RenderingServer.material_set_use_debanding], and [method RenderingServer.viewport_set_use_debanding]. If [code]true[/code], 2D rendering will use a high dynamic range (HDR) format framebuffer matching the bit depth of the 3D framebuffer. When using the Forward+ or Compatibility renderer, this will be an [code]RGBA16[/code] framebuffer. When using the Mobile renderer, it will be an [code]RGB10_A2[/code] framebuffer. diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index e2ae7df580d..2049408a932 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -4288,6 +4288,10 @@ void RasterizerSceneGLES3::lightmaps_set_bicubic_filter(bool p_enable) { lightmap_bicubic_upscale = p_enable; } +void RasterizerSceneGLES3::material_set_use_debanding(bool p_enable) { + // Material debanding not yet implemented. +} + RasterizerSceneGLES3::RasterizerSceneGLES3() { singleton = this; diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index ce6d1932d42..d51a3dcd38a 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -950,6 +950,7 @@ public: void decals_set_filter(RS::DecalFilter p_filter) override; void light_projectors_set_filter(RS::LightProjectorFilter p_filter) override; virtual void lightmaps_set_bicubic_filter(bool p_enable) override; + virtual void material_set_use_debanding(bool p_enable) override; RasterizerSceneGLES3(); ~RasterizerSceneGLES3(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 63c5b7c20b5..c4bce0dab39 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -527,6 +527,7 @@ void EditorNode::_update_from_settings() { RS::get_singleton()->decals_set_filter(RS::DecalFilter(int(GLOBAL_GET("rendering/textures/decals/filter")))); RS::get_singleton()->light_projectors_set_filter(RS::LightProjectorFilter(int(GLOBAL_GET("rendering/textures/light_projectors/filter")))); RS::get_singleton()->lightmaps_set_bicubic_filter(GLOBAL_GET("rendering/lightmapping/lightmap_gi/use_bicubic_filter")); + RS::get_singleton()->material_set_use_debanding(GLOBAL_GET("rendering/anti_aliasing/quality/use_debanding")); SceneTree *tree = get_tree(); tree->set_debug_collisions_color(GLOBAL_GET("debug/shapes/collision/shape_color")); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 5f4044cf6b6..07c47e8fc7b 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -2086,7 +2086,7 @@ SceneTree::SceneTree() { const bool use_taa = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/use_taa", false); root->set_use_taa(use_taa); - const bool use_debanding = GLOBAL_DEF("rendering/anti_aliasing/quality/use_debanding", false); + const bool use_debanding = GLOBAL_GET("rendering/anti_aliasing/quality/use_debanding"); root->set_use_debanding(use_debanding); const bool use_occlusion_culling = GLOBAL_DEF("rendering/occlusion_culling/use_occlusion_culling", false); diff --git a/servers/rendering/dummy/rasterizer_scene_dummy.h b/servers/rendering/dummy/rasterizer_scene_dummy.h index 4e86732d5e6..2769fff3a32 100644 --- a/servers/rendering/dummy/rasterizer_scene_dummy.h +++ b/servers/rendering/dummy/rasterizer_scene_dummy.h @@ -193,6 +193,7 @@ public: virtual void decals_set_filter(RS::DecalFilter p_filter) override {} virtual void light_projectors_set_filter(RS::LightProjectorFilter p_filter) override {} virtual void lightmaps_set_bicubic_filter(bool p_enable) override {} + virtual void material_set_use_debanding(bool p_enable) override {} RasterizerSceneDummy() {} ~RasterizerSceneDummy() {} diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index c8c1b365430..2b9aaafacbf 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -3329,6 +3329,7 @@ void RenderForwardMobile::_update_shader_quality_settings() { light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC; specialization.use_lightmap_bicubic_filter = lightmap_filter_bicubic_get(); + specialization.use_material_debanding = material_use_debanding_get(); specialization.luminance_multiplier = 2.0f; scene_shader.set_default_specialization(specialization); diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index 98ab09a1629..78863fc5595 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -89,21 +89,27 @@ public: uint32_t use_light_soft_shadows : 1; uint32_t use_directional_soft_shadows : 1; uint32_t decal_use_mipmaps : 1; + uint32_t projector_use_mipmaps : 1; uint32_t disable_fog : 1; uint32_t use_depth_fog : 1; uint32_t use_fog_aerial_perspective : 1; + uint32_t use_fog_sun_scatter : 1; uint32_t use_fog_height_density : 1; uint32_t use_lightmap_bicubic_filter : 1; + uint32_t use_material_debanding : 1; + uint32_t multimesh : 1; uint32_t multimesh_format_2d : 1; uint32_t multimesh_has_color : 1; uint32_t multimesh_has_custom_data : 1; + uint32_t scene_use_ambient_cubemap : 1; uint32_t scene_use_reflection_cubemap : 1; uint32_t scene_roughness_limiter_enabled : 1; - uint32_t padding_0 : 2; + uint32_t padding_0 : 1; + uint32_t soft_shadow_samples : 6; uint32_t penumbra_shadow_samples : 6; }; diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index d7766f4479e..3479da4424b 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -1248,6 +1248,11 @@ void RendererSceneRenderRD::lightmaps_set_bicubic_filter(bool p_enable) { _update_shader_quality_settings(); } +void RendererSceneRenderRD::material_set_use_debanding(bool p_enable) { + material_use_debanding = p_enable; + _update_shader_quality_settings(); +} + int RendererSceneRenderRD::get_roughness_layers() const { return sky.roughness_layers; } @@ -1702,6 +1707,7 @@ void RendererSceneRenderRD::init() { decals_set_filter(RS::DecalFilter(int(GLOBAL_GET("rendering/textures/decals/filter")))); light_projectors_set_filter(RS::LightProjectorFilter(int(GLOBAL_GET("rendering/textures/light_projectors/filter")))); lightmaps_set_bicubic_filter(GLOBAL_GET("rendering/lightmapping/lightmap_gi/use_bicubic_filter")); + material_set_use_debanding(GLOBAL_GET("rendering/anti_aliasing/quality/use_debanding")); cull_argument.set_page_pool(&cull_argument_pool); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 08251c001a4..0673562c039 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -154,6 +154,7 @@ private: int soft_shadow_samples = 0; RS::DecalFilter decals_filter = RS::DECAL_FILTER_LINEAR_MIPMAPS; RS::LightProjectorFilter light_projectors_filter = RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS; + bool material_use_debanding = false; /* RENDER BUFFERS */ @@ -278,6 +279,7 @@ public: virtual void decals_set_filter(RS::DecalFilter p_filter) override; virtual void light_projectors_set_filter(RS::LightProjectorFilter p_filter) override; virtual void lightmaps_set_bicubic_filter(bool p_enable) override; + virtual void material_set_use_debanding(bool p_enable) override; _FORCE_INLINE_ RS::ShadowQuality shadows_quality_get() const { return shadows_quality; @@ -328,6 +330,10 @@ public: return decals_filter; } + _FORCE_INLINE_ bool material_use_debanding_get() const { + return material_use_debanding; + } + int get_roughness_layers() const; bool is_using_radiance_cubemap_array() const; diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index 8512849c405..8eca5a67fdd 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -2225,6 +2225,28 @@ void main() { frag_color = out_color; + if (sc_use_material_debanding()) { + // 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: `gl_FragCoord` 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. + + // 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. + // This dither offset was chosen because it meshes nicely with the no-offset dither that + // is used for Viewport debanding. + const vec2 dither_offset = vec2(0.535, 8.715); + vec3 dither = vec3(dot(vec2(171.0, 231.0), gl_FragCoord.xy + dither_offset)); + 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. + // Assume that this shader always writes to a 10-bit buffer, so divide by 1023 to align + // to 10-bit quantization. + frag_color.rgb += (dither.rgb - 0.5) / 1023.0; + } + #endif //MODE_MULTIPLE_RENDER_TARGETS #endif //MODE_RENDER_DEPTH diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl index 5f6efb45612..2d907111c9a 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl @@ -116,34 +116,38 @@ bool sc_use_lightmap_bicubic_filter() { return ((sc_packed_0() >> 10) & 1U) != 0; } -bool sc_multimesh() { +bool sc_use_material_debanding() { return ((sc_packed_0() >> 11) & 1U) != 0; } -bool sc_multimesh_format_2d() { +bool sc_multimesh() { return ((sc_packed_0() >> 12) & 1U) != 0; } -bool sc_multimesh_has_color() { +bool sc_multimesh_format_2d() { return ((sc_packed_0() >> 13) & 1U) != 0; } -bool sc_multimesh_has_custom_data() { +bool sc_multimesh_has_color() { return ((sc_packed_0() >> 14) & 1U) != 0; } -bool sc_scene_use_ambient_cubemap() { +bool sc_multimesh_has_custom_data() { return ((sc_packed_0() >> 15) & 1U) != 0; } -bool sc_scene_use_reflection_cubemap() { +bool sc_scene_use_ambient_cubemap() { return ((sc_packed_0() >> 16) & 1U) != 0; } -bool sc_scene_roughness_limiter_enabled() { +bool sc_scene_use_reflection_cubemap() { return ((sc_packed_0() >> 17) & 1U) != 0; } +bool sc_scene_roughness_limiter_enabled() { + return ((sc_packed_0() >> 18) & 1U) != 0; +} + uint sc_soft_shadow_samples() { return (sc_packed_0() >> 20) & 63U; } diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 6f7c303ff08..b195fa520a6 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -1390,6 +1390,7 @@ public: PASS1(decals_set_filter, RS::DecalFilter) PASS1(light_projectors_set_filter, RS::LightProjectorFilter) PASS1(lightmaps_set_bicubic_filter, bool) + PASS1(material_set_use_debanding, bool) virtual void update(); diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index c31c68c9365..cf80b3924f8 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -342,6 +342,7 @@ public: virtual void decals_set_filter(RS::DecalFilter p_filter) = 0; virtual void light_projectors_set_filter(RS::LightProjectorFilter p_filter) = 0; virtual void lightmaps_set_bicubic_filter(bool p_enable) = 0; + virtual void material_set_use_debanding(bool p_enable) = 0; virtual void update() = 0; virtual ~RendererSceneRender() {} diff --git a/servers/rendering/rendering_method.h b/servers/rendering/rendering_method.h index 31ff4fc88d8..5c933d13d08 100644 --- a/servers/rendering/rendering_method.h +++ b/servers/rendering/rendering_method.h @@ -355,6 +355,7 @@ public: virtual void decals_set_filter(RS::DecalFilter p_filter) = 0; virtual void light_projectors_set_filter(RS::LightProjectorFilter p_filter) = 0; virtual void lightmaps_set_bicubic_filter(bool p_enable) = 0; + virtual void material_set_use_debanding(bool p_enable) = 0; virtual bool free(RID p_rid) = 0; diff --git a/servers/rendering/rendering_server.cpp b/servers/rendering/rendering_server.cpp index 26de259d842..4ca52a59ce5 100644 --- a/servers/rendering/rendering_server.cpp +++ b/servers/rendering/rendering_server.cpp @@ -2341,6 +2341,8 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("material_set_next_pass", "material", "next_material"), &RenderingServer::material_set_next_pass); + ClassDB::bind_method(D_METHOD("material_set_use_debanding", "enable"), &RenderingServer::material_set_use_debanding); + BIND_CONSTANT(MATERIAL_RENDER_PRIORITY_MIN); BIND_CONSTANT(MATERIAL_RENDER_PRIORITY_MAX); @@ -3698,6 +3700,8 @@ void RenderingServer::init() { GLOBAL_DEF_RST(PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/quality/smaa_edge_detection_threshold", PROPERTY_HINT_RANGE, "0.01,0.2,0.01"), 0.05); + GLOBAL_DEF("rendering/anti_aliasing/quality/use_debanding", false); + { String mode_hints; String mode_hints_metal; diff --git a/servers/rendering/rendering_server.h b/servers/rendering/rendering_server.h index 40ad775e21e..32f7bf0b642 100644 --- a/servers/rendering/rendering_server.h +++ b/servers/rendering/rendering_server.h @@ -271,6 +271,8 @@ public: virtual void material_set_next_pass(RID p_material, RID p_next_material) = 0; + virtual void material_set_use_debanding(bool p_enable) = 0; + /* MESH API */ enum ArrayType { diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index e7cf3cecc3e..49b8f2752c4 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -853,6 +853,7 @@ public: FUNC1(decals_set_filter, RS::DecalFilter); FUNC1(light_projectors_set_filter, RS::LightProjectorFilter); FUNC1(lightmaps_set_bicubic_filter, bool); + FUNC1(material_set_use_debanding, bool); /* CAMERA ATTRIBUTES */