diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 9f64cbf6103a44..173e8a29768716 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -4510,7 +4510,11 @@ Use AMD FidelityFX Super Resolution 2.2 upscaling for the viewport's 3D buffer. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less than [code]1.0[/code] will be result in the viewport being upscaled using FSR2. Values greater than [code]1.0[/code] are not supported and bilinear downsampling will be used instead. A value of [code]1.0[/code] will use FSR2 at native resolution as a TAA solution. - + + Use nearest-neighbor filtering for the viewport's 3D buffer. This looks crisper than [constant VIEWPORT_SCALING_3D_MODE_BILINEAR] and has no additional rendering cost. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values greater than [code]1.0[/code] are not supported and bilinear downsampling will be used instead. A value of [code]1.0[/code] disables scaling. + [b]Note:[/b] To avoid uneven pixel scaling, it's highly recommended to use a value equal to an integer divisor of 1, such as [code]1.0 / 2 = 0.5[/code]. For example, it's best to use a scale of [code]0.5[/code] (2×2), [code]0.3333[/code] (3×3), [code]0.25[/code] (4×4), [code]0.2[/code] (5×5) and so on. + + Represents the size of the [enum ViewportScaling3DMode] enum. diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index 1b5f7148ac219d..6b4c25762aa980 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -446,7 +446,11 @@ Use AMD FidelityFX Super Resolution 2.2 upscaling for the viewport's 3D buffer. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less than [code]1.0[/code] will be result in the viewport being upscaled using FSR2. Values greater than [code]1.0[/code] are not supported and bilinear downsampling will be used instead. A value of [code]1.0[/code] will use FSR2 at native resolution as a TAA solution. - + + Use nearest-neighbor filtering for the viewport's 3D buffer. This looks crisper than [constant SCALING_3D_MODE_BILINEAR] and has no additional rendering cost. The amount of scaling can be set using [member scaling_3d_scale]. Values greater than [code]1.0[/code] are not supported and bilinear downsampling will be used instead. A value of [code]1.0[/code] disables scaling. + [b]Note:[/b] To avoid uneven pixel scaling, it's highly recommended to use a value equal to an integer divisor of 1, such as [code]1.0 / 2 = 0.5[/code]. For example, it's best to use a scale of [code]0.5[/code] (2×2), [code]0.3333[/code] (3×3), [code]0.25[/code] (4×4), [code]0.2[/code] (5×5) and so on. + + Represents the size of the [enum Scaling3DMode] enum. diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 3a4fe9a059588e..2a0cdcaace01be 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -4505,10 +4505,10 @@ void Viewport::_bind_methods() { #ifndef _3D_DISABLED ADD_GROUP("Scaling 3D", ""); - ADD_PROPERTY(PropertyInfo(Variant::INT, "scaling_3d_mode", PROPERTY_HINT_ENUM, "Bilinear (Fastest),FSR 1.0 (Fast),FSR 2.2 (Slow)"), "set_scaling_3d_mode", "get_scaling_3d_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scaling_3d_scale", PROPERTY_HINT_RANGE, "0.25,2.0,0.01"), "set_scaling_3d_scale", "get_scaling_3d_scale"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "scaling_3d_mode", PROPERTY_HINT_ENUM, "Bilinear (Fastest),FSR 1.0 (Fast),FSR 2.2 (Slow),Nearest (Fastest)"), "set_scaling_3d_mode", "get_scaling_3d_mode"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scaling_3d_scale", PROPERTY_HINT_RANGE, "0.1,2.0,0.0001"), "set_scaling_3d_scale", "get_scaling_3d_scale"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_mipmap_bias", PROPERTY_HINT_RANGE, "-2,2,0.001"), "set_texture_mipmap_bias", "get_texture_mipmap_bias"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fsr_sharpness", PROPERTY_HINT_RANGE, "0,2,0.1"), "set_fsr_sharpness", "get_fsr_sharpness"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fsr_sharpness", PROPERTY_HINT_RANGE, "0,2,0.01"), "set_fsr_sharpness", "get_fsr_sharpness"); #endif ADD_GROUP("Variable Rate Shading", "vrs_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "vrs_mode", PROPERTY_HINT_ENUM, "Disabled,Texture,Depth buffer,XR"), "set_vrs_mode", "get_vrs_mode"); @@ -4557,6 +4557,7 @@ void Viewport::_bind_methods() { BIND_ENUM_CONSTANT(SCALING_3D_MODE_BILINEAR); BIND_ENUM_CONSTANT(SCALING_3D_MODE_FSR); BIND_ENUM_CONSTANT(SCALING_3D_MODE_FSR2); + BIND_ENUM_CONSTANT(SCALING_3D_MODE_NEAREST); BIND_ENUM_CONSTANT(SCALING_3D_MODE_MAX); BIND_ENUM_CONSTANT(MSAA_DISABLED); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index a32077a489e85f..dcd15da2e950b8 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -99,6 +99,7 @@ class Viewport : public Node { SCALING_3D_MODE_BILINEAR, SCALING_3D_MODE_FSR, SCALING_3D_MODE_FSR2, + SCALING_3D_MODE_NEAREST, SCALING_3D_MODE_MAX }; diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.cpp b/servers/rendering/renderer_rd/effects/tone_mapper.cpp index 48c651140891e3..82a5948cb71574 100644 --- a/servers/rendering/renderer_rd/effects/tone_mapper.cpp +++ b/servers/rendering/renderer_rd/effects/tone_mapper.cpp @@ -81,7 +81,7 @@ ToneMapper::~ToneMapper() { tonemap.shader.version_free(tonemap.shader_version); } -void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings) { +void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings, RS::CanvasItemTextureFilter p_filter_mode) { UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); @@ -137,7 +137,8 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - RD::Uniform u_source_color(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector({ default_sampler, p_source_color })); + RID viewport_scale_sampler = material_storage->sampler_rd_get_default(p_filter_mode, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + RD::Uniform u_source_color(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector({ viewport_scale_sampler, p_source_color })); RD::Uniform u_exposure_texture; u_exposure_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; @@ -178,7 +179,7 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton RD::get_singleton()->draw_list_end(); } -void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings) { +void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings, RS::CanvasItemTextureFilter p_filter_mode) { UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); @@ -216,9 +217,11 @@ void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_col RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + RID viewport_scale_sampler = material_storage->sampler_rd_get_default(p_filter_mode, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); RD::Uniform u_source_color; u_source_color.uniform_type = RD::UNIFORM_TYPE_INPUT_ATTACHMENT; u_source_color.binding = 0; + u_source_color.append_id(viewport_scale_sampler); u_source_color.append_id(p_source_color); RD::Uniform u_exposure_texture; diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.h b/servers/rendering/renderer_rd/effects/tone_mapper.h index a1a99f931fc32a..27fe734a9b035d 100644 --- a/servers/rendering/renderer_rd/effects/tone_mapper.h +++ b/servers/rendering/renderer_rd/effects/tone_mapper.h @@ -150,8 +150,8 @@ class ToneMapper { bool convert_to_srgb = false; }; - void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings); - void tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings); + void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings, RS::CanvasItemTextureFilter p_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR); + void tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings, RS::CanvasItemTextureFilter p_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR); }; } // namespace RendererRD diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 7696bddbca8511..ba350016922976 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -557,6 +557,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende tonemap.convert_to_srgb = !texture_storage->render_target_is_using_hdr(render_target); RID dest_fb; + RS::CanvasItemTextureFilter filter_mode = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR; bool use_intermediate_fb = use_fsr; if (use_intermediate_fb) { // If we use FSR to upscale we need to write our result into an intermediate buffer. @@ -568,9 +569,14 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende // Target size in this case is lying as we never get our real target size communicated. // Bit nasty but... dest_fb = texture_storage->render_target_get_rd_framebuffer(render_target); + + if (rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_NEAREST) { + // Make the hardware perform nearest-neighbor filtering when scaling the viewport 3D buffer. + filter_mode = RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST; + } } - tone_mapper->tonemapper(color_texture, dest_fb, tonemap); + tone_mapper->tonemapper(color_texture, dest_fb, tonemap, filter_mode); RD::get_singleton()->draw_command_end_label(); } diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 09737d03a024f9..5f1fc35e4645d0 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -121,8 +121,8 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) { bool scaling_3d_is_fsr = (scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) || (scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR2); bool use_taa = p_viewport->use_taa; - if (scaling_3d_is_fsr && (scaling_3d_scale > 1.0)) { - // FSR is not designed for downsampling. + if ((scaling_3d_is_fsr || scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_NEAREST) && (scaling_3d_scale > 1.0)) { + // FSR and nearest-neighbor scaling are not designed for downsampling. // Fall back to bilinear scaling. WARN_PRINT_ONCE("FSR 3D resolution scaling is not designed for downsampling. Falling back to bilinear 3D resolution scaling."); scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR; @@ -150,6 +150,7 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) { switch (scaling_3d_mode) { case RS::VIEWPORT_SCALING_3D_MODE_BILINEAR: + case RS::VIEWPORT_SCALING_3D_MODE_NEAREST: // Clamp 3D rendering resolution to reasonable values supported on most hardware. // This prevents freezing the engine or outright crashing on lower-end GPUs. width = CLAMP(p_viewport->size.width * scaling_3d_scale, 1, 16384); diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index b7c40600cb3ad5..86d90524d99f23 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2253,6 +2253,7 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_BILINEAR); BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_FSR); BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_FSR2); + BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_NEAREST); BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_MAX); BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_DISABLED); @@ -2961,9 +2962,9 @@ void RenderingServer::init() { GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/amount", PROPERTY_HINT_RANGE, "0.01,4.0,0.01"), 0.25); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/limit", PROPERTY_HINT_RANGE, "0.01,1.0,0.01"), 0.18); - GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/scaling_3d/mode", PROPERTY_HINT_ENUM, "Bilinear (Fastest),FSR 1.0 (Fast),FSR 2.2 (Slow)"), 0); - GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/scaling_3d/scale", PROPERTY_HINT_RANGE, "0.25,2.0,0.01"), 1.0); - GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/scaling_3d/fsr_sharpness", PROPERTY_HINT_RANGE, "0,2,0.1"), 0.2f); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/scaling_3d/mode", PROPERTY_HINT_ENUM, "Bilinear (Fastest),FSR 1.0 (Fast),FSR 2.2 (Slow),Nearest (Fastest)"), 0); + GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/scaling_3d/scale", PROPERTY_HINT_RANGE, "0.1,2.0,0.0001"), 1.0); + GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/scaling_3d/fsr_sharpness", PROPERTY_HINT_RANGE, "0,2,0.01"), 0.2f); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/textures/default_filters/texture_mipmap_bias", PROPERTY_HINT_RANGE, "-2,2,0.001"), 0.0f); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/textures/decals/filter", PROPERTY_HINT_ENUM, "Nearest (Fast),Linear (Fast),Nearest Mipmap (Fast),Linear Mipmap (Fast),Nearest Mipmap Anisotropic (Average),Linear Mipmap Anisotropic (Average)"), DECAL_FILTER_LINEAR_MIPMAPS); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 6b2ba562ce9bf6..edf90f1fed8fb0 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -808,6 +808,7 @@ class RenderingServer : public Object { VIEWPORT_SCALING_3D_MODE_BILINEAR, VIEWPORT_SCALING_3D_MODE_FSR, VIEWPORT_SCALING_3D_MODE_FSR2, + VIEWPORT_SCALING_3D_MODE_NEAREST, VIEWPORT_SCALING_3D_MODE_MAX, VIEWPORT_SCALING_3D_MODE_OFF = 255, // for internal use only };