diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-05-09 22:57:13 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2017-05-10 00:55:19 +0300 |
commit | 9075f934aae2cccad18ba96130650965875f2fa1 (patch) | |
tree | 061d478698a2951f46a2ce0f1cae5035a8d3cc05 /source | |
parent | 435f5017fafe81b90f59cb41be391f85b770e604 (diff) |
Eevee: Initial Depth Of Field commit.
Diffstat (limited to 'source')
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 |