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
path: root/source
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2017-05-09 22:57:13 +0300
committerClément Foucault <foucault.clem@gmail.com>2017-05-10 00:55:19 +0300
commit9075f934aae2cccad18ba96130650965875f2fa1 (patch)
tree061d478698a2951f46a2ce0f1cae5035a8d3cc05 /source
parent435f5017fafe81b90f59cb41be391f85b770e604 (diff)
Eevee: Initial Depth Of Field commit.
Diffstat (limited to 'source')
-rw-r--r--source/blender/draw/CMakeLists.txt3
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c231
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h19
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl222
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_geom.glsl55
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl92
6 files changed, 587 insertions, 35 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 0b229ecee8d..343f08343fd 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -115,6 +115,9 @@ data_to_c_simple(engines/eevee/shaders/background_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lit_surface_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lit_surface_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_bloom_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_dof_vert.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_dof_geom.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_dof_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_motion_blur_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/probe_filter_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/probe_sh_frag.glsl SRC)
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index 2279f0a6b44..586580e3a93 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -29,8 +29,10 @@
#include "DRW_render.h"
#include "DNA_anim_types.h"
+#include "DNA_camera_types.h"
#include "DNA_view3d_types.h"
+#include "BKE_camera.h"
#include "BKE_object.h"
#include "BKE_animsys.h"
@@ -44,8 +46,10 @@ typedef struct EEVEE_ProbeData {
/* TODO Option */
#define ENABLE_EFFECT_MOTION_BLUR 1
#define ENABLE_EFFECT_BLOOM 1
+#define ENABLE_EFFECT_DOF 1
static struct {
+ /* Motion Blur */
struct GPUShader *motion_blur_sh;
/* Bloom */
@@ -54,11 +58,19 @@ static struct {
struct GPUShader *bloom_upsample_sh[2];
struct GPUShader *bloom_resolve_sh[2];
+ /* Depth Of Field */
+ struct GPUShader *dof_downsample_sh;
+ struct GPUShader *dof_scatter_sh;
+ struct GPUShader *dof_resolve_sh;
+
struct GPUShader *tonemap_sh;
} e_data = {NULL}; /* Engine data */
extern char datatoc_effect_motion_blur_frag_glsl[];
extern char datatoc_effect_bloom_frag_glsl[];
+extern char datatoc_effect_dof_vert_glsl[];
+extern char datatoc_effect_dof_geom_glsl[];
+extern char datatoc_effect_dof_frag_glsl[];
extern char datatoc_tonemap_frag_glsl[];
void EEVEE_effects_init(EEVEE_Data *vedata)
@@ -66,19 +78,28 @@ void EEVEE_effects_init(EEVEE_Data *vedata)
EEVEE_StorageList *stl = vedata->stl;
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_TextureList *txl = vedata->txl;
+ EEVEE_EffectsInfo *effects;
- /* Ping Pong buffer */
- DRWFboTexture tex = {&txl->color_post, DRW_BUF_RGBA_16, DRW_TEX_FILTER};
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ View3D *v3d = draw_ctx->v3d;
+ RegionView3D *rv3d = draw_ctx->rv3d;
const float *viewport_size = DRW_viewport_size_get();
- DRW_framebuffer_init(&fbl->effect_fb,
- (int)viewport_size[0], (int)viewport_size[1],
- &tex, 1);
if (!e_data.motion_blur_sh) {
e_data.motion_blur_sh = DRW_shader_create_fullscreen(datatoc_effect_motion_blur_frag_glsl, NULL);
}
+ if (!e_data.dof_downsample_sh) {
+ e_data.dof_downsample_sh = DRW_shader_create(datatoc_effect_dof_vert_glsl, NULL,
+ datatoc_effect_dof_frag_glsl, "#define STEP_DOWNSAMPLE\n");
+ e_data.dof_scatter_sh = DRW_shader_create(datatoc_effect_dof_vert_glsl, NULL,
+ datatoc_effect_dof_frag_glsl, "#define STEP_SCATTER\n");
+ e_data.dof_resolve_sh = DRW_shader_create(datatoc_effect_dof_vert_glsl, NULL,
+ datatoc_effect_dof_frag_glsl, "#define STEP_RESOLVE\n");
+ }
+
if (!e_data.bloom_blit_sh[0]) {
e_data.bloom_blit_sh[0] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_BLIT\n");
e_data.bloom_blit_sh[1] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_BLIT\n"
@@ -103,18 +124,15 @@ void EEVEE_effects_init(EEVEE_Data *vedata)
if (!stl->effects) {
stl->effects = MEM_callocN(sizeof(EEVEE_EffectsInfo), "EEVEE_EffectsInfo");
- stl->effects->enabled_effects = 0;
}
+ effects = stl->effects;
+
+ effects->enabled_effects = 0;
+
#if ENABLE_EFFECT_MOTION_BLUR
{
/* Update Motion Blur Matrices */
- EEVEE_EffectsInfo *effects = stl->effects;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- View3D *v3d = draw_ctx->v3d;
- RegionView3D *rv3d = draw_ctx->rv3d;
-
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
float ctime = BKE_scene_frame_get(scene);
float past_obmat[4][4], future_obmat[4][4], winmat[4][4];
@@ -157,9 +175,9 @@ void EEVEE_effects_init(EEVEE_Data *vedata)
}
#endif /* ENABLE_EFFECT_MOTION_BLUR */
+#if ENABLE_EFFECT_BLOOM
{
/* Bloom */
- EEVEE_EffectsInfo *effects = stl->effects;
int blitsize[2], texsize[2];
/* Blit Buffer */
@@ -229,6 +247,76 @@ void EEVEE_effects_init(EEVEE_Data *vedata)
effects->enabled_effects |= EFFECT_BLOOM;
}
+#endif /* ENABLE_EFFECT_BLOOM */
+
+#if ENABLE_EFFECT_DOF
+ {
+ /* Depth Of Field */
+ if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
+ Camera *cam = (Camera *)v3d->camera->data;
+
+ /* Retreive Near and Far distance */
+ effects->dof_near_far[0] = -cam->clipsta;
+ effects->dof_near_far[1] = -cam->clipend;
+
+ int buffer_size[2] = {(int)viewport_size[0] / 2, (int)viewport_size[1] / 2};
+
+ /* Setup buffers */
+ DRWFboTexture tex_down[3] = {{&txl->dof_down_near, DRW_BUF_RGBA_16, 0},
+ {&txl->dof_down_far, DRW_BUF_RGBA_16, 0},
+ {&txl->dof_coc, DRW_BUF_RG_16, 0}};
+ DRW_framebuffer_init(&fbl->dof_down_fb, buffer_size[0], buffer_size[1], tex_down, 3);
+
+ DRWFboTexture tex_scatter_far = {&txl->dof_far_blur, DRW_BUF_RGBA_16, DRW_TEX_FILTER};
+ DRW_framebuffer_init(&fbl->dof_scatter_far_fb, buffer_size[0], buffer_size[1], &tex_scatter_far, 1);
+
+ DRWFboTexture tex_scatter_near = {&txl->dof_near_blur, DRW_BUF_RGBA_16, DRW_TEX_FILTER};
+ DRW_framebuffer_init(&fbl->dof_scatter_near_fb, buffer_size[0], buffer_size[1], &tex_scatter_near, 1);
+
+ /* Parameters */
+ /* TODO UI Options */
+ float fstop = cam->gpu_dof.fstop;
+ float blades = cam->gpu_dof.num_blades;
+ float rotation = 0.0f;
+ float ratio = 1.0f;
+ float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
+ float focus_dist = BKE_camera_object_dof_distance(v3d->camera);
+ float focal_len = cam->lens;
+
+ UNUSED_VARS(rotation, ratio);
+
+ /* this is factor that converts to the scene scale. focal length and sensor are expressed in mm
+ * unit.scale_length is how many meters per blender unit we have. We want to convert to blender units though
+ * because the shader reads coordinates in world space, which is in blender units.
+ * Note however that focus_distance is already in blender units and shall not be scaled here (see T48157). */
+ float scale = (scene->unit.system) ? scene->unit.scale_length : 1.0f;
+ float scale_camera = 0.001f / scale;
+ /* we want radius here for the aperture number */
+ float aperture = 0.5f * scale_camera * focal_len / fstop;
+ float focal_len_scaled = scale_camera * focal_len;
+ float sensor_scaled = scale_camera * sensor;
+
+ effects->dof_params[0] = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled));
+ effects->dof_params[1] = -focus_dist;
+ effects->dof_params[2] = viewport_size[0] / sensor_scaled;
+ effects->dof_bokeh[0] = blades;
+ effects->dof_bokeh[1] = rotation;
+ effects->dof_bokeh[2] = ratio;
+
+ effects->enabled_effects |= EFFECT_DOF;
+ }
+ }
+#endif /* ENABLE_EFFECT_DOF */
+
+ /* Only allocate if at least one effect is activated */
+ if (effects->enabled_effects != 0) {
+ /* Ping Pong buffer */
+ DRWFboTexture tex = {&txl->color_post, DRW_BUF_RGBA_16, DRW_TEX_FILTER};
+
+ DRW_framebuffer_init(&fbl->effect_fb,
+ (int)viewport_size[0], (int)viewport_size[1],
+ &tex, 1);
+ }
}
static DRWShadingGroup *eevee_create_bloom_pass(const char *name, EEVEE_EffectsInfo *effects, struct GPUShader *sh, DRWPass **pass, bool upsample)
@@ -266,7 +354,7 @@ void EEVEE_effects_cache_init(EEVEE_Data *vedata)
DRW_shgroup_uniform_float(grp, "blurAmount", &effects->blur_amount, 1);
DRW_shgroup_uniform_mat4(grp, "currInvViewProjMatrix", (float *)effects->current_ndc_to_world);
DRW_shgroup_uniform_mat4(grp, "pastViewProjMatrix", (float *)effects->past_world_to_ndc);
- DRW_shgroup_uniform_buffer(grp, "colorBuffer", &txl->color, 0);
+ DRW_shgroup_uniform_buffer(grp, "colorBuffer", &effects->source_buffer, 0);
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth, 1);
DRW_shgroup_call_add(grp, quad, NULL);
}
@@ -313,6 +401,52 @@ void EEVEE_effects_cache_init(EEVEE_Data *vedata)
}
{
+ /** Depth of Field algorithm
+ *
+ * Overview :
+ * - Downsample the color buffer into 2 buffers weighted with
+ * CoC values. Also output CoC into a texture.
+ * - Shoot quads for every pixel and expand it depending on the CoC.
+ * Do one pass for near Dof and one pass for far Dof.
+ * - Finally composite the 2 blurred buffers with the original render.
+ **/
+ DRWShadingGroup *grp;
+
+ psl->dof_down = DRW_pass_create("DoF Downsample", DRW_STATE_WRITE_COLOR);
+
+ grp = DRW_shgroup_create(e_data.dof_downsample_sh, psl->dof_down);
+ DRW_shgroup_uniform_buffer(grp, "colorBuffer", &effects->source_buffer, 0);
+ DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth, 1);
+ DRW_shgroup_uniform_vec2(grp, "nearFar", effects->dof_near_far, 1);
+ DRW_shgroup_uniform_vec3(grp, "dofParams", effects->dof_params, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+
+ psl->dof_scatter = DRW_pass_create("DoF Scatter", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE);
+
+ /* This create an empty batch of N triangles to be positioned
+ * by the vertex shader 0.4ms against 6ms with instancing */
+ const float *viewport_size = DRW_viewport_size_get();
+ const int sprite_ct = ((int)viewport_size[0]/2) * ((int)viewport_size[1]/2); /* brackets matters */
+ grp = DRW_shgroup_empty_tri_batch_create(e_data.dof_scatter_sh, psl->dof_scatter, sprite_ct);
+
+ DRW_shgroup_uniform_buffer(grp, "colorBuffer", &effects->unf_source_buffer, 0);
+ DRW_shgroup_uniform_buffer(grp, "cocBuffer", &txl->dof_coc, 1);
+ DRW_shgroup_uniform_vec2(grp, "layerSelection", effects->dof_layer_select, 1);
+ DRW_shgroup_uniform_vec3(grp, "bokehParams", effects->dof_bokeh, 1);
+
+ psl->dof_resolve = DRW_pass_create("DoF Resolve", DRW_STATE_WRITE_COLOR);
+
+ grp = DRW_shgroup_create(e_data.dof_resolve_sh, psl->dof_resolve);
+ DRW_shgroup_uniform_buffer(grp, "colorBuffer", &effects->source_buffer, 0);
+ DRW_shgroup_uniform_buffer(grp, "nearBuffer", &txl->dof_near_blur, 1);
+ DRW_shgroup_uniform_buffer(grp, "farBuffer", &txl->dof_far_blur, 2);
+ DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth, 3);
+ DRW_shgroup_uniform_vec2(grp, "nearFar", effects->dof_near_far, 1);
+ DRW_shgroup_uniform_vec3(grp, "dofParams", effects->dof_params, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+
+ {
/* Final pass : Map HDR color to LDR color.
* Write result to the default color buffer */
psl->tonemap = DRW_pass_create("Tone Mapping", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND);
@@ -323,24 +457,16 @@ void EEVEE_effects_cache_init(EEVEE_Data *vedata)
}
}
-/* Ping pong between 2 buffers */
-static void eevee_effect_framebuffer_bind(EEVEE_Data *vedata)
-{
- EEVEE_TextureList *txl = vedata->txl;
- EEVEE_FramebufferList *fbl = vedata->fbl;
- EEVEE_EffectsInfo *effects = vedata->stl->effects;
-
- DRW_framebuffer_bind(effects->target_buffer);
-
- if (effects->source_buffer == txl->color) {
- effects->source_buffer = txl->color_post;
- effects->target_buffer = fbl->main;
- }
- else {
- effects->source_buffer = txl->color;
- effects->target_buffer = fbl->effect_fb;
- }
-}
+#define SWAP_BUFFERS() { \
+ if (effects->source_buffer == txl->color) { \
+ effects->source_buffer = txl->color_post; \
+ effects->target_buffer = fbl->main; \
+ } \
+ else { \
+ effects->source_buffer = txl->color; \
+ effects->target_buffer = fbl->effect_fb; \
+ } \
+} ((void)0)
void EEVEE_draw_effects(EEVEE_Data *vedata)
{
@@ -358,10 +484,42 @@ void EEVEE_draw_effects(EEVEE_Data *vedata)
effects->source_buffer = txl->color; /* latest updated texture */
effects->target_buffer = fbl->effect_fb; /* next target to render to */
+ /* Detach depth for effects to use it */
+ DRW_framebuffer_texture_detach(dtxl->depth);
+
/* Motion Blur */
if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) {
- eevee_effect_framebuffer_bind(vedata);
+ DRW_framebuffer_bind(effects->target_buffer);
DRW_draw_pass(psl->motion_blur);
+ SWAP_BUFFERS();
+ }
+
+ /* Depth Of Field */
+ if ((effects->enabled_effects & EFFECT_DOF) != 0) {
+ float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ /* Downsample */
+ DRW_framebuffer_bind(fbl->dof_down_fb);
+ DRW_draw_pass(psl->dof_down);
+
+ /* Scatter Far */
+ effects->unf_source_buffer = txl->dof_down_far;
+ copy_v2_fl2(effects->dof_layer_select, 0.0f, 1.0f);
+ DRW_framebuffer_bind(fbl->dof_scatter_far_fb);
+ DRW_framebuffer_clear(true, false, false, clear_col, 0.0f);
+ DRW_draw_pass(psl->dof_scatter);
+
+ /* Scatter Near */
+ effects->unf_source_buffer = txl->dof_down_near;
+ copy_v2_fl2(effects->dof_layer_select, 1.0f, 0.0f);
+ DRW_framebuffer_bind(fbl->dof_scatter_near_fb);
+ DRW_framebuffer_clear(true, false, false, clear_col, 0.0f);
+ DRW_draw_pass(psl->dof_scatter);
+
+ /* Resolve */
+ DRW_framebuffer_bind(effects->target_buffer);
+ DRW_draw_pass(psl->dof_resolve);
+ SWAP_BUFFERS();
}
/* Bloom */
@@ -412,12 +570,12 @@ void EEVEE_draw_effects(EEVEE_Data *vedata)
effects->unf_source_buffer = last;
effects->unf_base_buffer = effects->source_buffer;
- eevee_effect_framebuffer_bind(vedata);
+ DRW_framebuffer_bind(effects->target_buffer);
DRW_draw_pass(psl->bloom_resolve);
+ SWAP_BUFFERS();
}
/* Restore default framebuffer */
- DRW_framebuffer_texture_detach(dtxl->depth);
DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
DRW_framebuffer_bind(dfbl->default_fb);
@@ -430,6 +588,9 @@ void EEVEE_effects_free(void)
{
DRW_SHADER_FREE_SAFE(e_data.tonemap_sh);
DRW_SHADER_FREE_SAFE(e_data.motion_blur_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_scatter_sh);
+ DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh);
DRW_SHADER_FREE_SAFE(e_data.bloom_blit_sh[0]);
DRW_SHADER_FREE_SAFE(e_data.bloom_downsample_sh[0]);
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 0c47af0f889..ef3cc7aa4c0 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -54,6 +54,9 @@ typedef struct EEVEE_PassList {
struct DRWPass *bloom_downsample;
struct DRWPass *bloom_upsample;
struct DRWPass *bloom_resolve;
+ struct DRWPass *dof_down;
+ struct DRWPass *dof_scatter;
+ struct DRWPass *dof_resolve;
struct DRWPass *tonemap;
struct DRWPass *depth_pass;
@@ -77,6 +80,9 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *bloom_blit_fb; /* HDR */
struct GPUFrameBuffer *bloom_down_fb[MAX_BLOOM_STEP]; /* HDR */
struct GPUFrameBuffer *bloom_accum_fb[MAX_BLOOM_STEP-1]; /* HDR */
+ struct GPUFrameBuffer *dof_down_fb;
+ struct GPUFrameBuffer *dof_scatter_far_fb;
+ struct GPUFrameBuffer *dof_scatter_near_fb;
struct GPUFrameBuffer *main; /* HDR */
} EEVEE_FramebufferList;
@@ -93,6 +99,11 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *probe_sh; /* R16_G16_B16 */
/* Effects */
struct GPUTexture *color_post; /* R16_G16_B16 */
+ struct GPUTexture *dof_down_near; /* R16_G16_B16_A16 */
+ struct GPUTexture *dof_down_far; /* R16_G16_B16_A16 */
+ struct GPUTexture *dof_coc; /* R16_G16 */
+ struct GPUTexture *dof_near_blur; /* R16_G16_B16_A16 */
+ struct GPUTexture *dof_far_blur; /* R16_G16_B16_A16 */
struct GPUTexture *bloom_blit; /* R16_G16_B16 */
struct GPUTexture *bloom_downsample[MAX_BLOOM_STEP]; /* R16_G16_B16 */
struct GPUTexture *bloom_upsample[MAX_BLOOM_STEP-1]; /* R16_G16_B16 */
@@ -193,6 +204,13 @@ typedef struct EEVEE_EffectsInfo {
float tmp_mat[4][4];
float blur_amount;
+ /* Depth Of Field */
+ float dof_near_far[2];
+ float dof_params[3];
+ float dof_bokeh[3];
+ float dof_layer_select[2];
+ int dof_target_size[2];
+
/* Bloom */
int bloom_iteration_ct;
float source_texel_size[2];
@@ -213,6 +231,7 @@ typedef struct EEVEE_EffectsInfo {
enum {
EFFECT_MOTION_BLUR = (1 << 0),
EFFECT_BLOOM = (1 << 1),
+ EFFECT_DOF = (1 << 2),
};
/* *********************************** */
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl
new file mode 100644
index 00000000000..0eaee94165d
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl
@@ -0,0 +1,222 @@
+
+uniform mat4 ProjectionMatrix;
+
+uniform sampler2D colorBuffer;
+uniform sampler2D depthBuffer;
+
+uniform vec3 dofParams;
+
+#define dof_aperturesize dofParams.x
+#define dof_distance dofParams.y
+#define dof_invsensorsize dofParams.z
+
+uniform vec3 bokehParams;
+
+#define bokeh_sides bokehParams.x /* Polygon Bokeh shape number of sides */
+#define bokeh_rotation bokehParams.y
+
+uniform vec2 nearFar; /* Near & far view depths values */
+
+/* initial uv coordinate */
+in vec2 uvcoord;
+
+layout(location = 0) out vec4 fragData0;
+layout(location = 1) out vec4 fragData1;
+layout(location = 2) out vec4 fragData2;
+
+#define M_PI 3.1415926535897932384626433832795
+#define M_2PI 6.2831853071795864769252868
+
+/* -------------- Utils ------------- */
+
+/* calculate 4 samples at once */
+float calculate_coc(in float zdepth)
+{
+ float coc = dof_aperturesize * (dof_distance / zdepth - 1.0);
+
+ /* multiply by 1.0 / sensor size to get the normalized size */
+ return coc * dof_invsensorsize;
+}
+
+vec4 calculate_coc(in vec4 zdepth)
+{
+ vec4 coc = dof_aperturesize * (vec4(dof_distance) / zdepth - vec4(1.0));
+
+ /* multiply by 1.0 / sensor size to get the normalized size */
+ return coc * dof_invsensorsize;
+}
+
+float max4(vec4 x)
+{
+ return max(max(x.x, x.y), max(x.z, x.w));
+}
+
+float linear_depth(float z)
+{
+ /* if persp */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ return (nearFar.x * nearFar.y) / (z * (nearFar.x - nearFar.y) + nearFar.y);
+ }
+ else {
+ return (z * 2.0 - 1.0) * nearFar.y;
+ }
+}
+
+vec4 linear_depth(vec4 z)
+{
+ /* if persp */
+ if (ProjectionMatrix[3][3] == 0.0) {
+ return (nearFar.xxxx * nearFar.yyyy) / (z * (nearFar.xxxx - nearFar.yyyy) + nearFar.yyyy);
+ }
+ else {
+ return (z * 2.0 - 1.0) * nearFar.yyyy;
+ }
+}
+
+#define THRESHOLD 0.0
+
+/* ----------- Steps ----------- */
+
+/* Downsample the color buffer to half resolution.
+ * Weight color samples by
+ * Compute maximum CoC for near and far blur. */
+void step_downsample(void)
+{
+ ivec4 uvs = ivec4(gl_FragCoord.xyxy) * 2 + ivec4(0, 0, 1, 1);
+
+ /* custom downsampling */
+ vec4 color1 = texelFetch(colorBuffer, uvs.xy, 0);
+ vec4 color2 = texelFetch(colorBuffer, uvs.zw, 0);
+ vec4 color3 = texelFetch(colorBuffer, uvs.zy, 0);
+ vec4 color4 = texelFetch(colorBuffer, uvs.xw, 0);
+
+ /* Leverage SIMD by combining 4 depth samples into a vec4 */
+ vec4 depth;
+ depth.r = texelFetch(depthBuffer, uvs.xy, 0).r;
+ depth.g = texelFetch(depthBuffer, uvs.zw, 0).r;
+ depth.b = texelFetch(depthBuffer, uvs.zy, 0).r;
+ depth.a = texelFetch(depthBuffer, uvs.xw, 0).r;
+
+ vec4 zdepth = linear_depth(depth);
+
+ /* Compute signed CoC for each depth samples */
+ vec4 coc_near = calculate_coc(zdepth);
+ vec4 coc_far = -coc_near;
+
+ /* now we need to write the near-far fields premultiplied by the coc */
+ vec4 near_weights = step(THRESHOLD, coc_near);
+ vec4 far_weights = step(THRESHOLD, coc_far);
+
+ /* now write output to weighted buffers. */
+ fragData0 = color1 * near_weights.x +
+ color2 * near_weights.y +
+ color3 * near_weights.z +
+ color4 * near_weights.w;
+
+ fragData1 = color1 * far_weights.x +
+ color2 * far_weights.y +
+ color3 * far_weights.z +
+ color4 * far_weights.w;
+
+ float norm_near = dot(near_weights, near_weights);
+ float norm_far = dot(far_weights, far_weights);
+
+ if (norm_near > 0.0) {
+ fragData0 /= norm_near;
+ }
+
+ if (norm_far > 0.0) {
+ fragData1 /= norm_far;
+ }
+
+ float max_near_coc = max(max4(coc_near), 0.0);
+ float max_far_coc = max(max4(coc_far), 0.0);
+
+ fragData2 = vec4(max_near_coc, max_far_coc, 0.0, 1.0);
+}
+
+/* coordinate used for calculating radius et al set in geometry shader */
+in vec2 particlecoord;
+flat in vec4 color;
+
+/* accumulate color in the near/far blur buffers */
+void step_scatter(void)
+{
+ /* Early out */
+ float dist_sqrd = dot(particlecoord, particlecoord);
+
+ /* Circle Dof */
+ if (dist_sqrd > 1.0) {
+ discard;
+ }
+
+ /* Regular Polygon Dof */
+ if (bokeh_sides > 0.0) {
+ /* Circle parametrization */
+ float theta = atan(particlecoord.y, particlecoord.x) + bokeh_rotation;
+ float r;
+
+ r = cos(M_PI / bokeh_sides) /
+ (cos(theta - (M_2PI / bokeh_sides) * floor((bokeh_sides * theta + M_PI) / M_2PI)));
+
+ if (dist_sqrd > r * r) {
+ discard;
+ }
+ }
+
+ fragData0 = color;
+}
+
+#define MERGE_THRESHOLD 4.0
+
+uniform sampler2D farBuffer;
+uniform sampler2D nearBuffer;
+
+/* Combine the Far and Near color buffers */
+void step_resolve(void)
+{
+ /* Recompute Near / Far CoC */
+ float depth = texture(depthBuffer, uvcoord).r;
+ float zdepth = linear_depth(depth);
+ float coc_signed = calculate_coc(zdepth);
+ float coc_far = max(-coc_signed, 0.0);
+ float coc_near = max(coc_signed, 0.0);
+
+ /* Recompute Near / Far CoC */
+ vec4 srccolor = texture(colorBuffer, uvcoord);
+ vec4 farcolor = texture(farBuffer, uvcoord);
+ vec4 nearcolor = texture(nearBuffer, uvcoord);
+
+ float farweight = farcolor.a;
+ if (farweight > 0.0)
+ farcolor /= farweight;
+
+ float mixfac = smoothstep(1.0, MERGE_THRESHOLD, coc_far);
+
+ farweight = mix(1.0, farweight, mixfac);
+
+ float nearweight = nearcolor.a;
+ if (nearweight > 0.0) {
+ nearcolor /= nearweight;
+ }
+
+ if (coc_near > 1.0) {
+ fragData0 = nearcolor;
+ }
+ else {
+ float totalweight = nearweight + farweight;
+ vec4 finalcolor = mix(srccolor, farcolor, mixfac);
+ fragData0 = mix(finalcolor, nearcolor, nearweight / totalweight);
+ }
+}
+
+void main()
+{
+#ifdef STEP_DOWNSAMPLE
+ step_downsample();
+#elif defined(STEP_SCATTER)
+ step_scatter();
+#elif defined(STEP_RESOLVE)
+ step_resolve();
+#endif
+}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_geom.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_geom.glsl
new file mode 100644
index 00000000000..1c774885a32
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_geom.glsl
@@ -0,0 +1,55 @@
+uniform ivec2 targetBufferSize;
+
+uniform vec2 layerSelection;
+
+uniform sampler2D colorBuffer;
+uniform sampler2D cocBuffer;
+
+layout(points) in;
+layout(triangle_strip, max_vertices = 4) out;
+
+#define POS gl_in[0].gl_Position
+
+in vec2 uvcoord[];
+out vec2 particlecoord;
+flat out vec4 color;
+
+#define M_PI 3.1415926535897932384626433832795
+
+void main()
+{
+ vec4 coc = textureLod(cocBuffer, uvcoord[0], 0.0);
+
+ float offset_val = dot(coc.rg, layerSelection);
+ if (offset_val < 1.0)
+ return;
+
+ vec4 colortex = textureLod(colorBuffer, uvcoord[0], 0.0);
+
+ /* find the area the pixel will cover and divide the color by it */
+ float alpha = 1.0 / (offset_val * offset_val * M_PI);
+ colortex *= alpha;
+ colortex.a = alpha;
+
+ vec2 offset_far = vec2(offset_val * 0.5) / vec2(targetBufferSize.x, targetBufferSize.y);
+
+ color = colortex;
+
+ gl_Position = POS + vec4(-offset_far.x, -offset_far.y, 0.0, 0.0);
+ particlecoord = vec2(-1.0, -1.0);
+ EmitVertex();
+
+ gl_Position = POS + vec4(-offset_far.x, offset_far.y, 0.0, 0.0);
+ particlecoord = vec2(-1.0, 1.0);
+ EmitVertex();
+
+ gl_Position = POS + vec4(offset_far.x, -offset_far.y, 0.0, 0.0);
+ particlecoord = vec2(1.0, -1.0);
+ EmitVertex();
+
+ gl_Position = POS + vec4(offset_far.x, offset_far.y, 0.0, 0.0);
+ particlecoord = vec2(1.0, 1.0);
+ EmitVertex();
+
+ EndPrimitive();
+}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl
new file mode 100644
index 00000000000..3899365a771
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_vert.glsl
@@ -0,0 +1,92 @@
+
+in vec2 pos;
+in vec2 uvs;
+
+uniform vec2 layerSelection;
+
+uniform sampler2D colorBuffer;
+uniform sampler2D cocBuffer;
+
+flat out vec4 color;
+out vec2 particlecoord;
+
+#define M_PI 3.1415926535897932384626433832795
+
+/* geometry shading pass, calculate a texture coordinate based on the indexed id */
+void step_scatter()
+{
+ ivec2 tex_size = textureSize(cocBuffer, 0);
+ vec2 texel_size = 1.0 / vec2(tex_size);
+
+ int t_id = gl_VertexID / 3; /* Triangle Id */
+
+ ivec2 texelco = ivec2(0);
+ /* some math to get the target pixel */
+ texelco.x = t_id % tex_size.x;
+ texelco.y = t_id / tex_size.x;
+
+ float coc = dot(layerSelection, texelFetch(cocBuffer, texelco, 0).rg);
+
+ /* Clamp to max size for performance */
+ coc = min(coc, 100.0);
+
+ if (coc >= 1.0) {
+ color = texelFetch(colorBuffer, texelco, 0);
+ /* find the area the pixel will cover and divide the color by it */
+ float alpha = 1.0 / (coc * coc * M_PI);
+ color *= alpha;
+ color.a = alpha;
+ }
+ else {
+ color = vec4(0.0);
+ }
+
+ /* Generate Triangle : less memory fetches from a VBO */
+ int v_id = gl_VertexID % 3; /* Vertex Id */
+
+ /* Extend to cover at least the unit circle */
+ const float extend = (cos(M_PI / 4.0) + 1.0) * 2.0;
+ /* Crappy diagram
+ * ex 1
+ * | \
+ * | \
+ * 1 | \
+ * | \
+ * | \
+ * 0 | x \
+ * | Circle \
+ * | Origin \
+ * -1 0 --------------- 2
+ * -1 0 1 ex
+ **/
+ gl_Position.x = float(v_id / 2) * extend - 1.0; /* int divisor round down */
+ gl_Position.y = float(v_id % 2) * extend - 1.0;
+ gl_Position.z = 0.0;
+ gl_Position.w = 1.0;
+
+ /* Generate Triangle */
+ particlecoord = gl_Position.xy;
+
+ gl_Position.xy *= coc * texel_size;
+ gl_Position.xy -= 1.0 - 0.5 * texel_size; /* NDC Bottom left */
+ gl_Position.xy += (0.5 + vec2(texelco) * 2.0) * texel_size;
+}
+
+out vec2 uvcoord;
+
+void passthrough()
+{
+ uvcoord = uvs;
+ gl_Position = vec4(pos, 0.0, 1.0);
+}
+
+void main()
+{
+#if defined(STEP_DOWNSAMPLE)
+ passthrough();
+#elif defined(STEP_SCATTER)
+ step_scatter();
+#elif defined(STEP_RESOLVE)
+ passthrough();
+#endif
+} \ No newline at end of file