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.
This commit is contained in:
Clément Foucault 2019-01-24 17:28:51 +01:00
parent aae2bf7735
commit 3f6e14e667
6 changed files with 612 additions and 3 deletions

View File

@ -115,6 +115,7 @@ set(SRC
engines/workbench/workbench_data.c
engines/workbench/workbench_deferred.c
engines/workbench/workbench_effect_aa.c
engines/workbench/workbench_effect_dof.c
engines/workbench/workbench_effect_fxaa.c
engines/workbench/workbench_effect_taa.c
engines/workbench/workbench_engine.c
@ -227,6 +228,7 @@ data_to_c_simple(engines/workbench/shaders/workbench_common_lib.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_deferred_composite_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_deferred_background_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_effect_dof_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_effect_fxaa_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_effect_taa_frag.glsl SRC)
data_to_c_simple(engines/workbench/shaders/workbench_forward_composite_frag.glsl SRC)

View File

@ -0,0 +1,265 @@
/**
* Separable Hexagonal Bokeh Blur by Colin Barré-Brisebois
* https://colinbarrebrisebois.com/2017/04/18/hexagonal-bokeh-blur-revisited-part-1-basic-3-pass-version/
* Converted and adapted from HLSL to GLSL by Clément Foucault
**/
uniform mat4 ProjectionMatrix;
uniform vec2 invertedViewportSize;
uniform vec2 nearFar;
uniform vec3 dofParams;
uniform sampler2D inputCocTex;
uniform sampler2D maxCocTilesTex;
uniform sampler2D sceneColorTex;
uniform sampler2D sceneDepthTex;
uniform sampler2D backgroundTex;
uniform sampler2D halfResColorTex;
uniform sampler2D blurTex;
#define dof_aperturesize dofParams.x
#define dof_distance dofParams.y
#define dof_invsensorsize dofParams.z
#define NUM_SAMPLES 25
#define THRESHOLD 1.0
#define M_PI 3.1415926535897932 /* pi */
const float GOLDEN_ANGLE = 2.39996323;
const float MAX_BLUR_SIZE = 20.0;
const float RAD_SCALE = 2.0; // Smaller = nicer blur, larger = faster
const float MAX_COC_SIZE = 40.0;
float max_v4(vec4 v) { return max(max(v.x, v.y), max(v.z, v.w)); }
#define weighted_sum(a, b, c, d, e, e_sum) ((a) * e.x + (b) * e.y + (c) * e.z + (d) * e.w) / max(1e-6, e_sum);
#define encode_signed_coc(coc) (((coc) / MAX_COC_SIZE) * 0.5 + 0.5);
#define decode_signed_coc(coc) (((coc) * 2.0 - 1.0) * MAX_COC_SIZE);
/* divide by sensor size to get the normalized size */
#define calculate_coc(zdepth) (dof_aperturesize * (dof_distance / zdepth - 1.0) * dof_invsensorsize)
#define linear_depth(z) ((ProjectionMatrix[3][3] == 0.0) \
? (nearFar.x * nearFar.y) / (z * (nearFar.x - nearFar.y) + nearFar.y) \
: (z * 2.0 - 1.0) * nearFar.y)
vec2 encode_coc(float near, float far) { return vec2(near, far) / MAX_COC_SIZE; }
float decode_coc(vec2 cocs) { return max(cocs.x, cocs.y) * MAX_COC_SIZE; }
/**
* ----------------- STEP 0 ------------------
* Coc aware downsample.
**/
#ifdef PREPARE
layout(location = 0) out vec4 backgroundColorCoc;
layout(location = 1) out vec2 normalizedCoc;
void main()
{
/* Half Res pass */
vec2 uv = (floor(gl_FragCoord.xy) * 2.0 + 0.5) * invertedViewportSize;
ivec4 texel = ivec4(gl_FragCoord.xyxy) * 2 + ivec4(0, 0, 1, 1);
/* custom downsampling */
vec4 color1 = texelFetch(sceneColorTex, texel.xy, 0);
vec4 color2 = texelFetch(sceneColorTex, texel.zw, 0);
vec4 color3 = texelFetch(sceneColorTex, texel.zy, 0);
vec4 color4 = texelFetch(sceneColorTex, texel.xw, 0);
vec3 ofs = vec3(invertedViewportSize.xy, 0.0);
vec4 depths;
depths.x = texelFetch(sceneDepthTex, texel.xy, 0).x;
depths.y = texelFetch(sceneDepthTex, texel.zw, 0).x;
depths.z = texelFetch(sceneDepthTex, texel.zy, 0).x;
depths.w = texelFetch(sceneDepthTex, texel.xw, 0).x;
vec4 zdepths = linear_depth(depths);
vec4 cocs_near = calculate_coc(zdepths);
vec4 cocs_far = -cocs_near;
float coc_near = max(max_v4(cocs_near), 0.0);
float coc_far = max(max_v4(cocs_far), 0.0);
/* now we need to write the near-far fields premultiplied by the coc
* also use bilateral weighting by each coc values to avoid bleeding. */
vec4 near_weights = step(0.0, cocs_near) * clamp(1.0 - abs(coc_near - cocs_near), 0.0, 1.0);
vec4 far_weights = step(0.0, cocs_far) * clamp(1.0 - abs(coc_far - cocs_far), 0.0, 1.0);
/* now write output to weighted buffers. */
// backgroundColorCoc = weighted_sum(color1, color2, color3, color4, cocs_far, coc_far);
float tot_weight_near = dot(near_weights, vec4(1.0));
float tot_weight_far = dot(far_weights, vec4(1.0));
backgroundColorCoc = weighted_sum(color1, color2, color3, color4, near_weights, tot_weight_near);
backgroundColorCoc += weighted_sum(color1, color2, color3, color4, far_weights, tot_weight_far);
if (tot_weight_near > 0.0 && tot_weight_far > 0.0) {
backgroundColorCoc *= 0.5;
}
normalizedCoc = encode_coc(cocs_near.x, cocs_far.x);
}
#endif
/**
* ----------------- STEP 1 ------------------
* Flatten COC buffer using max filter.
**/
#if defined(FLATTEN_VERTICAL) || defined(FLATTEN_HORIZONTAL)
layout(location = 0) out vec2 flattenedCoc;
void main()
{
#ifdef FLATTEN_HORIZONTAL
ivec2 texel = ivec2(gl_FragCoord.xy) * ivec2(8, 1);
vec2 cocs1 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 0)).rg;
vec2 cocs2 = texelFetchOffset(inputCocTex, texel, 0, ivec2(1, 0)).rg;
vec2 cocs3 = texelFetchOffset(inputCocTex, texel, 0, ivec2(2, 0)).rg;
vec2 cocs4 = texelFetchOffset(inputCocTex, texel, 0, ivec2(3, 0)).rg;
vec2 cocs5 = texelFetchOffset(inputCocTex, texel, 0, ivec2(4, 0)).rg;
vec2 cocs6 = texelFetchOffset(inputCocTex, texel, 0, ivec2(5, 0)).rg;
vec2 cocs7 = texelFetchOffset(inputCocTex, texel, 0, ivec2(6, 0)).rg;
vec2 cocs8 = texelFetchOffset(inputCocTex, texel, 0, ivec2(7, 0)).rg;
#else /* FLATTEN_VERTICAL */
ivec2 texel = ivec2(gl_FragCoord.xy) * ivec2(1, 8);
vec2 cocs1 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 0)).rg;
vec2 cocs2 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 1)).rg;
vec2 cocs3 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 2)).rg;
vec2 cocs4 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 3)).rg;
vec2 cocs5 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 4)).rg;
vec2 cocs6 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 5)).rg;
vec2 cocs7 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 6)).rg;
vec2 cocs8 = texelFetchOffset(inputCocTex, texel, 0, ivec2(0, 7)).rg;
#endif
flattenedCoc = max(max(max(cocs1, cocs2), max(cocs3, cocs4)), max(max(cocs5, cocs6), max(cocs7, cocs8)));
}
#endif
/**
* ----------------- STEP 1.ax------------------
* Dilate COC buffer using min filter.
**/
#if defined(DILATE_VERTICAL) || defined(DILATE_HORIZONTAL)
layout(location = 0) out vec2 dilatedCoc;
void main()
{
vec2 texel_size = 1.0 / vec2(textureSize(inputCocTex, 0));
vec2 uv = gl_FragCoord.xy * texel_size;
#ifdef DILATE_VERTICAL
// vec2 cocs1 = texture(inputCocTex, uv + texel_size * vec2(-3, 0)).rg;
vec2 cocs2 = texture(inputCocTex, uv + texel_size * vec2(-2, 0)).rg;
vec2 cocs3 = texture(inputCocTex, uv + texel_size * vec2(-1, 0)).rg;
vec2 cocs4 = texture(inputCocTex, uv + texel_size * vec2( 0, 0)).rg;
vec2 cocs5 = texture(inputCocTex, uv + texel_size * vec2( 1, 0)).rg;
vec2 cocs6 = texture(inputCocTex, uv + texel_size * vec2( 2, 0)).rg;
// vec2 cocs7 = texture(inputCocTex, uv + texel_size * vec2( 3, 0)).rg;
#else /* DILATE_HORIZONTAL */
// vec2 cocs1 = texture(inputCocTex, uv + texel_size * vec2(0, -3)).rg;
vec2 cocs2 = texture(inputCocTex, uv + texel_size * vec2(0, -2)).rg;
vec2 cocs3 = texture(inputCocTex, uv + texel_size * vec2(0, -1)).rg;
vec2 cocs4 = texture(inputCocTex, uv + texel_size * vec2(0, 0)).rg;
vec2 cocs5 = texture(inputCocTex, uv + texel_size * vec2(0, 1)).rg;
vec2 cocs6 = texture(inputCocTex, uv + texel_size * vec2(0, 2)).rg;
// vec2 cocs7 = texture(inputCocTex, uv + texel_size * vec2(0, 3)).rg;
#endif
dilatedCoc = max(max(cocs3, cocs4), max(max(cocs5, cocs6), cocs2));
// dilatedCoc = max(max(max(cocs1, cocs2), max(cocs3, cocs4)), max(max(cocs5, cocs6), cocs7));
}
#endif
/**
* ----------------- STEP 2 ------------------
* Blur vertically and diagonally.
* Outputs vertical blur and combined blur in MRT
**/
#ifdef BLUR1
layout(location = 0) out vec4 blurColor;
void main()
{
/* Half Res pass */
vec2 uv = gl_FragCoord.xy * invertedViewportSize * 2.0;
vec2 size = vec2(textureSize(halfResColorTex, 0).xy);
ivec2 texel = ivec2(uv * size);
vec3 color = texelFetch(halfResColorTex, texel, 0).rgb;
float coc = decode_coc(texelFetch(inputCocTex, texel, 0).rg);
/* TODO Ensure alignement */
vec2 max_radii = texture(maxCocTilesTex, (0.5 + floor(gl_FragCoord.xy / 8.0)) / vec2(textureSize(maxCocTilesTex, 0))).rg;
float max_radius = decode_coc(max_radii);
float center_coc = coc;
float tot = 1.0;
float radius = RAD_SCALE;
for (float ang = 0.0; radius < MAX_BLUR_SIZE && radius < max_radius; ang += GOLDEN_ANGLE) {
vec2 tc = uv + vec2(cos(ang), sin(ang)) * invertedViewportSize * radius;
vec3 samp = texture(halfResColorTex, tc).rgb;
coc = decode_coc(texture(inputCocTex, tc).rg);
if (coc > center_coc) {
coc = clamp(abs(coc), 0.0, abs(center_coc) * 2.0);
}
float m = smoothstep(radius - 0.5, radius + 0.5, abs(coc));
color += mix(color / tot, samp, m);
tot += 1.0;
radius += RAD_SCALE / radius;
}
blurColor.rgb = color / tot;
blurColor.a = 1.0;
}
#endif
/**
* ----------------- STEP 3 ------------------
* Additional 3x3 blur
**/
#ifdef BLUR2
out vec4 finalColor;
void main()
{
/* Half Res pass */
vec2 pixel_size = vec2(1.0, 1.0) / vec2(textureSize(blurTex, 0).xy);
vec2 uv = gl_FragCoord.xy * pixel_size.xy;
vec2 max_radii = texture(inputCocTex, uv).rg;
/* Scale filter */
float rad = min(max(max_radii.x, max_radii.y) * MAX_COC_SIZE, 4.0) * 0.25;
finalColor = texture(blurTex, uv + pixel_size * vec2(-0.5, -0.5) * rad);
finalColor += texture(blurTex, uv + pixel_size * vec2(-0.5, 1.5) * rad);
finalColor += texture(blurTex, uv + pixel_size * vec2( 1.5, -0.5) * rad);
finalColor += texture(blurTex, uv + pixel_size * vec2( 1.5, 1.5) * rad);
finalColor *= 0.25;
}
#endif
/**
* ----------------- STEP 4 ------------------
**/
#ifdef RESOLVE
out vec4 finalColor;
void main()
{
/* Fullscreen pass */
vec2 pixel_size = 0.5 / vec2(textureSize(halfResColorTex, 0).xy);
vec2 uv = gl_FragCoord.xy * pixel_size;
/* TODO MAKE SURE TO ALIGN SAMPLE POSITION TO AVOID OFFSET IN THE BOKEH */
float depth = texelFetch(sceneDepthTex, ivec2(gl_FragCoord.xy), 0).r;
float zdepth = linear_depth(depth);
float coc = calculate_coc(zdepth);
finalColor = texture(halfResColorTex, uv);
finalColor.a = smoothstep(1.0, 3.0, abs(coc));
}
#endif

