Combined the DOF far and DOF near passes

This commit is contained in:
Bastiaan Olij 2021-07-22 13:45:57 +10:00
parent 40b57319e2
commit 39658b4e07
5 changed files with 131 additions and 330 deletions

View file

@ -126,7 +126,7 @@
The length of the transition between the no-blur area and far blur. The length of the transition between the no-blur area and far blur.
</member> </member>
<member name="dof_blur_near_amount" type="float" setter="set_dof_blur_near_amount" getter="get_dof_blur_near_amount" default="0.1"> <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>
<member name="dof_blur_near_distance" type="float" setter="set_dof_blur_near_distance" getter="get_dof_blur_near_distance" default="2.0"> <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. 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. If [code]true[/code], enables the depth-of-field near blur effect.
</member> </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"> <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>
<member name="dof_blur_near_transition" type="float" setter="set_dof_blur_near_transition" getter="get_dof_blur_near_transition" default="1.0"> <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. The length of the transition between the near blur and no-blur area.

View file

@ -2989,23 +2989,36 @@ void RasterizerSceneGLES2::_post_process(Environment *env, const CameraMatrix &p
// DOF Blur // 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_h = storage->frame.current_rt->height;
int vp_w = storage->frame.current_rt->width; 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::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_FAR_BLUR, env->dof_blur_far_enabled);
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_NEAR_BLUR, env->dof_blur_near_enabled);
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_LOW, quality == VS::ENV_DOF_BLUR_QUALITY_LOW);
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_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(); state.effect_blur_shader.bind();
int qsteps[3] = { 4, 10, 20 }; 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); if (env->dof_blur_far_enabled) {
state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_END, env->dof_blur_far_distance + env->dof_blur_far_transition); 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_DIR, Vector2(1, 0));
state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_RADIUS, radius); 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::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(); storage->_copy_screen();
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_FAR_BLUR, false); 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_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_LOW, false);
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, 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::DOF_QUALITY_HIGH, false);
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::USE_ORTHOGONAL_PROJECTION, 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 //these needed to disable filtering, reenamble
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
if (storage->frame.current_rt->mip_maps[0].color) { if (storage->frame.current_rt->mip_maps[0].color) {

View file

@ -105,8 +105,10 @@ const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.0
#endif #endif
uniform sampler2D dof_source_depth; //texunit:1 uniform sampler2D dof_source_depth; //texunit:1
uniform float dof_begin; uniform float dof_far_begin;
uniform float dof_end; uniform float dof_far_end;
uniform float dof_near_begin;
uniform float dof_near_end;
uniform vec2 dof_dir; uniform vec2 dof_dir;
uniform float dof_radius; uniform float dof_radius;
@ -210,7 +212,7 @@ void main() {
#endif #endif
#endif //!USE_GLES_OVER_GL #endif //!USE_GLES_OVER_GL
#ifdef DOF_FAR_BLUR #if defined(DOF_FAR_BLUR) || defined(DOF_NEAR_BLUR)
vec4 color_accum = vec4(0.0); 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)); depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
#endif #endif
float amount = smoothstep(dof_begin, dof_end, depth); // Combine near and far, our depth is unlikely to be in both ranges
float k_accum = 0.0; float amount = 1.0;
#ifdef DOF_FAR_BLUR
for (int i = 0; i < dof_kernel_size; i++) { amount *= 1.0 - smoothstep(dof_far_begin, dof_far_end, depth);
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 #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 #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++) { float tap_k = dof_kernel[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_depth = texture2D(dof_source_depth, tap_uv, 0.0).r;
tap_depth = tap_depth * 2.0 - 1.0;
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;
#ifdef USE_ORTHOGONAL_PROJECTION #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 #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 #endif
float tap_amount = 1.0 - smoothstep(dof_end, dof_begin, tap_depth); float tap_amount = 1.0;
tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect #ifdef DOF_FAR_BLUR
tap_amount *= int_ofs == 0 ? 0.0 : (1.0 - smoothstep(dof_far_begin, dof_far_end, tap_depth));
#ifdef DOF_NEAR_FIRST_TAP
tap_color.a = 1.0 - smoothstep(dof_end, dof_begin, tap_depth);
#endif #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 #endif
#ifdef GLOW_FIRST_PASS #ifdef GLOW_FIRST_PASS

View file

@ -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; 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 //blur diffuse into effect mipmaps using separatable convolution
//storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true); //storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true);
int vp_h = storage->frame.current_rt->height; int vp_h = storage->frame.current_rt->height;
int vp_w = storage->frame.current_rt->width; 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::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_FAR_BLUR, env->dof_blur_far_enabled);
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_NEAR_BLUR, env->dof_blur_near_enabled);
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_LOW, quality == VS::ENV_DOF_BLUR_QUALITY_LOW);
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_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(); state.effect_blur_shader.bind();
int qsteps[3] = { 4, 10, 20 }; 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); if (env->dof_blur_far_enabled) {
state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_END, env->dof_blur_far_distance + env->dof_blur_far_transition); 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_DIR, Vector2(1, 0));
state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::DOF_RADIUS, radius); 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::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(); _copy_screen();
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_FAR_BLUR, false); 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_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_LOW, false);
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_MEDIUM, 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::DOF_QUALITY_HIGH, false);
state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_ORTHOGONAL_PROJECTION, false); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_ORTHOGONAL_PROJECTION, false);
composite_from = storage->frame.current_rt->effects.mip_maps[0].color; 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 //these needed to disable filtering, reenamble
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color);

