diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 110bc133efa35..488eba79ecc4d 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -4771,7 +4771,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 b288ee7ff63ab..da6018abdc5e9 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -465,7 +465,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/drivers/gles3/effects/post_effects.cpp b/drivers/gles3/effects/post_effects.cpp
index 105c8f6b71a20..0be9a22f7bfa7 100644
--- a/drivers/gles3/effects/post_effects.cpp
+++ b/drivers/gles3/effects/post_effects.cpp
@@ -87,7 +87,7 @@ void PostEffects::_draw_screen_triangle() {
glBindVertexArray(0);
}
-void PostEffects::post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuint p_source_color, Size2i p_source_size, float p_luminance_multiplier, const Glow::GLOWLEVEL *p_glow_buffers, float p_glow_intensity, uint32_t p_view, bool p_use_multiview, uint64_t p_spec_constants) {
+void PostEffects::post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuint p_source_color, Size2i p_source_size, float p_luminance_multiplier, const Glow::GLOWLEVEL *p_glow_buffers, float p_glow_intensity, uint32_t p_view, bool p_use_multiview, uint64_t p_spec_constants, bool p_filter) {
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDisable(GL_BLEND);
@@ -115,8 +115,9 @@ void PostEffects::post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuin
GLenum texture_target = p_use_multiview ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
glActiveTexture(GL_TEXTURE0);
glBindTexture(texture_target, p_source_color);
- glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, p_filter ? GL_LINEAR : GL_NEAREST);
+ glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, p_filter ? GL_LINEAR : GL_NEAREST);
if (p_glow_buffers != nullptr) {
glActiveTexture(GL_TEXTURE1);
diff --git a/drivers/gles3/effects/post_effects.h b/drivers/gles3/effects/post_effects.h
index 916d29a052d14..071daecea5ade 100644
--- a/drivers/gles3/effects/post_effects.h
+++ b/drivers/gles3/effects/post_effects.h
@@ -59,7 +59,7 @@ class PostEffects {
PostEffects();
~PostEffects();
- void post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuint p_source_color, Size2i p_source_size, float p_luminance_multiplier, const Glow::GLOWLEVEL *p_glow_buffers, float p_glow_intensity, uint32_t p_view = 0, bool p_use_multiview = false, uint64_t p_spec_constants = 0);
+ void post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuint p_source_color, Size2i p_source_size, float p_luminance_multiplier, const Glow::GLOWLEVEL *p_glow_buffers, float p_glow_intensity, uint32_t p_view = 0, bool p_use_multiview = false, uint64_t p_spec_constants = 0, bool p_filter = true);
};
} //namespace GLES3
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 7048301e57782..12c441f615397 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -2769,7 +2769,7 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
}
// Copy color buffer
- post_effects->post_copy(fbo_rt, target_size, color, internal_size, p_render_data->luminance_multiplier, glow_buffers, glow_intensity, 0, false, bcs_spec_constants);
+ post_effects->post_copy(fbo_rt, target_size, color, internal_size, p_render_data->luminance_multiplier, glow_buffers, glow_intensity, 0, false, bcs_spec_constants, p_render_data->render_buffers->scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_NEAREST);
// Copy depth buffer
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_int);
@@ -2837,7 +2837,7 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend
glBindFramebuffer(GL_FRAMEBUFFER, fbos[2]);
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, write_color, 0, v);
- post_effects->post_copy(fbos[2], target_size, source_color, internal_size, p_render_data->luminance_multiplier, glow_buffers, glow_intensity, v, true, bcs_spec_constants);
+ post_effects->post_copy(fbos[2], target_size, source_color, internal_size, p_render_data->luminance_multiplier, glow_buffers, glow_intensity, v, true, bcs_spec_constants, p_render_data->render_buffers->scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_NEAREST);
}
// Copy depth
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
index cb194933edf36..dfbc87e24987a 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.cpp
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
@@ -167,11 +167,11 @@ void RenderSceneBuffersGLES3::configure(const RenderSceneBuffersConfiguration *p
} else if (scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF && internal_size == target_size) {
// If size matches, we won't use scaling.
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
- } else if (scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF && scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_BILINEAR) {
- // We only support bilinear scaling atm.
- WARN_PRINT_ONCE("GLES only supports bilinear scaling.");
+ } else if (scaling_3d_mode != RS::VIEWPORT_SCALING_3D_MODE_OFF && !(scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_BILINEAR || scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_NEAREST)) {
+ WARN_PRINT_ONCE("The Compatibility rendering method only supports bilinear and nearest-neighbor scaling. Falling back to bilinear scaling.");
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR;
}
+ // Nearest/bilinear scaling decision is handled in `RasterizerSceneGLES3::_render_post_processing()`.
// Check if we support MSAA.
if (msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED && internal_size.x == 0 && internal_size.y == 0) {
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index b8c691c6e79f8..1f20fbe1dedcd 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -4826,10 +4826,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");
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");
ADD_PROPERTY(PropertyInfo(Variant::INT, "vrs_update_mode", PROPERTY_HINT_ENUM, "Disabled,Once,Always"), "set_vrs_update_mode", "get_vrs_update_mode");
@@ -4880,6 +4880,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 2474b890b0687..41420ff2a2a21 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 e943071f0e47b..db1628346d51b 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 a1a99f931fc32..27fe734a9b035 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 6cb03871c9698..6cc667d03e3f2 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -640,6 +640,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.
@@ -657,9 +658,14 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
} else {
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 884f8adb8c4e7..6d9d718532ac7 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -126,10 +126,10 @@ 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 + EPSILON))) {
- // 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 + EPSILON))) {
+ // 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.");
+ WARN_PRINT_ONCE("FSR or nearest-neighbor 3D resolution scaling is not designed for downsampling. Falling back to bilinear 3D resolution scaling.");
scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR;
}
@@ -154,6 +154,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.
target_width = p_viewport->size.width;
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index ab82e42f433c6..8dc45507cca5e 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -2830,6 +2830,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);
@@ -3590,9 +3591,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 5bc028dfdd80a..5121bdc06824a 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -872,6 +872,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
};