View File

@ -343,6 +343,9 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
WORKBENCH_PassList *psl = vedata->psl;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
const DRWContextState *draw_ctx = DRW_context_state_get();
RegionView3D *rv3d = draw_ctx->rv3d;
View3D *v3d = draw_ctx->v3d;
Object *camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL;
if (!stl->g_data) {
/* Alloc transient pointers */
@ -406,6 +409,8 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
WORKBENCH_PrivateData *wpd = stl->g_data;
workbench_private_data_init(wpd);
workbench_dof_engine_init(vedata, camera);
{
const float *viewport_size = DRW_viewport_size_get();
const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
@ -448,7 +453,7 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
GPU_ATTACHMENT_TEXTURE(dtxl->depth),
GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx),
});
GPU_framebuffer_ensure_config(&fbl->volume_fb, {
GPU_framebuffer_ensure_config(&fbl->color_only_fb, {
GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx),
});
@ -514,6 +519,10 @@ void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
workbench_aa_create_pass(vedata, &e_data.color_buffer_tx);
}
{
workbench_dof_create_pass(vedata, &e_data.composite_buffer_tx);
}
if (CAVITY_ENABLED(wpd)) {
int state = DRW_STATE_WRITE_COLOR;
GPUShader *shader = workbench_cavity_shader_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd));
@ -583,6 +592,7 @@ void workbench_deferred_engine_free(void)
workbench_volume_engine_free();
workbench_fxaa_engine_free();
workbench_taa_engine_free();
workbench_dof_engine_free();
}
static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp)
@ -1089,10 +1099,11 @@ void workbench_deferred_draw_scene(WORKBENCH_Data *vedata)
DRW_draw_pass(psl->background_pass);
if (wpd->volumes_do) {
GPU_framebuffer_bind(fbl->volume_fb);
GPU_framebuffer_bind(fbl->color_only_fb);
DRW_draw_pass(psl->volume_pass);
}
workbench_dof_draw_pass(vedata);
workbench_aa_draw_pass(vedata, e_data.composite_buffer_tx);
}

