diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 00c151f0806..2cc3086acf4 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -1119,6 +1119,9 @@ Sets the number of MSAA samples to use. 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. [b]Note:[/b] MSAA is not available on HTML5 export using the GLES2 backend. + + Enables FXAA in the root Viewport. FXAA is a popular screen-space antialiasing method, which is fast but will make the image look blurry, especially at lower resolutions. It can still work relatively well at large resolutions such as 1440p and 4K. + If [code]true[/code], uses nearest-neighbor mipmap filtering when using mipmaps (also called "bilinear filtering"), which will result in visible seams appearing between mipmap stages. This may increase performance in mobile as less memory bandwidth is used. If [code]false[/code], linear mipmap filtering (also called "trilinear filtering") is used. diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index f58671d48a9..f3aa7a7fa2c 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -241,6 +241,9 @@ If [code]true[/code], the viewport will disable 3D rendering. For actual disabling use [code]usage[/code]. + + Enables fast approximate antialiasing. FXAA is a popular screen-space antialiasing method, which is fast but will make the image look blurry, especially at lower resolutions. It can still work relatively well at large resolutions such as 1440p and 4K. + The global canvas transform of the viewport. The canvas transform is relative to this. diff --git a/doc/classes/VisualServer.xml b/doc/classes/VisualServer.xml index dbb93685c3d..058256a5912 100644 --- a/doc/classes/VisualServer.xml +++ b/doc/classes/VisualServer.xml @@ -4231,6 +4231,17 @@ If [code]true[/code], the viewport uses augmented or virtual reality technologies. See [ARVRInterface]. + + + + + + + + + Enables fast approximate antialiasing for this viewport. FXAA is a popular screen-space antialiasing method, which is fast but will make the image look blurry, especially at lower resolutions. It can still work relatively well at large resolutions such as 1440p and 4K. + + diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index 5488845a191..e3661b5232d 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_dummy.h @@ -708,6 +708,7 @@ public: bool render_target_was_used(RID p_render_target) { return false; } void render_target_clear_used(RID p_render_target) {} void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa) {} + void render_target_set_use_fxaa(RID p_render_target, bool p_fxaa) {} /* CANVAS SHADOW */ diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index 6fb19eae599..b81d651c8a4 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -2735,6 +2735,7 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p if (env) { use_post_process = use_post_process && (env->adjustments_enabled || env->glow_enabled || env->dof_blur_far_enabled || env->dof_blur_near_enabled); } + use_post_process = use_post_process || storage->frame.current_rt->use_fxaa; GLuint next_buffer; @@ -2787,12 +2788,13 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p // Order of operation //1) DOF Blur (first blur, then copy to buffer applying the blur) //only on desktop - //2) Bloom (Glow) //only on desktop - //3) Adjustments + //2) FXAA + //3) Bloom (Glow) //only on desktop + //4) Adjustments // DOF Blur - if (env->dof_blur_far_enabled) { + if (env && env->dof_blur_far_enabled) { int vp_h = storage->frame.current_rt->height; int vp_w = storage->frame.current_rt->width; @@ -2849,7 +2851,7 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::USE_ORTHOGONAL_PROJECTION, false); } - if (env->dof_blur_near_enabled) { + if (env && env->dof_blur_near_enabled) { //convert texture to RGBA format if not already if (!storage->frame.current_rt->used_dof_blur_near) { @@ -2934,7 +2936,7 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p storage->frame.current_rt->used_dof_blur_near = true; } - if (env->dof_blur_near_enabled || env->dof_blur_far_enabled) { + if (env && (env->dof_blur_near_enabled || env->dof_blur_far_enabled)) { //these needed to disable filtering, reenamble glActiveTexture(GL_TEXTURE0); if (storage->frame.current_rt->mip_maps[0].color) { @@ -2955,7 +2957,7 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p int max_glow_level = -1; int glow_mask = 0; - if (env->glow_enabled) { + if (env && env->glow_enabled) { for (int i = 0; i < VS::MAX_GLOW_LEVELS; i++) { if (env->glow_levels & (1 << i)) { @@ -3046,80 +3048,85 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[0].color); } - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_FILTER_BICUBIC, env->glow_bicubic_upscale); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_FXAA, storage->frame.current_rt->use_fxaa); - if (max_glow_level >= 0) { - if (storage->frame.current_rt->mip_maps[0].color) { - for (int i = 0; i < (max_glow_level + 1); i++) { + if (env) { - if (glow_mask & (1 << i)) { - if (i == 0) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL1, true); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_FILTER_BICUBIC, env->glow_bicubic_upscale); + + if (max_glow_level >= 0) { + if (storage->frame.current_rt->mip_maps[0].color) { + for (int i = 0; i < (max_glow_level + 1); i++) { + + if (glow_mask & (1 << i)) { + if (i == 0) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL1, true); + } + if (i == 1) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL2, true); + } + if (i == 2) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL3, true); + } + if (i == 3) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL4, true); + } + if (i == 4) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL5, true); + } + if (i == 5) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL6, true); + } + if (i == 6) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL7, true); + } } - if (i == 1) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL2, true); - } - if (i == 2) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL3, true); - } - if (i == 3) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL4, true); - } - if (i == 4) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL5, true); - } - if (i == 5) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL6, true); - } - if (i == 6) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL7, true); + } + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color); + } else { + + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_MULTI_TEXTURE_GLOW, true); + int active_glow_level = 0; + for (int i = 0; i < (max_glow_level + 1); i++) { + + if (glow_mask & (1 << i)) { + active_glow_level++; + glActiveTexture(GL_TEXTURE1 + active_glow_level); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[i + 1].color); + if (active_glow_level == 1) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL1, true); + } + if (active_glow_level == 2) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL2, true); + } + if (active_glow_level == 3) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL3, true); + } + if (active_glow_level == 4) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL4, true); + } + if (active_glow_level == 5) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL5, true); + } + if (active_glow_level == 6) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL6, true); + } + if (active_glow_level == 7) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL7, true); + } } } } - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color); - } else { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_MULTI_TEXTURE_GLOW, true); - int active_glow_level = 0; - for (int i = 0; i < (max_glow_level + 1); i++) { - - if (glow_mask & (1 << i)) { - active_glow_level++; - glActiveTexture(GL_TEXTURE1 + active_glow_level); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[i + 1].color); - if (active_glow_level == 1) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL1, true); - } - if (active_glow_level == 2) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL2, true); - } - if (active_glow_level == 3) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL3, true); - } - if (active_glow_level == 4) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL4, true); - } - if (active_glow_level == 5) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL5, true); - } - if (active_glow_level == 6) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL6, true); - } - if (active_glow_level == 7) { - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL7, true); - } - } - } + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SCREEN, env->glow_blend_mode == VS::GLOW_BLEND_MODE_SCREEN); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SOFTLIGHT, env->glow_blend_mode == VS::GLOW_BLEND_MODE_SOFTLIGHT); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_REPLACE, env->glow_blend_mode == VS::GLOW_BLEND_MODE_REPLACE); } - - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SCREEN, env->glow_blend_mode == VS::GLOW_BLEND_MODE_SCREEN); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SOFTLIGHT, env->glow_blend_mode == VS::GLOW_BLEND_MODE_SOFTLIGHT); - state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_REPLACE, env->glow_blend_mode == VS::GLOW_BLEND_MODE_REPLACE); } //Adjustments - if (env->adjustments_enabled) { + if (env && env->adjustments_enabled) { state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_BCS, true); RasterizerStorageGLES2::Texture *tex = storage->texture_owner.getornull(env->color_correction); @@ -3131,25 +3138,31 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p } state.tonemap_shader.bind(); + if (env) { + if (max_glow_level >= 0) { - if (max_glow_level >= 0) { + state.tonemap_shader.set_uniform(TonemapShaderGLES2::GLOW_INTENSITY, env->glow_intensity); + int ss[2] = { + storage->frame.current_rt->width, + storage->frame.current_rt->height, + }; + glUniform2iv(state.tonemap_shader.get_uniform(TonemapShaderGLES2::GLOW_TEXTURE_SIZE), 1, ss); + } - state.tonemap_shader.set_uniform(TonemapShaderGLES2::GLOW_INTENSITY, env->glow_intensity); - int ss[2] = { - storage->frame.current_rt->width, - storage->frame.current_rt->height, - }; - glUniform2iv(state.tonemap_shader.get_uniform(TonemapShaderGLES2::GLOW_TEXTURE_SIZE), 1, ss); + if (env->adjustments_enabled) { + + state.tonemap_shader.set_uniform(TonemapShaderGLES2::BCS, Vector3(env->adjustments_brightness, env->adjustments_contrast, env->adjustments_saturation)); + } } - if (env->adjustments_enabled) { - - state.tonemap_shader.set_uniform(TonemapShaderGLES2::BCS, Vector3(env->adjustments_brightness, env->adjustments_contrast, env->adjustments_saturation)); + if (storage->frame.current_rt->use_fxaa) { + state.tonemap_shader.set_uniform(TonemapShaderGLES2::PIXEL_SIZE, Vector2(1.0 / storage->frame.current_rt->width, 1.0 / storage->frame.current_rt->height)); } storage->_copy_screen(); //turn off everything used + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_FXAA, false); state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL1, false); state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL2, false); state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL3, false); diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h index 74adae05aab..0124d61ca6a 100644 --- a/drivers/gles2/rasterizer_scene_gles2.h +++ b/drivers/gles2/rasterizer_scene_gles2.h @@ -475,6 +475,7 @@ public: virtual void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality); virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality); + virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale); virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture); diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index af8cf45fb6d..90d9f9c3317 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -5414,6 +5414,13 @@ void RasterizerStorageGLES2::render_target_set_msaa(RID p_render_target, VS::Vie _render_target_allocate(rt); } +void RasterizerStorageGLES2::render_target_set_use_fxaa(RID p_render_target, bool p_fxaa) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + + rt->use_fxaa = p_fxaa; +} + /* CANVAS SHADOW */ RID RasterizerStorageGLES2::canvas_light_shadow_buffer_create(int p_width) { diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index e56465a3f91..01e33af7295 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -1218,6 +1218,8 @@ public: bool used_in_frame; VS::ViewportMSAA msaa; + bool use_fxaa; + RID texture; bool used_dof_blur_near; @@ -1237,6 +1239,7 @@ public: height(0), used_in_frame(false), msaa(VS::VIEWPORT_MSAA_DISABLED), + use_fxaa(false), used_dof_blur_near(false), mip_maps_allocated(false) { for (int i = 0; i < RENDER_TARGET_FLAG_MAX; ++i) { @@ -1261,6 +1264,7 @@ public: virtual bool render_target_was_used(RID p_render_target); virtual void render_target_clear_used(RID p_render_target); virtual void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa); + virtual void render_target_set_use_fxaa(RID p_render_target, bool p_fxaa); /* CANVAS SHADOW */ diff --git a/drivers/gles2/shaders/tonemap.glsl b/drivers/gles2/shaders/tonemap.glsl index ae1ba439e1d..5cd27b42c6f 100644 --- a/drivers/gles2/shaders/tonemap.glsl +++ b/drivers/gles2/shaders/tonemap.glsl @@ -94,6 +94,10 @@ uniform highp float glow_intensity; uniform vec3 bcs; #endif +#ifdef USE_FXAA +uniform vec2 pixel_size; +#endif + #ifdef USE_COLOR_CORRECTION uniform sampler2D color_correction; //texunit:1 #endif @@ -140,7 +144,7 @@ uniform ivec2 glow_texture_size; vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) { float lod = float(p_lod); vec2 tex_size = vec2(glow_texture_size >> p_lod); - vec2 pixel_size = vec2(1.0) / tex_size; + vec2 texel_size = vec2(1.0) / tex_size; uv = uv * tex_size + vec2(0.5); @@ -154,10 +158,10 @@ vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) { float h0y = h0(fuv.y); float h1y = h1(fuv.y); - vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5)) * pixel_size; - vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5)) * pixel_size; - vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5)) * pixel_size; - vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5)) * pixel_size; + vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5)) * texel_size; + vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5)) * texel_size; + vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5)) * texel_size; + vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5)) * texel_size; return (g0(fuv.y) * (g0x * texture2DLod(tex, p0, lod) + g1x * texture2DLod(tex, p1, lod))) + (g1(fuv.y) * (g0x * texture2DLod(tex, p2, lod) + g1x * texture2DLod(tex, p3, lod))); @@ -212,9 +216,58 @@ vec3 apply_color_correction(vec3 color, sampler2D correction_tex) { return color; } +vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) { + const float FXAA_REDUCE_MIN = (1.0 / 128.0); + const float FXAA_REDUCE_MUL = (1.0 / 8.0); + const float FXAA_SPAN_MAX = 8.0; + + vec3 rgbNW = texture2DLod(source, uv_interp + vec2(-1.0, -1.0) * pixel_size, 0.0).xyz; + vec3 rgbNE = texture2DLod(source, uv_interp + vec2(1.0, -1.0) * pixel_size, 0.0).xyz; + vec3 rgbSW = texture2DLod(source, uv_interp + vec2(-1.0, 1.0) * pixel_size, 0.0).xyz; + vec3 rgbSE = texture2DLod(source, uv_interp + vec2(1.0, 1.0) * pixel_size, 0.0).xyz; + vec3 rgbM = color; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), + FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * + pixel_size; + + vec3 rgbA = 0.5 * (texture2DLod(source, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + texture2DLod(source, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * (texture2DLod(source, uv_interp + dir * -0.5, 0.0).xyz + + texture2DLod(source, uv_interp + dir * 0.5, 0.0).xyz); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) { + return rgbA; + } else { + return rgbB; + } +} + void main() { vec3 color = texture2DLod(source, uv_interp, 0.0).rgb; +#ifdef USE_FXAA + color = apply_fxaa(color, uv_interp, pixel_size); +#endif + // Glow #ifdef USING_GLOW diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index ce7951ab5ad..57d9ea9d5dc 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -861,6 +861,7 @@ void RasterizerSceneGLES3::environment_set_dof_blur_near(RID p_env, bool p_enabl env->dof_blur_near_amount = p_amount; env->dof_blur_near_quality = p_quality; } + void RasterizerSceneGLES3::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) { Environment *env = environment_owner.getornull(p_env); @@ -3626,7 +3627,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } - if (!env || storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT] || storage->frame.current_rt->width < 4 || storage->frame.current_rt->height < 4) { //no post process on small render targets + if ((!env || storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT] || storage->frame.current_rt->width < 4 || storage->frame.current_rt->height < 4) && !storage->frame.current_rt->use_fxaa) { //no post process on small render targets //no environment or transparent render, simply return and convert to SRGB if (storage->frame.current_rt->external.fbo != 0) { glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->external.fbo); @@ -3651,14 +3652,14 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p //order of operation //1) DOF Blur (first blur, then copy to buffer applying the blur) - //2) Motion Blur - //3) Bloom + //2) FXAA + //3) Bloom (Glow) //4) Tonemap //5) Adjustments GLuint composite_from = storage->frame.current_rt->effects.mip_maps[0].color; - if (env->dof_blur_far_enabled) { + if (env && env->dof_blur_far_enabled) { //blur diffuse into effect mipmaps using separatable convolution //storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true); @@ -3714,7 +3715,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p composite_from = storage->frame.current_rt->effects.mip_maps[0].color; } - if (env->dof_blur_near_enabled) { + if (env && env->dof_blur_near_enabled) { //blur diffuse into effect mipmaps using separatable convolution //storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true); @@ -3803,7 +3804,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p composite_from = storage->frame.current_rt->effects.mip_maps[0].color; } - if (env->dof_blur_near_enabled || env->dof_blur_far_enabled) { + if (env && (env->dof_blur_near_enabled || env->dof_blur_far_enabled)) { //these needed to disable filtering, reenamble glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); @@ -3813,7 +3814,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } - if (env->auto_exposure) { + if (env && env->auto_exposure) { //compute auto exposure //first step, copy from image to luminance buffer @@ -3897,7 +3898,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p int max_glow_level = -1; int glow_mask = 0; - if (env->glow_enabled) { + if (env && env->glow_enabled) { for (int i = 0; i < VS::MAX_GLOW_LEVELS; i++) { if (env->glow_levels & (1 << i)) { @@ -3983,16 +3984,18 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, composite_from); + if (env) { + state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_FILMIC_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_FILMIC); + state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_ACES_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_ACES); + state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_REINHARD_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_REINHARD); + state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_AUTO_EXPOSURE, env->auto_exposure); + state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_FILTER_BICUBIC, env->glow_bicubic_upscale); + } - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_FILMIC_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_FILMIC); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_ACES_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_ACES); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_REINHARD_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_REINHARD); state.tonemap_shader.set_conditional(TonemapShaderGLES3::KEEP_3D_LINEAR, storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_KEEP_3D_LINEAR]); + state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_FXAA, storage->frame.current_rt->use_fxaa); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_AUTO_EXPOSURE, env->auto_exposure); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_FILTER_BICUBIC, env->glow_bicubic_upscale); - - if (max_glow_level >= 0) { + if (env && max_glow_level >= 0) { for (int i = 0; i < (max_glow_level + 1); i++) { @@ -4028,7 +4031,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); } - if (env->adjustments_enabled) { + if (env && env->adjustments_enabled) { state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_BCS, true); RasterizerStorageGLES3::Texture *tex = storage->texture_owner.getornull(env->color_correction); @@ -4042,34 +4045,44 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p state.tonemap_shader.set_conditional(TonemapShaderGLES3::V_FLIP, storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]); state.tonemap_shader.bind(); - state.tonemap_shader.set_uniform(TonemapShaderGLES3::EXPOSURE, env->tone_mapper_exposure); - state.tonemap_shader.set_uniform(TonemapShaderGLES3::WHITE, env->tone_mapper_exposure_white); + if (env) { + state.tonemap_shader.set_uniform(TonemapShaderGLES3::EXPOSURE, env->tone_mapper_exposure); + state.tonemap_shader.set_uniform(TonemapShaderGLES3::WHITE, env->tone_mapper_exposure_white); - if (max_glow_level >= 0) { + if (max_glow_level >= 0) { - state.tonemap_shader.set_uniform(TonemapShaderGLES3::GLOW_INTENSITY, env->glow_intensity); - int ss[2] = { - storage->frame.current_rt->width, - storage->frame.current_rt->height, - }; - glUniform2iv(state.tonemap_shader.get_uniform(TonemapShaderGLES3::GLOW_TEXTURE_SIZE), 1, ss); + state.tonemap_shader.set_uniform(TonemapShaderGLES3::GLOW_INTENSITY, env->glow_intensity); + int ss[2] = { + storage->frame.current_rt->width, + storage->frame.current_rt->height, + }; + glUniform2iv(state.tonemap_shader.get_uniform(TonemapShaderGLES3::GLOW_TEXTURE_SIZE), 1, ss); + } + + if (env->auto_exposure) { + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->exposure.color); + state.tonemap_shader.set_uniform(TonemapShaderGLES3::AUTO_EXPOSURE_GREY, env->auto_exposure_grey); + } + + if (env->adjustments_enabled) { + + state.tonemap_shader.set_uniform(TonemapShaderGLES3::BCS, Vector3(env->adjustments_brightness, env->adjustments_contrast, env->adjustments_saturation)); + } + } else { + // No environment, so no exposure. + state.tonemap_shader.set_uniform(TonemapShaderGLES3::EXPOSURE, 1.0); } - if (env->auto_exposure) { - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->exposure.color); - state.tonemap_shader.set_uniform(TonemapShaderGLES3::AUTO_EXPOSURE_GREY, env->auto_exposure_grey); - } - - if (env->adjustments_enabled) { - - state.tonemap_shader.set_uniform(TonemapShaderGLES3::BCS, Vector3(env->adjustments_brightness, env->adjustments_contrast, env->adjustments_saturation)); + if (storage->frame.current_rt->use_fxaa) { + state.tonemap_shader.set_uniform(TonemapShaderGLES3::PIXEL_SIZE, Vector2(1.0 / storage->frame.current_rt->width, 1.0 / storage->frame.current_rt->height)); } _copy_screen(true, true); //turn off everything used + state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_FXAA, false); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_AUTO_EXPOSURE, false); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_FILMIC_TONEMAPPER, false); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_ACES_TONEMAPPER, false); diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 7885d7c1b7c..9c48a98bfbb 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -549,6 +549,7 @@ public: virtual void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality); virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality); + virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale); virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 07d9826bdd4..d2330830aa5 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -7753,6 +7753,14 @@ void RasterizerStorageGLES3::render_target_set_msaa(RID p_render_target, VS::Vie _render_target_allocate(rt); } +void RasterizerStorageGLES3::render_target_set_use_fxaa(RID p_render_target, bool p_fxaa) { + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + + rt->use_fxaa = p_fxaa; +} + /* CANVAS SHADOW */ RID RasterizerStorageGLES3::canvas_light_shadow_buffer_create(int p_width) { diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index bfa451080f3..b7aefa2dea7 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -1390,6 +1390,7 @@ public: bool used_in_frame; VS::ViewportMSAA msaa; + bool use_fxaa; RID texture; @@ -1400,7 +1401,8 @@ public: width(0), height(0), used_in_frame(false), - msaa(VS::VIEWPORT_MSAA_DISABLED) { + msaa(VS::VIEWPORT_MSAA_DISABLED), + use_fxaa(false) { exposure.fbo = 0; buffers.fbo = 0; external.fbo = 0; @@ -1428,6 +1430,7 @@ public: virtual bool render_target_was_used(RID p_render_target); virtual void render_target_clear_used(RID p_render_target); virtual void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa); + virtual void render_target_set_use_fxaa(RID p_render_target, bool p_fxaa); /* CANVAS SHADOW */ diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl index 3e3596bc0dd..7ceaa387e17 100644 --- a/drivers/gles3/shaders/tonemap.glsl +++ b/drivers/gles3/shaders/tonemap.glsl @@ -48,6 +48,10 @@ uniform highp float glow_intensity; uniform vec3 bcs; #endif +#ifdef USE_FXAA +uniform vec2 pixel_size; +#endif + #ifdef USE_COLOR_CORRECTION uniform sampler2D color_correction; //texunit:3 #endif @@ -95,7 +99,7 @@ uniform ivec2 glow_texture_size; vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) { float lod = float(p_lod); vec2 tex_size = vec2(glow_texture_size >> p_lod); - vec2 pixel_size = vec2(1.0f) / tex_size; + vec2 texel_size = vec2(1.0f) / tex_size; uv = uv * tex_size + vec2(0.5f); @@ -109,10 +113,10 @@ vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) { float h0y = h0(fuv.y); float h1y = h1(fuv.y); - vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5f)) * pixel_size; - vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5f)) * pixel_size; - vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5f)) * pixel_size; - vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5f)) * pixel_size; + vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5f)) * texel_size; + vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5f)) * texel_size; + vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5f)) * texel_size; + vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5f)) * texel_size; return (g0(fuv.y) * (g0x * textureLod(tex, p0, lod) + g1x * textureLod(tex, p1, lod))) + (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod))); @@ -263,6 +267,51 @@ vec3 apply_color_correction(vec3 color, sampler2D correction_tex) { return color; } +vec3 apply_fxaa(vec3 color, float exposure, vec2 uv_interp, vec2 pixel_size) { + const float FXAA_REDUCE_MIN = (1.0 / 128.0); + const float FXAA_REDUCE_MUL = (1.0 / 8.0); + const float FXAA_SPAN_MAX = 8.0; + + vec3 rgbNW = textureLod(source, uv_interp + vec2(-1.0, -1.0) * pixel_size, 0.0).xyz * exposure; + vec3 rgbNE = textureLod(source, uv_interp + vec2(1.0, -1.0) * pixel_size, 0.0).xyz * exposure; + vec3 rgbSW = textureLod(source, uv_interp + vec2(-1.0, 1.0) * pixel_size, 0.0).xyz * exposure; + vec3 rgbSE = textureLod(source, uv_interp + vec2(1.0, 1.0) * pixel_size, 0.0).xyz * exposure; + vec3 rgbM = color; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), + FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * + pixel_size; + + vec3 rgbA = 0.5 * (textureLod(source, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz * exposure + textureLod(source, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz) * exposure; + vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source, uv_interp + dir * -0.5, 0.0).xyz * exposure + + textureLod(source, uv_interp + dir * 0.5, 0.0).xyz * exposure); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) { + return rgbA; + } else { + return rgbB; + } +} + void main() { vec3 color = textureLod(source, uv_interp, 0.0f).rgb; @@ -274,6 +323,11 @@ void main() { color *= exposure; +#ifdef USE_FXAA + // FXAA must be applied before tonemapping. + color = apply_fxaa(color, exposure, uv_interp, pixel_size); +#endif + // Early Tonemap & SRGB Conversion; note that Linear tonemapping does not clamp to [0, 1]; some operations below expect a [0, 1] range and will clamp color = apply_tonemapping(color, white); diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 37cffb909a2..3ac599072e4 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -2483,6 +2483,9 @@ void SpatialEditorViewport::_notification(int p_what) { int msaa_mode = ProjectSettings::get_singleton()->get("rendering/quality/filters/msaa"); viewport->set_msaa(Viewport::MSAA(msaa_mode)); + bool use_fxaa = ProjectSettings::get_singleton()->get("rendering/quality/filters/use_fxaa"); + viewport->set_use_fxaa(use_fxaa); + bool hdr = ProjectSettings::get_singleton()->get("rendering/quality/depth/hdr"); viewport->set_hdr(hdr); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 938390f3b50..84ca72f55a0 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -2079,6 +2079,9 @@ SceneTree::SceneTree() { ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/filters/msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x")); root->set_msaa(Viewport::MSAA(msaa_mode)); + const bool use_fxaa = GLOBAL_DEF("rendering/quality/filters/use_fxaa", false); + root->set_use_fxaa(use_fxaa); + GLOBAL_DEF_RST("rendering/quality/depth/hdr", true); GLOBAL_DEF("rendering/quality/depth/hdr.mobile", false); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 459d43a73f8..2ef3b1fd64e 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -3018,6 +3018,17 @@ Viewport::MSAA Viewport::get_msaa() const { return msaa; } +void Viewport::set_use_fxaa(bool p_fxaa) { + + use_fxaa = p_fxaa; + VS::get_singleton()->viewport_set_use_fxaa(viewport, use_fxaa); +} + +bool Viewport::get_use_fxaa() const { + + return use_fxaa; +} + void Viewport::set_hdr(bool p_hdr) { if (hdr == p_hdr) @@ -3153,6 +3164,9 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_msaa", "msaa"), &Viewport::set_msaa); ClassDB::bind_method(D_METHOD("get_msaa"), &Viewport::get_msaa); + ClassDB::bind_method(D_METHOD("set_use_fxaa", "enable"), &Viewport::set_use_fxaa); + ClassDB::bind_method(D_METHOD("get_use_fxaa"), &Viewport::get_use_fxaa); + ClassDB::bind_method(D_METHOD("set_hdr", "enable"), &Viewport::set_hdr); ClassDB::bind_method(D_METHOD("get_hdr"), &Viewport::get_hdr); @@ -3241,6 +3255,7 @@ void Viewport::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handle_input_locally"), "set_handle_input_locally", "is_handling_input_locally"); ADD_GROUP("Rendering", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x"), "set_msaa", "get_msaa"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fxaa"), "set_use_fxaa", "get_use_fxaa"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hdr"), "set_hdr", "get_hdr"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_3d_linear"), "set_keep_3d_linear", "get_keep_3d_linear"); @@ -3401,6 +3416,7 @@ Viewport::Viewport() { gui.last_mouse_focus = NULL; msaa = MSAA_DISABLED; + use_fxaa = false; hdr = true; usage = USAGE_3D; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index da329fdf436..0b52978f598 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -282,6 +282,7 @@ private: ShadowAtlasQuadrantSubdiv shadow_atlas_quadrant_subdiv[4]; MSAA msaa; + bool use_fxaa; bool hdr; Ref default_texture; @@ -495,6 +496,9 @@ public: void set_msaa(MSAA p_msaa); MSAA get_msaa() const; + void set_use_fxaa(bool p_fxaa); + bool get_use_fxaa() const; + void set_hdr(bool p_hdr); bool get_hdr() const; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 2c0512fa948..e27ddb9c8b6 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -572,6 +572,7 @@ public: virtual bool render_target_was_used(RID p_render_target) = 0; virtual void render_target_clear_used(RID p_render_target) = 0; virtual void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa) = 0; + virtual void render_target_set_use_fxaa(RID p_render_target, bool p_fxaa) = 0; /* CANVAS SHADOW */ diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 5661d4df06f..6db1c009f69 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -485,6 +485,7 @@ public: BIND2(viewport_set_shadow_atlas_size, RID, int) BIND3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int) BIND2(viewport_set_msaa, RID, ViewportMSAA) + BIND2(viewport_set_use_fxaa, RID, bool) BIND2(viewport_set_hdr, RID, bool) BIND2(viewport_set_usage, RID, ViewportUsage) diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index 6e70e934342..af5b6685daf 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -653,6 +653,14 @@ void VisualServerViewport::viewport_set_msaa(RID p_viewport, VS::ViewportMSAA p_ VSG::storage->render_target_set_msaa(viewport->render_target, p_msaa); } +void VisualServerViewport::viewport_set_use_fxaa(RID p_viewport, bool p_fxaa) { + + Viewport *viewport = viewport_owner.getornull(p_viewport); + ERR_FAIL_COND(!viewport); + + VSG::storage->render_target_set_use_fxaa(viewport->render_target, p_fxaa); +} + void VisualServerViewport::viewport_set_hdr(RID p_viewport, bool p_enabled) { Viewport *viewport = viewport_owner.getornull(p_viewport); diff --git a/servers/visual/visual_server_viewport.h b/servers/visual/visual_server_viewport.h index e8d36f70af9..129a8391307 100644 --- a/servers/visual/visual_server_viewport.h +++ b/servers/visual/visual_server_viewport.h @@ -190,6 +190,7 @@ public: void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv); void viewport_set_msaa(RID p_viewport, VS::ViewportMSAA p_msaa); + void viewport_set_use_fxaa(RID p_viewport, bool p_fxaa); void viewport_set_hdr(RID p_viewport, bool p_enabled); void viewport_set_usage(RID p_viewport, VS::ViewportUsage p_usage); diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 1474b5761aa..e73a6ef6036 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -412,6 +412,7 @@ public: FUNC2(viewport_set_shadow_atlas_size, RID, int) FUNC3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int) FUNC2(viewport_set_msaa, RID, ViewportMSAA) + FUNC2(viewport_set_use_fxaa, RID, bool) FUNC2(viewport_set_hdr, RID, bool) FUNC2(viewport_set_usage, RID, ViewportUsage) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 9d31e501a71..9473a21ff77 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1891,6 +1891,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_size", "viewport", "size"), &VisualServer::viewport_set_shadow_atlas_size); ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_quadrant_subdivision", "viewport", "quadrant", "subdivision"), &VisualServer::viewport_set_shadow_atlas_quadrant_subdivision); ClassDB::bind_method(D_METHOD("viewport_set_msaa", "viewport", "msaa"), &VisualServer::viewport_set_msaa); + ClassDB::bind_method(D_METHOD("viewport_set_use_fxaa", "viewport", "fxaa"), &VisualServer::viewport_set_use_fxaa); ClassDB::bind_method(D_METHOD("viewport_set_hdr", "viewport", "enabled"), &VisualServer::viewport_set_hdr); ClassDB::bind_method(D_METHOD("viewport_set_usage", "viewport", "usage"), &VisualServer::viewport_set_usage); ClassDB::bind_method(D_METHOD("viewport_get_render_info", "viewport", "info"), &VisualServer::viewport_get_render_info); diff --git a/servers/visual_server.h b/servers/visual_server.h index 68523e6c997..804d8e166e3 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -680,6 +680,7 @@ public: }; virtual void viewport_set_msaa(RID p_viewport, ViewportMSAA p_msaa) = 0; + virtual void viewport_set_use_fxaa(RID p_viewport, bool p_fxaa) = 0; enum ViewportUsage { VIEWPORT_USAGE_2D,