Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2021-02-13 00:35:18 +0300
committerClément Foucault <foucault.clem@gmail.com>2021-02-13 00:35:52 +0300
commit000a340afa67a12a38c103e19f7d52ed42c4492e (patch)
treed59ea49aedfba450d7de20240004399e1ee30dc8 /source/blender/draw/engines/eevee/eevee_private.h
parentdd2ff266acf999dbb3a37b70162f5ca7c029426a (diff)
EEVEE: Depth of field: New implementation
This is a complete refactor over the old system. The goal was to increase quality first and then have something more flexible and optimised. |{F9603145} | {F9603142}|{F9603147}| This fixes issues we had with the old system which were: - Too much overdraw (low performance). - Not enough precision in render targets (hugly color banding/drifting). - Poor resolution near in-focus regions. - Wrong support of orthographic views. - Missing alpha support in viewport. - Missing bokeh shape inversion on foreground field. - Issues on some GPUs. (see T72489) (But I'm sure this one will have other issues as well heh...) - Fix T81092 I chose Unreal's Diaphragm DOF as a reference / goal implementation. It is well described in the presentation "A Life of a Bokeh" by Guillaume Abadie. You can check about it here https://epicgames.ent.box.com/s/s86j70iamxvsuu6j35pilypficznec04 Along side the main implementation we provide a way to increase the quality by jittering the camera position for each sample (the ones specified under the Sampling tab). The jittering is dividing the actual post processing dof radius so that it fills the undersampling. The user can still add more overblur to have a noiseless image, but reducing bokeh shape sharpness. Effect of overblur (left without, right with): | {F9603122} | {F9603123}| The actual implementation differs a bit: - Foreground gather implementation uses the same "ring binning" accumulator as background but uses a custom occlusion method. This gives the problem of inflating the foreground elements when they are over background or in-focus regions. This is was a hard decision but this was preferable to the other method that was giving poor opacity masks for foreground and had other more noticeable issues. Do note it is possible to improve this part in the future if a better alternative is found. - Use occlusion texture for foreground. Presentation says it wasn't really needed for them. - The TAA stabilisation pass is replace by a simple neighborhood clamping at the reduce copy stage for simplicity. - We don't do a brute-force in-focus separate gather pass. Instead we just do the brute force pass during resolve. Using the separate pass could be a future optimization if needed but might give less precise results. - We don't use compute shaders at all so shader branching might not be optimal. But performance is still way better than our previous implementation. - We mainly rely on density change to fix all undersampling issues even for foreground (which is something the reference implementation is not doing strangely). Remaining issues (not considered blocking for me): - Slight defocus stability: Due to slight defocus bruteforce gather using the bare scene color, highlights are dilated and make convergence quite slow or imposible when using jittered DOF (or gives ) - ~~Slight defocus inflating: There seems to be a 1px inflation discontinuity of the slight focus convolution compared to the half resolution. This is not really noticeable if using jittered camera.~~ Fixed - Foreground occlusion approximation is a bit glitchy and gives incorrect result if the a defocus foreground element overlaps a farther foreground element. Note that this is easily mitigated using the jittered camera position. |{F9603114}|{F9603115}|{F9603116}| - Foreground is inflating, not revealing background. However this avoids some other bugs too as discussed previously. Also mitigated with jittered camera position. |{F9603130}|{F9603129}| - Sensor vertical fit is still broken (does not match cycles). - Scattred bokeh shapes can be a bit strange at polygon vertices. This is due to the distance field stored in the Bokeh LUT which is not rounded at the edges. This is barely noticeable if the shape does not rotate. - ~~Sampling pattern of the jittered camera position is suboptimal. Could try something like hammersley or poisson disc distribution.~~Used hexaweb sampling pattern which is not random but has better stability and overall coverage. - Very large bokeh (> 300 px) can exhibit undersampling artifact in gather pass and quite a bit of bleeding. But at this size it is preferable to use jittered camera position. Codewise the changes are pretty much self contained and each pass are well documented. However the whole pipeline is quite complex to understand from bird's-eye view. Notes: - There is the possibility of using arbitrary bokeh texture with this implementation. However implementation is a bit involved. - Gathering max sample count is hardcoded to avoid to deal with shader variations. The actual max sample count is already quite high but samples are not evenly distributed due to the ring binning method. - While this implementation does not need 32bit/channel textures to render correctly it does use many other textures so actual VRAM usage is higher than previous method for viewport but less for render. Textures are reused to avoid many allocations. - Bokeh LUT computation is fast and done for each redraw because it can be animated. Also the texture can be shared with other viewport with different camera settings.
Diffstat (limited to 'source/blender/draw/engines/eevee/eevee_private.h')
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h132
1 files changed, 114 insertions, 18 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index e48f5f9dd32..9761264f03e 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -55,6 +55,9 @@ extern struct DrawEngineType draw_engine_eevee_type;
#define MAX_BLOOM_STEP 16
#define MAX_AOVS 64
+/* Special value chosen to not be altered by depth of field sample count. */
+#define TAA_MAX_SAMPLE 10000926
+
// #define DEBUG_SHADOW_DISTRIBUTION
/* Only define one of these. */
@@ -206,6 +209,28 @@ typedef enum EEVEE_SSRShaderOptions {
SSR_MAX_SHADER = (1 << 4),
} EEVEE_SSRShaderOptions;
+/* DOF Gather pass shader variations */
+typedef enum EEVEE_DofGatherPass {
+ DOF_GATHER_FOREGROUND = 0,
+ DOF_GATHER_BACKGROUND = 1,
+ DOF_GATHER_HOLEFILL = 2,
+
+ DOF_GATHER_MAX_PASS,
+} EEVEE_DofGatherPass;
+
+#define DOF_TILE_DIVISOR 16
+#define DOF_BOKEH_LUT_SIZE 32
+#define DOF_GATHER_RING_COUNT 5
+#define DOF_DILATE_RING_COUNT 3
+#define DOF_FAST_GATHER_COC_ERROR 0.05
+
+#define DOF_SHADER_DEFINES \
+ "#define DOF_TILE_DIVISOR " STRINGIFY(DOF_TILE_DIVISOR) "\n" \
+ "#define DOF_BOKEH_LUT_SIZE " STRINGIFY(DOF_BOKEH_LUT_SIZE) "\n" \
+ "#define DOF_GATHER_RING_COUNT " STRINGIFY(DOF_GATHER_RING_COUNT) "\n" \
+ "#define DOF_DILATE_RING_COUNT " STRINGIFY(DOF_DILATE_RING_COUNT) "\n" \
+ "#define DOF_FAST_GATHER_COC_ERROR " STRINGIFY(DOF_FAST_GATHER_COC_ERROR) "\n"
+
/* ************ PROBE UBO ************* */
/* They are the same struct as their Cache siblings.
@@ -258,8 +283,20 @@ typedef struct EEVEE_PassList {
struct DRWPass *bloom_upsample;
struct DRWPass *bloom_resolve;
struct DRWPass *bloom_accum_ps;
- struct DRWPass *dof_down;
- struct DRWPass *dof_scatter;
+ struct DRWPass *dof_setup;
+ struct DRWPass *dof_flatten_tiles;
+ struct DRWPass *dof_dilate_tiles_minmax;
+ struct DRWPass *dof_dilate_tiles_minabs;
+ struct DRWPass *dof_reduce_copy;
+ struct DRWPass *dof_downsample;
+ struct DRWPass *dof_reduce;
+ struct DRWPass *dof_bokeh;
+ struct DRWPass *dof_gather_fg;
+ struct DRWPass *dof_gather_fg_holefill;
+ struct DRWPass *dof_gather_bg;
+ struct DRWPass *dof_scatter_fg;
+ struct DRWPass *dof_scatter_bg;
+ struct DRWPass *dof_filter;
struct DRWPass *dof_resolve;
struct DRWPass *volumetric_world_ps;
struct DRWPass *volumetric_objects_ps;
@@ -339,8 +376,20 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *sss_clear_fb;
struct GPUFrameBuffer *sss_translucency_fb;
struct GPUFrameBuffer *sss_accum_fb;
- struct GPUFrameBuffer *dof_down_fb;
- struct GPUFrameBuffer *dof_scatter_fb;
+ struct GPUFrameBuffer *dof_setup_fb;
+ struct GPUFrameBuffer *dof_flatten_tiles_fb;
+ struct GPUFrameBuffer *dof_dilate_tiles_fb;
+ struct GPUFrameBuffer *dof_downsample_fb;
+ struct GPUFrameBuffer *dof_reduce_fb;
+ struct GPUFrameBuffer *dof_reduce_copy_fb;
+ struct GPUFrameBuffer *dof_bokeh_fb;
+ struct GPUFrameBuffer *dof_gather_fg_fb;
+ struct GPUFrameBuffer *dof_filter_fg_fb;
+ struct GPUFrameBuffer *dof_gather_fg_holefill_fb;
+ struct GPUFrameBuffer *dof_gather_bg_fb;
+ struct GPUFrameBuffer *dof_filter_bg_fb;
+ struct GPUFrameBuffer *dof_scatter_fg_fb;
+ struct GPUFrameBuffer *dof_scatter_bg_fb;
struct GPUFrameBuffer *volumetric_fb;
struct GPUFrameBuffer *volumetric_scat_fb;
struct GPUFrameBuffer *volumetric_integ_fb;
@@ -390,6 +439,9 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *cryptomatte;
struct GPUTexture *refract_color;
struct GPUTexture *taa_history;
+ /* Could not be pool texture because of mipmapping. */
+ struct GPUTexture *dof_reduced_color;
+ struct GPUTexture *dof_reduced_coc;
struct GPUTexture *volume_prop_scattering;
struct GPUTexture *volume_prop_extinction;
@@ -727,16 +779,45 @@ typedef struct EEVEE_EffectsInfo {
struct GPUTexture *velocity_tiles_x_tx;
struct GPUTexture *velocity_tiles_tx;
/* Depth Of Field */
- float dof_near_far[2];
- float dof_params[2];
- float dof_bokeh[4];
- float dof_bokeh_sides[4];
- int dof_target_size[2];
- struct GPUTexture *dof_down_near; /* Textures from pool */
- struct GPUTexture *dof_down_far;
- struct GPUTexture *dof_coc;
- struct GPUTexture *dof_blur;
- struct GPUTexture *dof_blur_alpha;
+ float dof_jitter_radius;
+ float dof_jitter_blades;
+ float dof_jitter_focus;
+ int dof_jitter_ring_count;
+ float dof_coc_params[2], dof_coc_near_dist, dof_coc_far_dist;
+ float dof_bokeh_blades, dof_bokeh_rotation, dof_bokeh_aniso[2], dof_bokeh_max_size;
+ float dof_bokeh_aniso_inv[2];
+ float dof_scatter_color_threshold;
+ float dof_scatter_coc_threshold;
+ float dof_scatter_neighbor_max_color;
+ float dof_fx_max_coc;
+ float dof_denoise_factor;
+ int dof_dilate_slight_focus;
+ int dof_dilate_ring_count;
+ int dof_dilate_ring_width_multiplier;
+ int dof_reduce_steps;
+ bool dof_hq_slight_focus;
+ eGPUTextureFormat dof_color_format;
+ struct GPUTexture *dof_bg_color_tx; /* All textures from pool... */
+ struct GPUTexture *dof_bg_occlusion_tx;
+ struct GPUTexture *dof_bg_weight_tx;
+ struct GPUTexture *dof_bokeh_gather_lut_tx;
+ struct GPUTexture *dof_bokeh_scatter_lut_tx;
+ struct GPUTexture *dof_bokeh_resolve_lut_tx;
+ struct GPUTexture *dof_coc_dilated_tiles_bg_tx;
+ struct GPUTexture *dof_coc_dilated_tiles_fg_tx;
+ struct GPUTexture *dof_coc_tiles_bg_tx;
+ struct GPUTexture *dof_coc_tiles_fg_tx;
+ struct GPUTexture *dof_downsample_tx;
+ struct GPUTexture *dof_fg_color_tx;
+ struct GPUTexture *dof_fg_occlusion_tx;
+ struct GPUTexture *dof_fg_weight_tx;
+ struct GPUTexture *dof_fg_holefill_color_tx;
+ struct GPUTexture *dof_fg_holefill_weight_tx;
+ struct GPUTexture *dof_half_res_coc_tx;
+ struct GPUTexture *dof_half_res_color_tx;
+ struct GPUTexture *dof_scatter_src_tx;
+ struct GPUTexture *dof_reduce_input_coc_tx; /* Just references to actual textures. */
+ struct GPUTexture *dof_reduce_input_color_tx;
/* Alpha Checker */
float color_checker_dark[4];
float color_checker_light[4];
@@ -1002,7 +1083,8 @@ typedef struct EEVEE_PrivateData {
/** For rendering planar reflections. */
struct DRWView *planar_views[MAX_PLANAR];
- int render_tot_samples;
+ int render_timesteps;
+ int render_sample_count_per_timestep;
} EEVEE_PrivateData; /* Transient data */
/* eevee_data.c */
@@ -1110,9 +1192,16 @@ struct GPUShader *EEVEE_shaders_bloom_blit_get(bool high_quality);
struct GPUShader *EEVEE_shaders_bloom_downsample_get(bool high_quality);
struct GPUShader *EEVEE_shaders_bloom_upsample_get(bool high_quality);
struct GPUShader *EEVEE_shaders_bloom_resolve_get(bool high_quality);
-struct GPUShader *EEVEE_shaders_depth_of_field_downsample_get(bool use_alpha);
-struct GPUShader *EEVEE_shaders_depth_of_field_scatter_get(bool use_alpha);
-struct GPUShader *EEVEE_shaders_depth_of_field_resolve_get(bool use_alpha);
+struct GPUShader *EEVEE_shaders_depth_of_field_bokeh_get(void);
+struct GPUShader *EEVEE_shaders_depth_of_field_setup_get(void);
+struct GPUShader *EEVEE_shaders_depth_of_field_flatten_tiles_get(void);
+struct GPUShader *EEVEE_shaders_depth_of_field_dilate_tiles_get(bool pass);
+struct GPUShader *EEVEE_shaders_depth_of_field_downsample_get(void);
+struct GPUShader *EEVEE_shaders_depth_of_field_reduce_get(bool is_copy_pass);
+struct GPUShader *EEVEE_shaders_depth_of_field_gather_get(EEVEE_DofGatherPass pass, bool bokeh_tx);
+struct GPUShader *EEVEE_shaders_depth_of_field_filter_get(void);
+struct GPUShader *EEVEE_shaders_depth_of_field_scatter_get(bool is_foreground, bool bokeh_tx);
+struct GPUShader *EEVEE_shaders_depth_of_field_resolve_get(bool use_bokeh_tx, bool use_hq_gather);
struct GPUShader *EEVEE_shaders_effect_downsample_sh_get(void);
struct GPUShader *EEVEE_shaders_effect_downsample_cube_sh_get(void);
struct GPUShader *EEVEE_shaders_effect_minz_downlevel_sh_get(void);
@@ -1232,6 +1321,12 @@ void EEVEE_lightprobes_planar_data_from_object(Object *ob,
int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera);
void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_depth_of_field_draw(EEVEE_Data *vedata);
+bool EEVEE_depth_of_field_jitter_get(EEVEE_EffectsInfo *effects,
+ float r_jitter[2],
+ float *r_focus_distance);
+int EEVEE_depth_of_field_sample_count_get(EEVEE_EffectsInfo *effects,
+ int sample_count,
+ int *r_ring_count);
/* eevee_bloom.c */
int EEVEE_bloom_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
@@ -1345,6 +1440,7 @@ int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov);
/* eevee_temporal_sampling.c */
void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata);
void EEVEE_temporal_sampling_create_view(EEVEE_Data *vedata);
+int EEVEE_temporal_sampling_sample_count_get(const Scene *scene, const EEVEE_StorageList *stl);
int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_temporal_sampling_offset_calc(const double ht_point[2],
const float filter_size,