View File

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

View File

@ -430,6 +430,7 @@ void workbench_forward_engine_free()
workbench_volume_engine_free();
workbench_fxaa_engine_free();
workbench_taa_engine_free();
workbench_dof_engine_free();
}
void workbench_forward_cache_init(WORKBENCH_Data *UNUSED(vedata))

View File

@ -92,7 +92,14 @@ typedef struct WORKBENCH_FramebufferList {
struct GPUFrameBuffer *effect_fb;
struct GPUFrameBuffer *effect_taa_fb;
struct GPUFrameBuffer *depth_buffer_fb;
struct GPUFrameBuffer *volume_fb;
struct GPUFrameBuffer *color_only_fb;
struct GPUFrameBuffer *dof_downsample_fb;
struct GPUFrameBuffer *dof_coc_tile_h_fb;
struct GPUFrameBuffer *dof_coc_tile_v_fb;
struct GPUFrameBuffer *dof_coc_dilate_fb;
struct GPUFrameBuffer *dof_blur1_fb;
struct GPUFrameBuffer *dof_blur2_fb;
/* Forward render buffers */
struct GPUFrameBuffer *object_outline_fb;
@ -129,6 +136,14 @@ typedef struct WORKBENCH_PassList {
struct DRWPass *background_pass_clip;
struct DRWPass *ghost_resolve_pass;
struct DRWPass *effect_aa_pass;
struct DRWPass *dof_down_ps;
struct DRWPass *dof_flatten_v_ps;
struct DRWPass *dof_flatten_h_ps;
struct DRWPass *dof_dilate_h_ps;
struct DRWPass *dof_dilate_v_ps;
struct DRWPass *dof_blur1_ps;
struct DRWPass *dof_blur2_ps;
struct DRWPass *dof_resolve_ps;
struct DRWPass *volume_pass;
/* forward rendering */
@ -218,6 +233,18 @@ typedef struct WORKBENCH_PrivateData {
float ssao_params[4];
float ssao_settings[4];
/* Dof */
struct GPUTexture *half_res_col_tx;
struct GPUTexture *dof_blur_tx;
struct GPUTexture *coc_halfres_tx;
struct GPUTexture *coc_temp_tx;
struct GPUTexture *coc_tiles_tx[2];
float dof_aperturesize;
float dof_distance;
float dof_invsensorsize;
float dof_near_far[2];
bool dof_enabled;
/* Color Management */
bool use_color_view_settings;
} WORKBENCH_PrivateData; /* Transient data */
@ -302,6 +329,12 @@ void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata);
void workbench_taa_view_updated(WORKBENCH_Data *vedata);
int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata);
/* workbench_effect_dof.c */
void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera);
void workbench_dof_engine_free(void);
void workbench_dof_create_pass(WORKBENCH_Data *vedata, GPUTexture **dof_input);
void workbench_dof_draw_pass(WORKBENCH_Data *vedata);
/* workbench_materials.c */
int workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd, Image *ima, Object *ob);
void workbench_material_get_image_and_mat(Object *ob, int mat_nr, Image **r_image, int *r_interp, Material **r_mat);