EEVEE-Next: Depth Of Field: Use random sampling in slight focus gather

This replace the previous square rings approach by sampling a disk the
footprint of the search area. This avoids sampling in areas in corners
where there isn't any weight.

This results in much less samples needed to acheive a good enough result.
The max number of samples for an area of 11x11 px is hard coded to 16 and
still gives good results with the final clamp.

The number of samples is adaptative and is scaled by the search area (max
CoC).

The High Quality Slight Defocus is not required anymore. If there is a
quality parameter to add, it would be sample count option. But I consider
the temporal stability enough for viewport work and render can still
render many full scene samples. So I don't see a need for that yet.
This commit is contained in:
2022-08-05 13:51:29 +02:00
parent 3690dad40a
commit 2a4cc0c81c
8 changed files with 53 additions and 75 deletions

View File

@@ -267,7 +267,6 @@ class RENDER_PT_eevee_next_depth_of_field(RenderButtonsPanel, Panel):
col.prop(props, "bokeh_max_size") col.prop(props, "bokeh_max_size")
col.prop(props, "bokeh_threshold") col.prop(props, "bokeh_threshold")
col.prop(props, "bokeh_neighbor_max") col.prop(props, "bokeh_neighbor_max")
col.prop(props, "use_bokeh_high_quality_slight_defocus")
col.prop(props, "use_bokeh_jittered") col.prop(props, "use_bokeh_jittered")
col = layout.column() col = layout.column()

View File

@@ -57,6 +57,7 @@
#define DOF_TILES_DILATE_GROUP_SIZE 8 #define DOF_TILES_DILATE_GROUP_SIZE 8
#define DOF_BOKEH_LUT_SIZE 32 #define DOF_BOKEH_LUT_SIZE 32
#define DOF_MAX_SLIGHT_FOCUS_RADIUS 5 #define DOF_MAX_SLIGHT_FOCUS_RADIUS 5
#define DOF_SLIGHT_FOCUS_SAMPLE_MAX 16
#define DOF_MIP_COUNT 4 #define DOF_MIP_COUNT 4
#define DOF_REDUCE_GROUP_SIZE (1 << (DOF_MIP_COUNT - 1)) #define DOF_REDUCE_GROUP_SIZE (1 << (DOF_MIP_COUNT - 1))
#define DOF_DEFAULT_GROUP_SIZE 32 #define DOF_DEFAULT_GROUP_SIZE 32

View File

@@ -55,8 +55,6 @@ void DepthOfField::init()
/* Reminder: These are parameters not interpolated by motion blur. */ /* Reminder: These are parameters not interpolated by motion blur. */
int update = 0; int update = 0;
int sce_flag = sce_eevee.flag; int sce_flag = sce_eevee.flag;
update += assign_if_different(do_hq_slight_focus_,
(sce_flag & SCE_EEVEE_DOF_HQ_SLIGHT_FOCUS) != 0);
update += assign_if_different(do_jitter_, (sce_flag & SCE_EEVEE_DOF_JITTER) != 0); update += assign_if_different(do_jitter_, (sce_flag & SCE_EEVEE_DOF_JITTER) != 0);
update += assign_if_different(user_overblur_, sce_eevee.bokeh_overblur / 100.0f); update += assign_if_different(user_overblur_, sce_eevee.bokeh_overblur / 100.0f);
update += assign_if_different(fx_max_coc_, sce_eevee.bokeh_max_size); update += assign_if_different(fx_max_coc_, sce_eevee.bokeh_max_size);
@@ -462,8 +460,7 @@ void DepthOfField::resolve_pass_sync()
resolve_ps_ = DRW_pass_create("Dof.resolve_ps_", DRW_STATE_NO_DRAW); resolve_ps_ = DRW_pass_create("Dof.resolve_ps_", DRW_STATE_NO_DRAW);
bool use_lut = bokeh_lut_ps_ != nullptr; bool use_lut = bokeh_lut_ps_ != nullptr;
eShaderType sh_type = do_hq_slight_focus_ ? (use_lut ? DOF_RESOLVE_LUT_HQ : DOF_RESOLVE_HQ) : eShaderType sh_type = use_lut ? DOF_RESOLVE_LUT : DOF_RESOLVE;
(use_lut ? DOF_RESOLVE_LUT : DOF_RESOLVE);
GPUShader *sh = inst_.shaders.static_shader_get(sh_type); GPUShader *sh = inst_.shaders.static_shader_get(sh_type);
DRWShadingGroup *grp = DRW_shgroup_create(sh, resolve_ps_); DRWShadingGroup *grp = DRW_shgroup_create(sh, resolve_ps_);
inst_.sampling.bind_resources(grp); inst_.sampling.bind_resources(grp);

View File

