diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml
index 694a09acd8d..0116701ce66 100644
--- a/doc/classes/Environment.xml
+++ b/doc/classes/Environment.xml
@@ -126,7 +126,7 @@
The length of the transition between the no-blur area and far blur.
- The amount of near blur for the depth-of-field effect.
+ The amount of near blur for the depth-of-field effect. [member dof_blur_far_amount] is used if both far and near DOF are enabled.
Distance from the camera where the near blur effect affects the rendering.
@@ -135,7 +135,7 @@
If [code]true[/code], enables the depth-of-field near blur effect.
- The depth-of-field near blur's quality. Higher values can mitigate the visible banding effect seen at higher strengths, but are much slower.
+ The depth-of-field near blur's quality. Higher values can mitigate the visible banding effect seen at higher strengths, but are much slower. [member dof_blur_far_quality] is used if both far and near DOF are enabled.
The length of the transition between the near blur and no-blur area.
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index 09ae5243695..f6d12371aa5 100644
--- a/drivers/gles2/rasterizer_scene_gles2.cpp
+++ b/drivers/gles2/rasterizer_scene_gles2.cpp
@@ -2989,23 +2989,36 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p
// DOF Blur
- if (env && env->dof_blur_far_enabled) {
+ if (env && (env->dof_blur_near_enabled || env->dof_blur_far_enabled)) {
int vp_h = storage->frame.current_rt->height;
int vp_w = storage->frame.current_rt->width;
+ // If both near and far are used, we use the far quality and amount settings.
+ // We should just have one setting like in Godot 4 but that would be a serious breaking change.
+ // This is defendable.
+ float dof_blur_amount = env->dof_blur_far_enabled ? env->dof_blur_far_amount : env->dof_blur_near_amount;
+ VS::EnvironmentDOFBlurQuality quality = env->dof_blur_far_enabled ? env->dof_blur_far_quality : env->dof_blur_near_quality;
+
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal());
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_FAR_BLUR, true);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_LOW, env->dof_blur_far_quality == VS::ENV_DOF_BLUR_QUALITY_LOW);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, env->dof_blur_far_quality == VS::ENV_DOF_BLUR_QUALITY_MEDIUM);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_HIGH, env->dof_blur_far_quality == VS::ENV_DOF_BLUR_QUALITY_HIGH);
+ state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_FAR_BLUR, env->dof_blur_far_enabled);
+ state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_BLUR, env->dof_blur_near_enabled);
+ state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_LOW, quality == VS::ENV_DOF_BLUR_QUALITY_LOW);
+ state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, quality == VS::ENV_DOF_BLUR_QUALITY_MEDIUM);
+ state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_HIGH, quality == VS::ENV_DOF_BLUR_QUALITY_HIGH);
state.effect_blur_shader.bind();
int qsteps[3] = { 4, 10, 20 };
- float radius = (env->dof_blur_far_amount * env->dof_blur_far_amount) / qsteps[env->dof_blur_far_quality];
+ float radius = (dof_blur_amount * dof_blur_amount) / qsteps[quality];
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_BEGIN, env->dof_blur_far_distance);
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_END, env->dof_blur_far_distance + env->dof_blur_far_transition);
+ if (env->dof_blur_far_enabled) {
+ state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_FAR_BEGIN, env->dof_blur_far_distance);
+ state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_FAR_END, env->dof_blur_far_distance + env->dof_blur_far_transition);
+ }
+ if (env->dof_blur_near_enabled) {
+ state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_NEAR_BEGIN, env->dof_blur_near_distance);
+ state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_NEAR_END, env->dof_blur_near_distance - env->dof_blur_near_transition);
+ }
state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_DIR, Vector2(1, 0));
state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_RADIUS, radius);
state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h));
@@ -3039,97 +3052,12 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p
storage->_copy_screen();
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_FAR_BLUR, false);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_LOW, false);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, false);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_HIGH, false);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::USE_ORTHOGONAL_PROJECTION, false);
- }
-
- if (env && env->dof_blur_near_enabled) {
- //convert texture to RGBA format if not already
- if (!storage->frame.current_rt->used_dof_blur_near) {
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
- }
-
- int vp_h = storage->frame.current_rt->height;
- int vp_w = storage->frame.current_rt->width;
-
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal());
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_BLUR, true);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_FIRST_TAP, true);
-
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_LOW, env->dof_blur_near_quality == VS::ENV_DOF_BLUR_QUALITY_LOW);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, env->dof_blur_near_quality == VS::ENV_DOF_BLUR_QUALITY_MEDIUM);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_HIGH, env->dof_blur_near_quality == VS::ENV_DOF_BLUR_QUALITY_HIGH);
-
- state.effect_blur_shader.bind();
- int qsteps[3] = { 4, 10, 20 };
-
- float radius = (env->dof_blur_near_amount * env->dof_blur_near_amount) / qsteps[env->dof_blur_near_quality];
-
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_BEGIN, env->dof_blur_near_distance);
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_END, env->dof_blur_near_distance - env->dof_blur_near_transition);
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_DIR, Vector2(1, 0));
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_RADIUS, radius);
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h));
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::CAMERA_Z_NEAR, p_cam_projection.get_z_near());
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::CAMERA_Z_FAR, p_cam_projection.get_z_far());
-
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth);
-
- glActiveTexture(GL_TEXTURE0);
- if (storage->frame.current_rt->mip_maps[0].color) {
- glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color);
- } else {
- glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[0].color);
- }
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); //copy to front first
-
- storage->_copy_screen();
-
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_FIRST_TAP, false);
- state.effect_blur_shader.bind();
-
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_BEGIN, env->dof_blur_near_distance);
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_END, env->dof_blur_near_distance - env->dof_blur_near_transition);
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_DIR, Vector2(0, 1));
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_RADIUS, radius);
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h));
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::CAMERA_Z_NEAR, p_cam_projection.get_z_near());
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::CAMERA_Z_FAR, p_cam_projection.get_z_far());
-
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color);
-
- glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->mip_maps[0].sizes[0].fbo); // copy to base level
-
- glEnable(GL_BLEND);
- glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- storage->_copy_screen();
-
- glDisable(GL_BLEND);
-
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_BLUR, false);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_FIRST_TAP, false);
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_LOW, false);
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, false);
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_HIGH, false);
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::USE_ORTHOGONAL_PROJECTION, false);
- storage->frame.current_rt->used_dof_blur_near = true;
- }
- 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) {
diff --git a/drivers/gles2/shaders/effect_blur.glsl b/drivers/gles2/shaders/effect_blur.glsl
index 7b607dd76a0..9a0b358e9f9 100644
--- a/drivers/gles2/shaders/effect_blur.glsl
+++ b/drivers/gles2/shaders/effect_blur.glsl
@@ -105,8 +105,10 @@ const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.0
#endif
uniform sampler2D dof_source_depth; //texunit:1
-uniform float dof_begin;
-uniform float dof_end;
+uniform float dof_far_begin;
+uniform float dof_far_end;
+uniform float dof_near_begin;
+uniform float dof_near_end;
uniform vec2 dof_dir;
uniform float dof_radius;
@@ -210,7 +212,7 @@ void main() {
#endif
#endif //!USE_GLES_OVER_GL
-#ifdef DOF_FAR_BLUR
+#if defined(DOF_FAR_BLUR) || defined(DOF_NEAR_BLUR)
vec4 color_accum = vec4(0.0);
@@ -222,79 +224,59 @@ void main() {
depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
#endif
- float amount = smoothstep(dof_begin, dof_end, depth);
- float k_accum = 0.0;
-
- for (int i = 0; i < dof_kernel_size; i++) {
- int int_ofs = i - dof_kernel_from;
- vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * amount * dof_radius;
-
- float tap_k = dof_kernel[i];
-
- float tap_depth = texture2D(dof_source_depth, tap_uv, 0.0).r;
- tap_depth = tap_depth * 2.0 - 1.0;
-#ifdef USE_ORTHOGONAL_PROJECTION
- tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
-#else
- tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near));
+ // Combine near and far, our depth is unlikely to be in both ranges
+ float amount = 1.0;
+#ifdef DOF_FAR_BLUR
+ amount *= 1.0 - smoothstep(dof_far_begin, dof_far_end, depth);
#endif
- float tap_amount = int_ofs == 0 ? 1.0 : smoothstep(dof_begin, dof_end, tap_depth);
- tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect
-
- vec4 tap_color = texture2DLod(source_color, tap_uv, 0.0) * tap_k;
-
- k_accum += tap_k * tap_amount;
- color_accum += tap_color * tap_amount;
- }
-
- if (k_accum > 0.0) {
- color_accum /= k_accum;
- }
-
- gl_FragColor = color_accum; ///k_accum;
-
-#endif
-
#ifdef DOF_NEAR_BLUR
+ amount *= smoothstep(dof_near_end, dof_near_begin, depth);
+#endif
+ amount = 1.0 - amount;
- vec4 color_accum = vec4(0.0);
+ if (amount > 0.0) {
+ float k_accum = 0.0;
- float max_accum = 0.0;
+ for (int i = 0; i < dof_kernel_size; i++) {
+ int int_ofs = i - dof_kernel_from;
+ vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * amount * dof_radius;
- for (int i = 0; i < dof_kernel_size; i++) {
- int int_ofs = i - dof_kernel_from;
- vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * dof_radius;
- float ofs_influence = max(0.0, 1.0 - abs(float(int_ofs)) / float(dof_kernel_from));
+ float tap_k = dof_kernel[i];
- float tap_k = dof_kernel[i];
-
- vec4 tap_color = texture2DLod(source_color, tap_uv, 0.0);
-
- float tap_depth = texture2D(dof_source_depth, tap_uv, 0.0).r;
- tap_depth = tap_depth * 2.0 - 1.0;
+ float tap_depth = texture2D(dof_source_depth, tap_uv, 0.0).r;
+ tap_depth = tap_depth * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
+ tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
- tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near));
+ tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near));
#endif
- float tap_amount = 1.0 - smoothstep(dof_end, dof_begin, tap_depth);
- tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect
-
-#ifdef DOF_NEAR_FIRST_TAP
-
- tap_color.a = 1.0 - smoothstep(dof_end, dof_begin, tap_depth);
-
+ float tap_amount = 1.0;
+#ifdef DOF_FAR_BLUR
+ tap_amount *= int_ofs == 0 ? 0.0 : (1.0 - smoothstep(dof_far_begin, dof_far_end, tap_depth));
#endif
+#ifdef DOF_NEAR_BLUR
+ tap_amount *= int_ofs == 0 ? 0.0 : (smoothstep(dof_near_end, dof_near_begin, tap_depth));
+#endif
+ tap_amount = 1.0 - tap_amount;
- max_accum = max(max_accum, tap_amount * ofs_influence);
+ tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect
- color_accum += tap_color * tap_k;
+ vec4 tap_color = texture2DLod(source_color, tap_uv, 0.0) * tap_k;
+
+ k_accum += tap_k * tap_amount;
+ color_accum += tap_color * tap_amount;
+ }
+
+ if (k_accum > 0.0) {
+ color_accum /= k_accum;
+ }
+
+ gl_FragColor = color_accum; ///k_accum;
+ } else {
+ // We're in focus, no need to waste time sampling the same UV a bunch of times...
+ gl_FragColor = texture2DLod(source_color, uv_interp, 0.0);
}
- color_accum.a = max(color_accum.a, sqrt(max_accum));
-
- gl_FragColor = color_accum;
-
#endif
#ifdef GLOW_FIRST_PASS
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index e193d6d58d5..43db3a13313 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -3535,26 +3535,39 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p
GLuint composite_from = storage->frame.current_rt->effects.mip_maps[0].color;
- if (env && env->dof_blur_far_enabled) {
+ if (env && (env->dof_blur_near_enabled || env->dof_blur_far_enabled)) {
//blur diffuse into effect mipmaps using separatable convolution
//storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true);
int vp_h = storage->frame.current_rt->height;
int vp_w = storage->frame.current_rt->width;
+ // If both near and far are used, we use the far quality and amount settings.
+ // We should just have one setting like in Godot 4 but that would be a serious breaking change.
+ // This is defendable.
+ float dof_blur_amount = env->dof_blur_far_enabled ? env->dof_blur_far_amount : env->dof_blur_near_amount;
+ VS::EnvironmentDOFBlurQuality quality = env->dof_blur_far_enabled ? env->dof_blur_far_quality : env->dof_blur_near_quality;
+
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal());
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_FAR_BLUR, true);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_LOW, env->dof_blur_far_quality == VS::ENV_DOF_BLUR_QUALITY_LOW);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_MEDIUM, env->dof_blur_far_quality == VS::ENV_DOF_BLUR_QUALITY_MEDIUM);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_HIGH, env->dof_blur_far_quality == VS::ENV_DOF_BLUR_QUALITY_HIGH);
+ state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_FAR_BLUR, env->dof_blur_far_enabled);
+ state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_NEAR_BLUR, env->dof_blur_near_enabled);
+ state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_LOW, quality == VS::ENV_DOF_BLUR_QUALITY_LOW);
+ state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_MEDIUM, quality == VS::ENV_DOF_BLUR_QUALITY_MEDIUM);
+ state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_HIGH, quality == VS::ENV_DOF_BLUR_QUALITY_HIGH);
state.effect_blur_shader.bind();
int qsteps[3] = { 4, 10, 20 };
- float radius = (env->dof_blur_far_amount * env->dof_blur_far_amount) / qsteps[env->dof_blur_far_quality];
+ float radius = (dof_blur_amount * dof_blur_amount) / qsteps[quality];
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_BEGIN, env->dof_blur_far_distance);
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_END, env->dof_blur_far_distance + env->dof_blur_far_transition);
+ if (env->dof_blur_far_enabled) {
+ state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_FAR_BEGIN, env->dof_blur_far_distance);
+ state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_FAR_END, env->dof_blur_far_distance + env->dof_blur_far_transition);
+ }
+ if (env->dof_blur_near_enabled) {
+ state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_NEAR_BEGIN, env->dof_blur_near_distance);
+ state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_NEAR_END, env->dof_blur_near_distance - env->dof_blur_near_transition);
+ }
state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_DIR, Vector2(1, 0));
state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_RADIUS, radius);
state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h));
@@ -3582,101 +3595,14 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p
_copy_screen();
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_FAR_BLUR, false);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_LOW, false);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_MEDIUM, false);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_HIGH, false);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_ORTHOGONAL_PROJECTION, false);
-
- composite_from = storage->frame.current_rt->effects.mip_maps[0].color;
- }
-
- if (env && env->dof_blur_near_enabled) {
- //blur diffuse into effect mipmaps using separatable convolution
- //storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true);
-
- int vp_h = storage->frame.current_rt->height;
- int vp_w = storage->frame.current_rt->width;
-
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal());
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_NEAR_BLUR, true);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_NEAR_FIRST_TAP, true);
-
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_LOW, env->dof_blur_near_quality == VS::ENV_DOF_BLUR_QUALITY_LOW);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_MEDIUM, env->dof_blur_near_quality == VS::ENV_DOF_BLUR_QUALITY_MEDIUM);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_HIGH, env->dof_blur_near_quality == VS::ENV_DOF_BLUR_QUALITY_HIGH);
-
- state.effect_blur_shader.bind();
- int qsteps[3] = { 4, 10, 20 };
-
- float radius = (env->dof_blur_near_amount * env->dof_blur_near_amount) / qsteps[env->dof_blur_near_quality];
-
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_BEGIN, env->dof_blur_near_distance);
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_END, env->dof_blur_near_distance - env->dof_blur_near_transition);
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_DIR, Vector2(1, 0));
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_RADIUS, radius);
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h));
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::CAMERA_Z_NEAR, p_cam_projection.get_z_near());
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::CAMERA_Z_FAR, p_cam_projection.get_z_far());
-
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth);
-
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, composite_from);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); //copy to front first
-
- _copy_screen();
- //manually do the blend if this is the first operation resolving from the diffuse buffer
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_NEAR_BLUR_MERGE, composite_from == storage->frame.current_rt->buffers.diffuse);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_NEAR_FIRST_TAP, false);
- state.effect_blur_shader.bind();
-
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_BEGIN, env->dof_blur_near_distance);
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_END, env->dof_blur_near_distance - env->dof_blur_near_transition);
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_DIR, Vector2(0, 1));
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_RADIUS, radius);
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h));
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::CAMERA_Z_NEAR, p_cam_projection.get_z_near());
- state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::CAMERA_Z_FAR, p_cam_projection.get_z_far());
-
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color);
-
- glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); // copy to base level
-
- if (composite_from != storage->frame.current_rt->buffers.diffuse) {
- glEnable(GL_BLEND);
- glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- } else {
- glActiveTexture(GL_TEXTURE2);
- glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->buffers.diffuse);
- }
-
- _copy_screen(true);
-
- if (composite_from != storage->frame.current_rt->buffers.diffuse) {
- glDisable(GL_BLEND);
- }
-
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_NEAR_BLUR, false);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_NEAR_FIRST_TAP, false);
- state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_NEAR_BLUR_MERGE, false);
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_LOW, false);
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_MEDIUM, false);
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_HIGH, false);
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_ORTHOGONAL_PROJECTION, false);
composite_from = storage->frame.current_rt->effects.mip_maps[0].color;
- }
- 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);
diff --git a/drivers/gles3/shaders/effect_blur.glsl b/drivers/gles3/shaders/effect_blur.glsl
index 3a7330c826f..6d920f45fa0 100644
--- a/drivers/gles3/shaders/effect_blur.glsl
+++ b/drivers/gles3/shaders/effect_blur.glsl
@@ -77,16 +77,13 @@ const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.0
#endif
uniform sampler2D dof_source_depth; //texunit:1
-uniform float dof_begin;
-uniform float dof_end;
+uniform float dof_far_begin;
+uniform float dof_far_end;
+uniform float dof_near_begin;
+uniform float dof_near_end;
uniform vec2 dof_dir;
uniform float dof_radius;
-#ifdef DOF_NEAR_BLUR_MERGE
-
-uniform sampler2D source_dof_original; //texunit:2
-#endif
-
#endif
#ifdef GLOW_FIRST_PASS
@@ -161,7 +158,7 @@ void main() {
frag_color = color;
#endif
-#ifdef DOF_FAR_BLUR
+#if defined(DOF_FAR_BLUR) || defined(DOF_NEAR_BLUR)
vec4 color_accum = vec4(0.0);
@@ -173,89 +170,57 @@ void main() {
depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
#endif
- float amount = smoothstep(dof_begin, dof_end, depth);
- float k_accum = 0.0;
-
- for (int i = 0; i < dof_kernel_size; i++) {
- int int_ofs = i - dof_kernel_from;
- vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * amount * dof_radius;
-
- float tap_k = dof_kernel[i];
-
- float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r;
- tap_depth = tap_depth * 2.0 - 1.0;
-#ifdef USE_ORTHOGONAL_PROJECTION
- tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
-#else
- tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near));
+ // Combine near and far, our depth is unlikely to be in both ranges
+ float amount = 1.0;
+#ifdef DOF_FAR_BLUR
+ amount *= 1.0 - smoothstep(dof_far_begin, dof_far_end, depth);
#endif
- float tap_amount = mix(smoothstep(dof_begin, dof_end, tap_depth), 1.0, int_ofs == 0);
- tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect
-
- vec4 tap_color = textureLod(source_color, tap_uv, 0.0) * tap_k;
-
- k_accum += tap_k * tap_amount;
- color_accum += tap_color * tap_amount;
- }
-
- if (k_accum > 0.0) {
- color_accum /= k_accum;
- }
-
- frag_color = color_accum; ///k_accum;
-
-#endif
-
#ifdef DOF_NEAR_BLUR
+ amount *= smoothstep(dof_near_end, dof_near_begin, depth);
+#endif
+ amount = 1.0 - amount;
- vec4 color_accum = vec4(0.0);
+ if (amount > 0.0) {
+ float k_accum = 0.0;
- float max_accum = 0.0;
+ for (int i = 0; i < dof_kernel_size; i++) {
+ int int_ofs = i - dof_kernel_from;
+ vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * amount * dof_radius;
- for (int i = 0; i < dof_kernel_size; i++) {
- int int_ofs = i - dof_kernel_from;
- vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * dof_radius;
- float ofs_influence = max(0.0, 1.0 - float(abs(int_ofs)) / float(dof_kernel_from));
+ float tap_k = dof_kernel[i];
- float tap_k = dof_kernel[i];
-
- vec4 tap_color = textureLod(source_color, tap_uv, 0.0);
-
- float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r;
- tap_depth = tap_depth * 2.0 - 1.0;
+ float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r;
+ tap_depth = tap_depth * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
+ tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
- tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near));
+ tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near));
#endif
- float tap_amount = 1.0 - smoothstep(dof_end, dof_begin, tap_depth);
- tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect
-
-#ifdef DOF_NEAR_FIRST_TAP
-
- tap_color.a = 1.0 - smoothstep(dof_end, dof_begin, tap_depth);
-
+ float tap_amount = 1.0;
+#ifdef DOF_FAR_BLUR
+ tap_amount *= mix(1.0 - smoothstep(dof_far_begin, dof_far_end, tap_depth), 0.0, int_ofs == 0);
#endif
+#ifdef DOF_NEAR_BLUR
+ tap_amount *= mix(smoothstep(dof_near_end, dof_near_begin, tap_depth), 0.0, int_ofs == 0);
+#endif
+ tap_amount = 1.0 - tap_amount;
+ tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect
- max_accum = max(max_accum, tap_amount * ofs_influence);
+ vec4 tap_color = textureLod(source_color, tap_uv, 0.0) * tap_k;
- color_accum += tap_color * tap_k;
+ k_accum += tap_k * tap_amount;
+ color_accum += tap_color * tap_amount;
+ }
+
+ if (k_accum > 0.0) {
+ color_accum /= k_accum;
+ }
+
+ frag_color = color_accum; ///k_accum;
+ } else {
+ // We're in focus, no need to waste time sampling the same UV a bunch of times...
+ frag_color = textureLod(source_color, uv_interp, 0.0);
}
-
- color_accum.a = max(color_accum.a, sqrt(max_accum));
-
-#ifdef DOF_NEAR_BLUR_MERGE
-
- vec4 original = textureLod(source_dof_original, uv_interp, 0.0);
- color_accum = mix(original, color_accum, color_accum.a);
-
-#endif
-
-#ifndef DOF_NEAR_FIRST_TAP
- //color_accum=vec4(vec3(color_accum.a),1.0);
-#endif
- frag_color = color_accum;
-
#endif
#ifdef GLOW_FIRST_PASS