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>2019-01-24 19:28:51 +0300
committerClément Foucault <foucault.clem@gmail.com>2019-01-25 17:02:49 +0300
commit3f6e14e667c4442bcc1f4d1fc795633cc706150f (patch)
treec0501be8f98350b1d5907d7a37b4382f38c1a4b7 /source/blender/draw/engines/workbench/workbench_effect_dof.c
parentaae2bf77351103b15e5a97daed7f396a546c001c (diff)
Workbench: Depth Of Field: Initial Commit
The algorithm used is borrowed from : http://tuxedolabs.blogspot.com/2018/05/bokeh-depth-of-field-in-single-pass.html This makes it possible to have a decent blur for foreground over defocused background in one pass only. The algorithm is using a gather approach that is much faster than the scatter approach used in Eevee. This makes it possible to have custom bokeh shapes (not implemented yet) which would be impossible with a separable gaussian technique. The blur is done in 2 steps. The first one define the shape of the bokeh and the second that fill the undersampling. A downsample max-CoC tile texture speed up the gathering process.
Diffstat (limited to 'source/blender/draw/engines/workbench/workbench_effect_dof.c')
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_dof.c297
1 files changed, 297 insertions, 0 deletions
diff --git a/source/blender/draw/engines/workbench/workbench_effect_dof.c b/source/blender/draw/engines/workbench/workbench_effect_dof.c
new file mode 100644
index 00000000000..85213a7460c
--- /dev/null
+++ b/source/blender/draw/engines/workbench/workbench_effect_dof.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2016, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Institute
+ *
+ */
+
+/** \file workbench_effect_dof.c
+ * \ingroup draw_engine
+ */
+
+#include "workbench_private.h"
+
+#include "BKE_camera.h"
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_camera_types.h"
+
+/* *********** STATIC *********** */
+static struct {
+ struct GPUShader *effect_dof_prepare_sh;
+ struct GPUShader *effect_dof_flatten_v_sh;
+ struct GPUShader *effect_dof_flatten_h_sh;
+ struct GPUShader *effect_dof_dilate_v_sh;
+ struct GPUShader *effect_dof_dilate_h_sh;
+ struct GPUShader *effect_dof_blur1_sh;
+ struct GPUShader *effect_dof_blur2_sh;
+ struct GPUShader *effect_dof_resolve_sh;
+} e_data = {NULL};
+
+/* Shaders */
+extern char datatoc_workbench_effect_dof_frag_glsl[];
+
+/* *********** Functions *********** */
+void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
+{
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+
+ if (camera == NULL) {
+ wpd->dof_enabled = false;
+ return;
+ }
+
+ if (e_data.effect_dof_prepare_sh == NULL) {
+ e_data.effect_dof_prepare_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_effect_dof_frag_glsl,
+ "#define PREPARE\n");
+
+ e_data.effect_dof_flatten_v_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_effect_dof_frag_glsl,
+ "#define FLATTEN_VERTICAL\n");
+
+ e_data.effect_dof_flatten_h_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_effect_dof_frag_glsl,
+ "#define FLATTEN_HORIZONTAL\n");
+
+ e_data.effect_dof_dilate_v_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_effect_dof_frag_glsl,
+ "#define DILATE_VERTICAL\n");
+
+ e_data.effect_dof_dilate_h_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_effect_dof_frag_glsl,
+ "#define DILATE_HORIZONTAL\n");
+
+ e_data.effect_dof_blur1_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_effect_dof_frag_glsl,
+ "#define BLUR1\n");
+
+ e_data.effect_dof_blur2_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_effect_dof_frag_glsl,
+ "#define BLUR2\n");
+
+ e_data.effect_dof_resolve_sh = DRW_shader_create_fullscreen(
+ datatoc_workbench_effect_dof_frag_glsl,
+ "#define RESOLVE\n");
+ }
+
+ const float *full_size = DRW_viewport_size_get();
+ int size[2] = {full_size[0] / 2, full_size[1] / 2};
+ /* NOTE: We Ceil here in order to not miss any edge texel if using a NPO2 texture. */
+ int shrink_h_size[2] = {ceilf(size[0] / 8.0f), size[1]};
+ int shrink_w_size[2] = {shrink_h_size[0], ceilf(size[1] / 8.0f)};
+
+ wpd->half_res_col_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_R11F_G11F_B10F, &draw_engine_workbench_solid);
+ wpd->dof_blur_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_R11F_G11F_B10F, &draw_engine_workbench_solid);
+ wpd->coc_halfres_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RG8, &draw_engine_workbench_solid);
+ wpd->coc_temp_tx = DRW_texture_pool_query_2D(shrink_h_size[0], shrink_h_size[1], GPU_RG8, &draw_engine_workbench_solid);
+ wpd->coc_tiles_tx[0] = DRW_texture_pool_query_2D(shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench_solid);
+ wpd->coc_tiles_tx[1] = DRW_texture_pool_query_2D(shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench_solid);
+
+ GPU_framebuffer_ensure_config(&fbl->dof_downsample_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->half_res_col_tx),
+ GPU_ATTACHMENT_TEXTURE(wpd->coc_halfres_tx),
+ });
+ GPU_framebuffer_ensure_config(&fbl->dof_coc_tile_h_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->coc_temp_tx),
+ });
+ GPU_framebuffer_ensure_config(&fbl->dof_coc_tile_v_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->coc_tiles_tx[0]),
+ });
+ GPU_framebuffer_ensure_config(&fbl->dof_coc_dilate_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->coc_tiles_tx[1]),
+ });
+ GPU_framebuffer_ensure_config(&fbl->dof_blur1_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->dof_blur_tx),
+ });
+ GPU_framebuffer_ensure_config(&fbl->dof_blur2_fb, {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(wpd->half_res_col_tx),
+ });
+
+ {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
+ RegionView3D *rv3d = draw_ctx->rv3d;
+ Camera *cam = (Camera *)camera->data;
+
+ /* Parameters */
+ /* TODO UI Options */
+ float fstop = cam->gpu_dof.fstop;
+ float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
+ float focus_dist = BKE_camera_object_dof_distance(camera);
+ float focal_len = cam->lens;
+
+ /* TODO(fclem) deduplicate with eevee */
+
+ /* 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_eval->unit.system) ? scene_eval->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;
+
+ if (rv3d != NULL) {
+ sensor_scaled *= rv3d->viewcamtexcofac[0];
+ }
+
+ wpd->dof_aperturesize = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled));
+ wpd->dof_distance = -focus_dist;
+ wpd->dof_invsensorsize = full_size[0] / sensor_scaled;
+
+ wpd->dof_near_far[0] = -cam->clipsta;
+ wpd->dof_near_far[1] = -cam->clipend;
+ }
+
+ wpd->dof_enabled = true;
+}
+
+void workbench_dof_create_pass(WORKBENCH_Data *vedata, GPUTexture **dof_input)
+{
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+ struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+
+ if (!wpd->dof_enabled) {
+ return;
+ }
+
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+
+ psl->dof_down_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR);
+ psl->dof_flatten_h_ps = DRW_pass_create("DoF Flatten Coc H", DRW_STATE_WRITE_COLOR);
+ psl->dof_flatten_v_ps = DRW_pass_create("DoF Flatten Coc V", DRW_STATE_WRITE_COLOR);
+ psl->dof_dilate_h_ps = DRW_pass_create("DoF Dilate Coc H", DRW_STATE_WRITE_COLOR);
+ psl->dof_dilate_v_ps = DRW_pass_create("DoF Dilate Coc V", DRW_STATE_WRITE_COLOR);
+ psl->dof_blur1_ps = DRW_pass_create("DoF Blur 1", DRW_STATE_WRITE_COLOR);
+ psl->dof_blur2_ps = DRW_pass_create("DoF Blur 2", DRW_STATE_WRITE_COLOR);
+ psl->dof_resolve_ps = DRW_pass_create("DoF Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND);
+
+ {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_prepare_sh, psl->dof_down_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "sceneColorTex", dof_input);
+ DRW_shgroup_uniform_texture(grp, "sceneDepthTex", dtxl->depth);
+ DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
+ DRW_shgroup_uniform_vec3(grp, "dofParams", &wpd->dof_aperturesize, 1);
+ DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+ {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_h_sh, psl->dof_flatten_h_ps);
+ DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_halfres_tx);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+ {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_v_sh, psl->dof_flatten_v_ps);
+ DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_temp_tx);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+ {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_v_sh, psl->dof_dilate_v_ps);
+ DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[0]);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+ {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_h_sh, psl->dof_dilate_h_ps);
+ DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[1]);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+ {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur1_sh, psl->dof_blur1_ps);
+ DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_halfres_tx);
+ DRW_shgroup_uniform_texture(grp, "maxCocTilesTex", wpd->coc_tiles_tx[0]);
+ DRW_shgroup_uniform_texture(grp, "halfResColorTex", wpd->half_res_col_tx);
+ DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+ {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur2_sh, psl->dof_blur2_ps);
+ DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_halfres_tx);
+ DRW_shgroup_uniform_texture(grp, "blurTex", wpd->dof_blur_tx);
+ DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+ {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_resolve_sh, psl->dof_resolve_ps);
+ DRW_shgroup_uniform_texture(grp, "halfResColorTex", wpd->half_res_col_tx);
+ DRW_shgroup_uniform_texture(grp, "sceneDepthTex", dtxl->depth);
+ DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
+ DRW_shgroup_uniform_vec3(grp, "dofParams", &wpd->dof_aperturesize, 1);
+ DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1);
+ DRW_shgroup_call_add(grp, quad, NULL);
+ }
+}
+
+void workbench_dof_engine_free(void)
+{
+ DRW_SHADER_FREE_SAFE(e_data.effect_dof_prepare_sh);
+ DRW_SHADER_FREE_SAFE(e_data.effect_dof_flatten_v_sh);
+ DRW_SHADER_FREE_SAFE(e_data.effect_dof_flatten_h_sh);
+ DRW_SHADER_FREE_SAFE(e_data.effect_dof_dilate_v_sh);
+ DRW_SHADER_FREE_SAFE(e_data.effect_dof_dilate_h_sh);
+ DRW_SHADER_FREE_SAFE(e_data.effect_dof_blur1_sh);
+ DRW_SHADER_FREE_SAFE(e_data.effect_dof_blur2_sh);
+ DRW_SHADER_FREE_SAFE(e_data.effect_dof_resolve_sh);
+}
+
+void workbench_dof_draw_pass(WORKBENCH_Data *vedata)
+{
+ WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_StorageList *stl = vedata->stl;
+ WORKBENCH_PassList *psl = vedata->psl;
+ WORKBENCH_PrivateData *wpd = stl->g_data;
+
+ if (!wpd->dof_enabled) {
+ return;
+ }
+
+ GPU_framebuffer_bind(fbl->dof_downsample_fb);
+ DRW_draw_pass(psl->dof_down_ps);
+
+ GPU_framebuffer_bind(fbl->dof_coc_tile_h_fb);
+ DRW_draw_pass(psl->dof_flatten_h_ps);
+
+ GPU_framebuffer_bind(fbl->dof_coc_tile_v_fb);
+ DRW_draw_pass(psl->dof_flatten_v_ps);
+
+ GPU_framebuffer_bind(fbl->dof_coc_dilate_fb);
+ DRW_draw_pass(psl->dof_dilate_v_ps);
+
+ GPU_framebuffer_bind(fbl->dof_coc_tile_v_fb);
+ DRW_draw_pass(psl->dof_dilate_h_ps);
+
+ GPU_framebuffer_bind(fbl->dof_blur1_fb);
+ DRW_draw_pass(psl->dof_blur1_ps);
+
+ GPU_framebuffer_bind(fbl->dof_blur2_fb);
+ DRW_draw_pass(psl->dof_blur2_ps);
+
+ GPU_framebuffer_bind(fbl->color_only_fb);
+ DRW_draw_pass(psl->dof_resolve_ps);
+}