Add fast approximate antialiasing (FXAA) to Viewport
This backports FXAA from the `master` branch. Co-authored-by: Clay John <claynjohn@gmail.com>
This commit is contained in:
parent
eefb417614
commit
af45c97652
25 changed files with 340 additions and 125 deletions
|
@ -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.
|
||||
</member>
|
||||
<member name="rendering/quality/filters/use_fxaa" type="bool" setter="" getter="" default="false">
|
||||
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.
|
||||
</member>
|
||||
<member name="rendering/quality/filters/use_nearest_mipmap_filter" type="bool" setter="" getter="" default="false">
|
||||
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.
|
||||
</member>
|
||||
|
|
|
@ -241,6 +241,9 @@
|
|||
<member name="disable_3d" type="bool" setter="set_disable_3d" getter="is_3d_disabled" default="false">
|
||||
If [code]true[/code], the viewport will disable 3D rendering. For actual disabling use [code]usage[/code].
|
||||
</member>
|
||||
<member name="fxaa" type="bool" setter="set_use_fxaa" getter="get_use_fxaa" default="false">
|
||||
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.
|
||||
</member>
|
||||
<member name="global_canvas_transform" type="Transform2D" setter="set_global_canvas_transform" getter="get_global_canvas_transform">
|
||||
The global canvas transform of the viewport. The canvas transform is relative to this.
|
||||
</member>
|
||||
|
|
|
@ -4231,6 +4231,17 @@
|
|||
If [code]true[/code], the viewport uses augmented or virtual reality technologies. See [ARVRInterface].
|
||||
</description>
|
||||
</method>
|
||||
<method name="viewport_set_use_fxaa">
|
||||
<return type="void">
|
||||
</return>
|
||||
<argument index="0" name="viewport" type="RID">
|
||||
</argument>
|
||||
<argument index="1" name="fxaa" type="bool">
|
||||
</argument>
|
||||
<description>
|
||||
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.
|
||||
</description>
|
||||
</method>
|
||||
<method name="viewport_set_vflip">
|
||||
<return type="void">
|
||||
</return>
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -282,6 +282,7 @@ private:
|
|||
ShadowAtlasQuadrantSubdiv shadow_atlas_quadrant_subdiv[4];
|
||||
|
||||
MSAA msaa;
|
||||
bool use_fxaa;
|
||||
bool hdr;
|
||||
|
||||
Ref<ViewportTexture> 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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue