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