View file

@ -77,16 +77,13 @@ const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.0
#endif #endif
uniform sampler2D dof_source_depth; //texunit:1 uniform sampler2D dof_source_depth; //texunit:1
uniform float dof_begin; uniform float dof_far_begin;
uniform float dof_end; uniform float dof_far_end;
uniform float dof_near_begin;
uniform float dof_near_end;
uniform vec2 dof_dir; uniform vec2 dof_dir;
uniform float dof_radius; uniform float dof_radius;
#ifdef DOF_NEAR_BLUR_MERGE
uniform sampler2D source_dof_original; //texunit:2
#endif
#endif #endif
#ifdef GLOW_FIRST_PASS #ifdef GLOW_FIRST_PASS
@ -161,7 +158,7 @@ void main() {
frag_color = color; frag_color = color;
#endif #endif
#ifdef DOF_FAR_BLUR #if defined(DOF_FAR_BLUR) || defined(DOF_NEAR_BLUR)
vec4 color_accum = vec4(0.0); 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)); depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
#endif #endif
float amount = smoothstep(dof_begin, dof_end, depth); // Combine near and far, our depth is unlikely to be in both ranges
float k_accum = 0.0; float amount = 1.0;
#ifdef DOF_FAR_BLUR
for (int i = 0; i < dof_kernel_size; i++) { amount *= 1.0 - smoothstep(dof_far_begin, dof_far_end, depth);
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));
#endif #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 #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++) { float tap_k = dof_kernel[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_depth = texture(dof_source_depth, tap_uv, 0.0).r;
tap_depth = tap_depth * 2.0 - 1.0;
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;
#ifdef USE_ORTHOGONAL_PROJECTION #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 #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 #endif
float tap_amount = 1.0 - smoothstep(dof_end, dof_begin, tap_depth); float tap_amount = 1.0;
tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect #ifdef DOF_FAR_BLUR
tap_amount *= mix(1.0 - smoothstep(dof_far_begin, dof_far_end, tap_depth), 0.0, int_ofs == 0);
#ifdef DOF_NEAR_FIRST_TAP
tap_color.a = 1.0 - smoothstep(dof_end, dof_begin, tap_depth);
#endif #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 #endif
#ifdef GLOW_FIRST_PASS #ifdef GLOW_FIRST_PASS