Eevee: Initial Depth Of Field commit.

This commit is contained in:
Clément Foucault 2017-05-09 21:57:13 +02:00
parent 435f5017fa
commit 9075f934aa
7 changed files with 596 additions and 44 deletions

View File

@ -37,7 +37,7 @@ class CAMERA_MT_presets(Menu):
bl_label = "Camera Presets"
preset_subdir = "camera"
preset_operator = "script.execute_preset"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
draw = Menu.draw_preset
@ -45,14 +45,14 @@ class SAFE_AREAS_MT_presets(Menu):
bl_label = "Camera Presets"
preset_subdir = "safe_areas"
preset_operator = "script.execute_preset"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
draw = Menu.draw_preset
class DATA_PT_context_camera(CameraButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@ -72,7 +72,7 @@ class DATA_PT_context_camera(CameraButtonsPanel, Panel):
class DATA_PT_lens(CameraButtonsPanel, Panel):
bl_label = "Lens"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@ -183,7 +183,7 @@ class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel):
class DATA_PT_camera(CameraButtonsPanel, Panel):
bl_label = "Camera"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@ -217,7 +217,7 @@ class DATA_PT_camera(CameraButtonsPanel, Panel):
class DATA_PT_camera_dof(CameraButtonsPanel, Panel):
bl_label = "Depth of Field"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@ -247,7 +247,7 @@ class DATA_PT_camera_dof(CameraButtonsPanel, Panel):
class DATA_PT_camera_display(CameraButtonsPanel, Panel):
bl_label = "Display"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
def draw(self, context):
layout = self.layout
@ -277,7 +277,7 @@ class DATA_PT_camera_display(CameraButtonsPanel, Panel):
class DATA_PT_camera_safe_areas(CameraButtonsPanel, Panel):
bl_label = "Safe Areas"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
def draw_header(self, context):
cam = context.camera
@ -293,7 +293,7 @@ class DATA_PT_camera_safe_areas(CameraButtonsPanel, Panel):
class DATA_PT_custom_props_camera(CameraButtonsPanel, PropertyPanel, Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
_context_path = "object.data"
_property_type = bpy.types.Camera

View File

@ -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)

View File

@ -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);
}
@ -312,6 +400,52 @@ void EEVEE_effects_cache_init(EEVEE_Data *vedata)
DRW_shgroup_uniform_float(grp, "bloomIntensity", &effects->bloom_intensity, 1);
}
{
/** 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 */
@ -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]);

View File

@ -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),
};
/* *********************************** */

View File

@ -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
}

View File

@ -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();
}

View File

@ -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
}