Skip to content

Commit

Permalink
Merge pull request #50723 from BastiaanOlij/combine_far_near_dof
Browse files Browse the repository at this point in the history
Combined the DOF far and DOF near passes
  • Loading branch information
akien-mga authored Jul 22, 2021
2 parents ca8e488 + 39658b4 commit 214106d
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 327 deletions.
4 changes: 2 additions & 2 deletions doc/classes/Environment.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@
The length of the transition between the no-blur area and far blur.
</member>
<member name="dof_blur_near_amount" type="float" setter="set_dof_blur_near_amount" getter="get_dof_blur_near_amount" default="0.1">
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.
</member>
<member name="dof_blur_near_distance" type="float" setter="set_dof_blur_near_distance" getter="get_dof_blur_near_distance" default="2.0">
Distance from the camera where the near blur effect affects the rendering.
Expand All @@ -135,7 +135,7 @@
If [code]true[/code], enables the depth-of-field near blur effect.
</member>
<member name="dof_blur_near_quality" type="int" setter="set_dof_blur_near_quality" getter="get_dof_blur_near_quality" enum="Environment.DOFBlurQuality" default="1">
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.
</member>
<member name="dof_blur_near_transition" type="float" setter="set_dof_blur_near_transition" getter="get_dof_blur_near_transition" default="1.0">
The length of the transition between the near blur and no-blur area.
Expand Down
114 changes: 21 additions & 93 deletions drivers/gles2/rasterizer_scene_gles2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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) {
Expand Down
102 changes: 42 additions & 60 deletions drivers/gles2/shaders/effect_blur.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);

Expand All @@ -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));
#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;

// 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

#ifdef DOF_NEAR_BLUR
amount *= smoothstep(dof_near_end, dof_near_begin, depth);
#endif
amount = 1.0 - amount;

vec4 color_accum = vec4(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) * dof_radius;
float ofs_influence = max(0.0, 1.0 - abs(float(int_ofs)) / float(dof_kernel_from));
if (amount > 0.0) {
float k_accum = 0.0;

float tap_k = dof_kernel[i];
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;

vec4 tap_color = texture2DLod(source_color, tap_uv, 0.0);
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;
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
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;

#ifdef DOF_NEAR_FIRST_TAP
tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect

tap_color.a = 1.0 - smoothstep(dof_end, dof_begin, tap_depth);
vec4 tap_color = texture2DLod(source_color, tap_uv, 0.0) * tap_k;

#endif
k_accum += tap_k * tap_amount;
color_accum += tap_color * tap_amount;
}

max_accum = max(max_accum, tap_amount * ofs_influence);
if (k_accum > 0.0) {
color_accum /= k_accum;
}

color_accum += tap_color * tap_k;
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
Expand Down
Loading

0 comments on commit 214106d

Please sign in to comment.