@@ -136,8 +136,6 @@ class DepthOfField {
/** Scene settings that are immutable. */ /** Scene settings that are immutable. */
float user_overblur_; float user_overblur_;
float fx_max_coc_; float fx_max_coc_;
/** Use High Quality (expensive) in-focus gather pass. */
bool do_hq_slight_focus_;
/** Use jittered depth of field where we randomize camera location. */ /** Use jittered depth of field where we randomize camera location. */
bool do_jitter_; bool do_jitter_;

View File

@@ -99,23 +99,19 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
case DOF_GATHER_FOREGROUND_LUT: case DOF_GATHER_FOREGROUND_LUT:
return "eevee_depth_of_field_gather_foreground_lut"; return "eevee_depth_of_field_gather_foreground_lut";
case DOF_GATHER_FOREGROUND: case DOF_GATHER_FOREGROUND:
return "eevee_depth_of_field_gather_foreground"; return "eevee_depth_of_field_gather_foreground_no_lut";
case DOF_GATHER_BACKGROUND_LUT: case DOF_GATHER_BACKGROUND_LUT:
return "eevee_depth_of_field_gather_background_lut"; return "eevee_depth_of_field_gather_background_lut";
case DOF_GATHER_BACKGROUND: case DOF_GATHER_BACKGROUND:
return "eevee_depth_of_field_gather_background"; return "eevee_depth_of_field_gather_background_no_lut";
case DOF_GATHER_HOLE_FILL: case DOF_GATHER_HOLE_FILL:
return "eevee_depth_of_field_hole_fill"; return "eevee_depth_of_field_hole_fill";
case DOF_REDUCE: case DOF_REDUCE:
return "eevee_depth_of_field_reduce"; return "eevee_depth_of_field_reduce";
case DOF_RESOLVE: case DOF_RESOLVE:
return "eevee_depth_of_field_resolve_lq"; return "eevee_depth_of_field_resolve_no_lut";
case DOF_RESOLVE_HQ:
return "eevee_depth_of_field_resolve_hq";
case DOF_RESOLVE_LUT: case DOF_RESOLVE_LUT:
return "eevee_depth_of_field_resolve_lq_lut"; return "eevee_depth_of_field_resolve_lut";
case DOF_RESOLVE_LUT_HQ:
return "eevee_depth_of_field_resolve_hq_lut";
case DOF_SETUP: case DOF_SETUP:
return "eevee_depth_of_field_setup"; return "eevee_depth_of_field_setup";
case DOF_SCATTER: case DOF_SCATTER:

View File

@@ -38,8 +38,6 @@ enum eShaderType {
DOF_GATHER_FOREGROUND, DOF_GATHER_FOREGROUND,
DOF_GATHER_HOLE_FILL, DOF_GATHER_HOLE_FILL,
DOF_REDUCE, DOF_REDUCE,
DOF_RESOLVE_HQ,
DOF_RESOLVE_LUT_HQ,
DOF_RESOLVE_LUT, DOF_RESOLVE_LUT,
DOF_RESOLVE, DOF_RESOLVE,
DOF_SCATTER, DOF_SCATTER,

View File

@@ -578,53 +578,51 @@ void dof_slight_focus_gather(sampler2D depth_tx,
out float out_center_coc) out float out_center_coc)
{ {
vec2 frag_coord = vec2(gl_GlobalInvocationID.xy) + 0.5; vec2 frag_coord = vec2(gl_GlobalInvocationID.xy) + 0.5;
float noise_offset = sampling_rng_1D_get(SAMPLING_LENS_U); vec2 noise_offset = sampling_rng_2D_get(SAMPLING_LENS_U);
float noise = no_gather_random ? 0.0 : interlieved_gradient_noise(frag_coord, 3, noise_offset); vec2 noise = no_gather_random ? vec2(0.0) :
vec2(interlieved_gradient_noise(frag_coord, 3, noise_offset.x),
interlieved_gradient_noise(frag_coord, 5, noise_offset.y));
DofGatherData fg_accum = GATHER_DATA_INIT; DofGatherData fg_accum = GATHER_DATA_INIT;
DofGatherData bg_accum = GATHER_DATA_INIT; DofGatherData bg_accum = GATHER_DATA_INIT;
int i_radius = clamp(int(radius), 0, int(dof_layer_threshold)); int i_radius = clamp(int(radius), 0, int(dof_layer_threshold));
const int resolve_ring_density = DOF_SLIGHT_FOCUS_DENSITY;
ivec2 texel = ivec2(gl_GlobalInvocationID.xy); const float sample_count_max = float(DOF_SLIGHT_FOCUS_SAMPLE_MAX);
/* Scale by search area. */
float sample_count = sample_count_max * saturate(sqr(radius) / sqr(dof_layer_threshold));
bool first_ring = true; bool first_ring = true;
for (int ring = i_radius; ring > 0; ring--) { for (float s = 0.0; s < sample_count; s++) {
DofGatherData fg_ring = GATHER_DATA_INIT; vec2 rand2 = fract(hammersley_2d(s, sample_count) + noise);
DofGatherData bg_ring = GATHER_DATA_INIT; vec2 offset = sample_disk(rand2);
float ring_dist = sqrt(rand2.y);
int ring_distance = ring;
int ring_sample_count = resolve_ring_density * ring_distance;
for (int sample_id = 0; sample_id < ring_sample_count; sample_id++) {
int s = sample_id * (4 / resolve_ring_density) +
int(noise * float((4 - resolve_ring_density) * ring_distance));
ivec2 offset = dof_square_ring_sample_offset(ring_distance, s);
float ring_dist = length(vec2(offset));
DofGatherData pair_data[2]; DofGatherData pair_data[2];
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
ivec2 sample_offset = ((i == 0) ? offset : -offset); vec2 sample_offset = ((i == 0) ? offset : -offset);
ivec2 sample_texel = texel + sample_offset;
/* OPTI: could precompute the factor. */ /* OPTI: could precompute the factor. */
vec2 sample_uv = (vec2(sample_texel) + 0.5) / vec2(textureSize(depth_tx, 0)); vec2 sample_uv = (frag_coord + sample_offset) / vec2(textureSize(depth_tx, 0));
float depth = textureLod(depth_tx, sample_uv, 0.0).r; float depth = textureLod(depth_tx, sample_uv, 0.0).r;
pair_data[i].coc = dof_coc_from_depth(dof_buf, sample_uv, depth); pair_data[i].coc = dof_coc_from_depth(dof_buf, sample_uv, depth);
pair_data[i].color = safe_color(textureLod(color_tx, sample_uv, 0.0)); pair_data[i].color = safe_color(textureLod(color_tx, sample_uv, 0.0));
pair_data[i].dist = ring_dist; pair_data[i].dist = ring_dist;
if (DOF_BOKEH_TEXTURE) { if (DOF_BOKEH_TEXTURE) {
/* Contains subpixel distance to bokeh shape. */ /* Contains subpixel distance to bokeh shape. */
sample_offset += dof_max_slight_focus_radius; ivec2 lut_texel = ivec2(round(sample_offset)) + dof_max_slight_focus_radius;
pair_data[i].dist = texelFetch(bkh_lut_tx, sample_offset, 0).r; pair_data[i].dist = texelFetch(bkh_lut_tx, lut_texel, 0).r;
} }
pair_data[i].coc = clamp(pair_data[i].coc, -dof_buf.coc_abs_max, dof_buf.coc_abs_max); pair_data[i].coc = clamp(pair_data[i].coc, -dof_buf.coc_abs_max, dof_buf.coc_abs_max);
} }
float bordering_radius = ring_dist + 0.5; float bordering_radius = ring_dist + 0.5;
const float isect_mul = 1.0; const float isect_mul = 1.0;
DofGatherData bg_ring = GATHER_DATA_INIT;
dof_gather_accumulate_sample_pair( dof_gather_accumulate_sample_pair(
pair_data, bordering_radius, isect_mul, first_ring, false, false, bg_ring, bg_accum); pair_data, bordering_radius, isect_mul, first_ring, false, false, bg_ring, bg_accum);
/* Treat each sample as a ring. */
dof_gather_accumulate_sample_ring(bg_ring, 2, first_ring, false, false, bg_accum);
if (DOF_BOKEH_TEXTURE) { if (DOF_BOKEH_TEXTURE) {
/* Swap distances in order to flip bokeh shape for foreground. */ /* Swap distances in order to flip bokeh shape for foreground. */
@@ -632,14 +630,11 @@ void dof_slight_focus_gather(sampler2D depth_tx,
pair_data[0].dist = pair_data[1].dist; pair_data[0].dist = pair_data[1].dist;
pair_data[1].dist = tmp; pair_data[1].dist = tmp;
} }
DofGatherData fg_ring = GATHER_DATA_INIT;
dof_gather_accumulate_sample_pair( dof_gather_accumulate_sample_pair(
pair_data, bordering_radius, isect_mul, first_ring, false, true, fg_ring, fg_accum); pair_data, bordering_radius, isect_mul, first_ring, false, true, fg_ring, fg_accum);
} /* Treat each sample as a ring. */
dof_gather_accumulate_sample_ring(fg_ring, 2, first_ring, false, true, fg_accum);
dof_gather_accumulate_sample_ring(
bg_ring, ring_sample_count * 2, first_ring, false, false, bg_accum);
dof_gather_accumulate_sample_ring(
fg_ring, ring_sample_count * 2, first_ring, false, true, fg_accum);
first_ring = false; first_ring = false;
} }
@@ -666,7 +661,7 @@ void dof_slight_focus_gather(sampler2D depth_tx,
float bg_weight, fg_weight; float bg_weight, fg_weight;
vec2 unused_occlusion; vec2 unused_occlusion;
int total_sample_count = dof_gather_total_sample_count(i_radius + 1, resolve_ring_density); int total_sample_count = int(sample_count) * 2 + 1;
dof_gather_accumulate_resolve(total_sample_count, bg_accum, bg_col, bg_weight, unused_occlusion); dof_gather_accumulate_resolve(total_sample_count, bg_accum, bg_col, bg_weight, unused_occlusion);
dof_gather_accumulate_resolve(total_sample_count, fg_accum, fg_col, fg_weight, unused_occlusion); dof_gather_accumulate_resolve(total_sample_count, fg_accum, fg_col, fg_weight, unused_occlusion);

View File

@@ -130,24 +130,18 @@ GPU_SHADER_CREATE_INFO(eevee_depth_of_field_lut)
GPU_SHADER_CREATE_INFO(eevee_depth_of_field_background).define("DOF_FOREGROUND_PASS", "false"); GPU_SHADER_CREATE_INFO(eevee_depth_of_field_background).define("DOF_FOREGROUND_PASS", "false");
GPU_SHADER_CREATE_INFO(eevee_depth_of_field_foreground).define("DOF_FOREGROUND_PASS", "true"); GPU_SHADER_CREATE_INFO(eevee_depth_of_field_foreground).define("DOF_FOREGROUND_PASS", "true");
GPU_SHADER_CREATE_INFO(eevee_depth_of_field_hq).define("DOF_SLIGHT_FOCUS_DENSITY", "4");
GPU_SHADER_CREATE_INFO(eevee_depth_of_field_lq).define("DOF_SLIGHT_FOCUS_DENSITY", "2");
#define EEVEE_DOF_FINAL_VARIATION(name, ...) \ #define EEVEE_DOF_FINAL_VARIATION(name, ...) \
GPU_SHADER_CREATE_INFO(name).additional_info(__VA_ARGS__).do_static_compilation(true); GPU_SHADER_CREATE_INFO(name).additional_info(__VA_ARGS__).do_static_compilation(true);
#define EEVEE_DOF_LUT_VARIATIONS(prefix, ...) \ #define EEVEE_DOF_LUT_VARIATIONS(prefix, ...) \
EEVEE_DOF_FINAL_VARIATION(prefix##_lut, "eevee_depth_of_field_lut", __VA_ARGS__) \ EEVEE_DOF_FINAL_VARIATION(prefix##_lut, "eevee_depth_of_field_lut", __VA_ARGS__) \
EEVEE_DOF_FINAL_VARIATION(prefix, "eevee_depth_of_field_no_lut", __VA_ARGS__) EEVEE_DOF_FINAL_VARIATION(prefix##_no_lut, "eevee_depth_of_field_no_lut", __VA_ARGS__)
#define EEVEE_DOF_GROUND_VARIATIONS(name, ...) \ #define EEVEE_DOF_GROUND_VARIATIONS(name, ...) \
EEVEE_DOF_LUT_VARIATIONS(name##_background, "eevee_depth_of_field_background", __VA_ARGS__) \ EEVEE_DOF_LUT_VARIATIONS(name##_background, "eevee_depth_of_field_background", __VA_ARGS__) \
EEVEE_DOF_LUT_VARIATIONS(name##_foreground, "eevee_depth_of_field_foreground", __VA_ARGS__) EEVEE_DOF_LUT_VARIATIONS(name##_foreground, "eevee_depth_of_field_foreground", __VA_ARGS__)
#define EEVEE_DOF_HQ_VARIATIONS(name, ...) \
EEVEE_DOF_LUT_VARIATIONS(name##_hq, "eevee_depth_of_field_hq", __VA_ARGS__) \
EEVEE_DOF_LUT_VARIATIONS(name##_lq, "eevee_depth_of_field_lq", __VA_ARGS__)
/** \} */ /** \} */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
@@ -247,6 +241,6 @@ GPU_SHADER_CREATE_INFO(eevee_depth_of_field_resolve)
.image(2, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_color_img") .image(2, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_color_img")
.compute_source("eevee_depth_of_field_resolve_comp.glsl"); .compute_source("eevee_depth_of_field_resolve_comp.glsl");
EEVEE_DOF_HQ_VARIATIONS(eevee_depth_of_field_resolve, "eevee_depth_of_field_resolve") EEVEE_DOF_LUT_VARIATIONS(eevee_depth_of_field_resolve, "eevee_depth_of_field_resolve")
/** \} */ /** \} */