6886b73650c5c6c98ae12b68f9a574dbd2d849e9
[blender.git] / source / blender / draw / engines / workbench / workbench_effect_dof.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Copyright 2016, Blender Foundation.
17  */
18
19 /** \file
20  * \ingroup draw_engine
21  */
22
23 #include "workbench_private.h"
24
25 #include "BKE_camera.h"
26 #include "DEG_depsgraph_query.h"
27
28 #include "DNA_camera_types.h"
29
30 /* *********** STATIC *********** */
31 static struct {
32   struct GPUShader *effect_dof_prepare_sh;
33   struct GPUShader *effect_dof_downsample_sh;
34   struct GPUShader *effect_dof_flatten_v_sh;
35   struct GPUShader *effect_dof_flatten_h_sh;
36   struct GPUShader *effect_dof_dilate_v_sh;
37   struct GPUShader *effect_dof_dilate_h_sh;
38   struct GPUShader *effect_dof_blur1_sh;
39   struct GPUShader *effect_dof_blur2_sh;
40   struct GPUShader *effect_dof_resolve_sh;
41 } e_data = {NULL};
42
43 /* Shaders */
44 extern char datatoc_workbench_effect_dof_frag_glsl[];
45
46 /* *********** Functions *********** */
47
48 /**
49  * Transform [-1..1] square to unit circle.
50  */
51 static void square_to_circle(float x, float y, float *r, float *T)
52 {
53   if (x > -y) {
54     if (x > y) {
55       *r = x;
56       *T = (M_PI / 4.0f) * (y / x);
57     }
58     else {
59       *r = y;
60       *T = (M_PI / 4.0f) * (2 - (x / y));
61     }
62   }
63   else {
64     if (x < y) {
65       *r = -x;
66       *T = (M_PI / 4.0f) * (4 + (y / x));
67     }
68     else {
69       *r = -y;
70       if (y != 0) {
71         *T = (M_PI / 4.0f) * (6 - (x / y));
72       }
73       else {
74         *T = 0.0f;
75       }
76     }
77   }
78 }
79
80 #define KERNEL_RAD 3
81 #define SAMP_LEN SQUARE(KERNEL_RAD * 2 + 1)
82
83 static void workbench_dof_setup_samples(struct GPUUniformBuffer **ubo,
84                                         float **data,
85                                         float bokeh_sides,
86                                         float bokeh_rotation,
87                                         float bokeh_ratio)
88 {
89   if (*data == NULL) {
90     *data = MEM_callocN(sizeof(float) * 4 * SAMP_LEN, "workbench dof samples");
91   }
92   if (*ubo == NULL) {
93     *ubo = DRW_uniformbuffer_create(sizeof(float) * 4 * SAMP_LEN, NULL);
94   }
95
96   float *samp = *data;
97   for (int i = 0; i <= KERNEL_RAD; ++i) {
98     for (int j = -KERNEL_RAD; j <= KERNEL_RAD; ++j) {
99       for (int k = -KERNEL_RAD; k <= KERNEL_RAD; ++k) {
100         if (abs(j) > i || abs(k) > i) {
101           continue;
102         }
103         if (abs(j) < i && abs(k) < i) {
104           continue;
105         }
106         float x = ((float)j) / KERNEL_RAD;
107         float y = ((float)k) / KERNEL_RAD;
108
109         float r, T;
110         square_to_circle(x, y, &r, &T);
111         samp[2] = r;
112
113         /* Bokeh shape parametrisation */
114         if (bokeh_sides > 1.0f) {
115           float denom = T - (2.0 * M_PI / bokeh_sides) *
116                                 floorf((bokeh_sides * T + M_PI) / (2.0 * M_PI));
117           r *= cosf(M_PI / bokeh_sides) / cosf(denom);
118         }
119
120         T += bokeh_rotation;
121
122         samp[0] = r * cosf(T) * bokeh_ratio;
123         samp[1] = r * sinf(T);
124         samp += 4;
125       }
126     }
127   }
128
129   DRW_uniformbuffer_update(*ubo, *data);
130 }
131
132 void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera)
133 {
134   WORKBENCH_TextureList *txl = vedata->txl;
135   WORKBENCH_StorageList *stl = vedata->stl;
136   WORKBENCH_PrivateData *wpd = stl->g_data;
137   WORKBENCH_FramebufferList *fbl = vedata->fbl;
138
139   Camera *cam = camera != NULL ? camera->data : NULL;
140   if ((wpd->shading.flag & V3D_SHADING_DEPTH_OF_FIELD) == 0 || (cam == NULL) ||
141       ((cam->dof.flag & CAM_DOF_ENABLED) == 0)) {
142     wpd->dof_enabled = false;
143     return;
144   }
145
146   if (e_data.effect_dof_prepare_sh == NULL) {
147     e_data.effect_dof_prepare_sh = DRW_shader_create_fullscreen(
148         datatoc_workbench_effect_dof_frag_glsl, "#define PREPARE\n");
149
150     e_data.effect_dof_downsample_sh = DRW_shader_create_fullscreen(
151         datatoc_workbench_effect_dof_frag_glsl, "#define DOWNSAMPLE\n");
152
153     e_data.effect_dof_flatten_v_sh = DRW_shader_create_fullscreen(
154         datatoc_workbench_effect_dof_frag_glsl, "#define FLATTEN_VERTICAL\n");
155
156     e_data.effect_dof_flatten_h_sh = DRW_shader_create_fullscreen(
157         datatoc_workbench_effect_dof_frag_glsl, "#define FLATTEN_HORIZONTAL\n");
158
159     e_data.effect_dof_dilate_v_sh = DRW_shader_create_fullscreen(
160         datatoc_workbench_effect_dof_frag_glsl, "#define DILATE_VERTICAL\n");
161
162     e_data.effect_dof_dilate_h_sh = DRW_shader_create_fullscreen(
163         datatoc_workbench_effect_dof_frag_glsl, "#define DILATE_HORIZONTAL\n");
164
165     e_data.effect_dof_blur1_sh = DRW_shader_create_fullscreen(
166         datatoc_workbench_effect_dof_frag_glsl, "#define BLUR1\n");
167
168     e_data.effect_dof_blur2_sh = DRW_shader_create_fullscreen(
169         datatoc_workbench_effect_dof_frag_glsl, "#define BLUR2\n");
170
171     e_data.effect_dof_resolve_sh = DRW_shader_create_fullscreen(
172         datatoc_workbench_effect_dof_frag_glsl, "#define RESOLVE\n");
173   }
174
175   const float *full_size = DRW_viewport_size_get();
176   int size[2] = {full_size[0] / 2, full_size[1] / 2};
177 #if 0
178   /* NOTE: We Ceil here in order to not miss any edge texel if using a NPO2 texture.  */
179   int shrink_h_size[2] = {ceilf(size[0] / 8.0f), size[1]};
180   int shrink_w_size[2] = {shrink_h_size[0], ceilf(size[1] / 8.0f)};
181 #endif
182
183   DRW_texture_ensure_2d(
184       &txl->dof_source_tx, size[0], size[1], GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP);
185   DRW_texture_ensure_2d(
186       &txl->coc_halfres_tx, size[0], size[1], GPU_RG8, DRW_TEX_FILTER | DRW_TEX_MIPMAP);
187   wpd->dof_blur_tx = DRW_texture_pool_query_2d(
188       size[0], size[1], GPU_R11F_G11F_B10F, &draw_engine_workbench_solid);
189 #if 0
190   wpd->coc_temp_tx = DRW_texture_pool_query_2d(
191       shrink_h_size[0], shrink_h_size[1], GPU_RG8, &draw_engine_workbench_solid);
192   wpd->coc_tiles_tx[0] = DRW_texture_pool_query_2d(
193       shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench_solid);
194   wpd->coc_tiles_tx[1] = DRW_texture_pool_query_2d(
195       shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench_solid);
196 #endif
197
198   GPU_framebuffer_ensure_config(&fbl->dof_downsample_fb,
199                                 {
200                                     GPU_ATTACHMENT_NONE,
201                                     GPU_ATTACHMENT_TEXTURE(txl->dof_source_tx),
202                                     GPU_ATTACHMENT_TEXTURE(txl->coc_halfres_tx),
203                                 });
204 #if 0
205   GPU_framebuffer_ensure_config(&fbl->dof_coc_tile_h_fb,
206                                 {
207                                     GPU_ATTACHMENT_NONE,
208                                     GPU_ATTACHMENT_TEXTURE(wpd->coc_temp_tx),
209                                 });
210   GPU_framebuffer_ensure_config(&fbl->dof_coc_tile_v_fb,
211                                 {
212                                     GPU_ATTACHMENT_NONE,
213                                     GPU_ATTACHMENT_TEXTURE(wpd->coc_tiles_tx[0]),
214                                 });
215   GPU_framebuffer_ensure_config(&fbl->dof_coc_dilate_fb,
216                                 {
217                                     GPU_ATTACHMENT_NONE,
218                                     GPU_ATTACHMENT_TEXTURE(wpd->coc_tiles_tx[1]),
219                                 });
220 #endif
221   GPU_framebuffer_ensure_config(&fbl->dof_blur1_fb,
222                                 {
223                                     GPU_ATTACHMENT_NONE,
224                                     GPU_ATTACHMENT_TEXTURE(wpd->dof_blur_tx),
225                                 });
226   GPU_framebuffer_ensure_config(&fbl->dof_blur2_fb,
227                                 {
228                                     GPU_ATTACHMENT_NONE,
229                                     GPU_ATTACHMENT_TEXTURE(txl->dof_source_tx),
230                                 });
231
232   {
233     const DRWContextState *draw_ctx = DRW_context_state_get();
234     const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
235     RegionView3D *rv3d = draw_ctx->rv3d;
236
237     /* Parameters */
238     /* TODO UI Options */
239     float fstop = cam->dof.aperture_fstop;
240     float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
241     float focus_dist = BKE_camera_object_dof_distance(camera);
242     float focal_len = cam->lens;
243
244     /* TODO(fclem) deduplicate with eevee */
245
246     /* this is factor that converts to the scene scale. focal length and sensor are expressed in mm
247      * unit.scale_length is how many meters per blender unit we have. We want to convert to blender
248      * units though because the shader reads coordinates in world space, which is in blender units.
249      * Note however that focus_distance is already in blender units and shall not be scaled here
250      * (see T48157). */
251     float scale = (scene_eval->unit.system) ? scene_eval->unit.scale_length : 1.0f;
252     float scale_camera = 0.001f / scale;
253     /* we want radius here for the aperture number  */
254     float aperture = 0.5f * scale_camera * focal_len / fstop;
255     float focal_len_scaled = scale_camera * focal_len;
256     float sensor_scaled = scale_camera * sensor;
257
258     if (rv3d != NULL) {
259       sensor_scaled *= rv3d->viewcamtexcofac[0];
260     }
261
262     wpd->dof_aperturesize = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled));
263     wpd->dof_distance = -focus_dist;
264     wpd->dof_invsensorsize = full_size[0] / sensor_scaled;
265
266     wpd->dof_near_far[0] = -cam->clip_start;
267     wpd->dof_near_far[1] = -cam->clip_end;
268
269     float blades = cam->dof.aperture_blades;
270     float rotation = cam->dof.aperture_rotation;
271     float ratio = 1.0f / cam->dof.aperture_ratio;
272
273     if (wpd->dof_ubo == NULL || blades != wpd->dof_blades || rotation != wpd->dof_rotation ||
274         ratio != wpd->dof_ratio) {
275       wpd->dof_blades = blades;
276       wpd->dof_rotation = rotation;
277       wpd->dof_ratio = ratio;
278       workbench_dof_setup_samples(&wpd->dof_ubo, &stl->dof_ubo_data, blades, rotation, ratio);
279     }
280   }
281
282   wpd->dof_enabled = true;
283 }
284
285 void workbench_dof_create_pass(WORKBENCH_Data *vedata,
286                                GPUTexture **dof_input,
287                                GPUTexture *noise_tex)
288 {
289   WORKBENCH_PassList *psl = vedata->psl;
290   WORKBENCH_TextureList *txl = vedata->txl;
291   WORKBENCH_StorageList *stl = vedata->stl;
292   WORKBENCH_PrivateData *wpd = stl->g_data;
293   struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
294
295   if (!wpd->dof_enabled) {
296     return;
297   }
298
299   DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
300
301   psl->dof_down_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR);
302   psl->dof_down2_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR);
303   psl->dof_flatten_h_ps = DRW_pass_create("DoF Flatten Coc H", DRW_STATE_WRITE_COLOR);
304   psl->dof_flatten_v_ps = DRW_pass_create("DoF Flatten Coc V", DRW_STATE_WRITE_COLOR);
305   psl->dof_dilate_h_ps = DRW_pass_create("DoF Dilate Coc H", DRW_STATE_WRITE_COLOR);
306   psl->dof_dilate_v_ps = DRW_pass_create("DoF Dilate Coc V", DRW_STATE_WRITE_COLOR);
307   psl->dof_blur1_ps = DRW_pass_create("DoF Blur 1", DRW_STATE_WRITE_COLOR);
308   psl->dof_blur2_ps = DRW_pass_create("DoF Blur 2", DRW_STATE_WRITE_COLOR);
309   psl->dof_resolve_ps = DRW_pass_create("DoF Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND);
310
311   {
312     DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_prepare_sh, psl->dof_down_ps);
313     DRW_shgroup_uniform_texture_ref(grp, "sceneColorTex", dof_input);
314     DRW_shgroup_uniform_texture(grp, "sceneDepthTex", dtxl->depth);
315     DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
316     DRW_shgroup_uniform_vec3(grp, "dofParams", &wpd->dof_aperturesize, 1);
317     DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1);
318     DRW_shgroup_call(grp, quad, NULL);
319   }
320
321   {
322     DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_downsample_sh, psl->dof_down2_ps);
323     DRW_shgroup_uniform_texture(grp, "sceneColorTex", txl->dof_source_tx);
324     DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
325     DRW_shgroup_call(grp, quad, NULL);
326   }
327 #if 0
328   {
329     DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_h_sh,
330                                               psl->dof_flatten_h_ps);
331     DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
332     DRW_shgroup_call(grp, quad, NULL);
333   }
334   {
335     DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_v_sh,
336                                               psl->dof_flatten_v_ps);
337     DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_temp_tx);
338     DRW_shgroup_call(grp, quad, NULL);
339   }
340   {
341     DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_v_sh, psl->dof_dilate_v_ps);
342     DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[0]);
343     DRW_shgroup_call(grp, quad, NULL);
344   }
345   {
346     DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_h_sh, psl->dof_dilate_h_ps);
347     DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[1]);
348     DRW_shgroup_call(grp, quad, NULL);
349   }
350 #endif
351   {
352     float offset = stl->effects->jitter_index /
353                    (float)workbench_taa_calculate_num_iterations(vedata);
354     DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur1_sh, psl->dof_blur1_ps);
355     DRW_shgroup_uniform_block(grp, "dofSamplesBlock", wpd->dof_ubo);
356     DRW_shgroup_uniform_texture(grp, "noiseTex", noise_tex);
357     DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
358     DRW_shgroup_uniform_texture(grp, "halfResColorTex", txl->dof_source_tx);
359     DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
360     DRW_shgroup_uniform_float_copy(grp, "noiseOffset", offset);
361     DRW_shgroup_call(grp, quad, NULL);
362   }
363   {
364     DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur2_sh, psl->dof_blur2_ps);
365     DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx);
366     DRW_shgroup_uniform_texture(grp, "blurTex", wpd->dof_blur_tx);
367     DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
368     DRW_shgroup_call(grp, quad, NULL);
369   }
370   {
371     DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_resolve_sh, psl->dof_resolve_ps);
372     DRW_shgroup_uniform_texture(grp, "halfResColorTex", txl->dof_source_tx);
373     DRW_shgroup_uniform_texture(grp, "sceneDepthTex", dtxl->depth);
374     DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1);
375     DRW_shgroup_uniform_vec3(grp, "dofParams", &wpd->dof_aperturesize, 1);
376     DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1);
377     DRW_shgroup_call(grp, quad, NULL);
378   }
379 }
380
381 void workbench_dof_engine_free(void)
382 {
383   DRW_SHADER_FREE_SAFE(e_data.effect_dof_prepare_sh);
384   DRW_SHADER_FREE_SAFE(e_data.effect_dof_downsample_sh);
385   DRW_SHADER_FREE_SAFE(e_data.effect_dof_flatten_v_sh);
386   DRW_SHADER_FREE_SAFE(e_data.effect_dof_flatten_h_sh);
387   DRW_SHADER_FREE_SAFE(e_data.effect_dof_dilate_v_sh);
388   DRW_SHADER_FREE_SAFE(e_data.effect_dof_dilate_h_sh);
389   DRW_SHADER_FREE_SAFE(e_data.effect_dof_blur1_sh);
390   DRW_SHADER_FREE_SAFE(e_data.effect_dof_blur2_sh);
391   DRW_SHADER_FREE_SAFE(e_data.effect_dof_resolve_sh);
392 }
393
394 static void workbench_dof_downsample_level(void *userData, int UNUSED(level))
395 {
396   WORKBENCH_PassList *psl = (WORKBENCH_PassList *)userData;
397   DRW_draw_pass(psl->dof_down2_ps);
398 }
399
400 void workbench_dof_draw_pass(WORKBENCH_Data *vedata)
401 {
402   WORKBENCH_FramebufferList *fbl = vedata->fbl;
403   WORKBENCH_StorageList *stl = vedata->stl;
404   WORKBENCH_PassList *psl = vedata->psl;
405   WORKBENCH_PrivateData *wpd = stl->g_data;
406
407   if (!wpd->dof_enabled) {
408     return;
409   }
410
411   DRW_stats_group_start("Depth Of Field");
412
413   GPU_framebuffer_bind(fbl->dof_downsample_fb);
414   DRW_draw_pass(psl->dof_down_ps);
415
416   GPU_framebuffer_recursive_downsample(
417       fbl->dof_downsample_fb, 2, workbench_dof_downsample_level, psl);
418
419 #if 0
420   GPU_framebuffer_bind(fbl->dof_coc_tile_h_fb);
421   DRW_draw_pass(psl->dof_flatten_h_ps);
422
423   GPU_framebuffer_bind(fbl->dof_coc_tile_v_fb);
424   DRW_draw_pass(psl->dof_flatten_v_ps);
425
426   GPU_framebuffer_bind(fbl->dof_coc_dilate_fb);
427   DRW_draw_pass(psl->dof_dilate_v_ps);
428
429   GPU_framebuffer_bind(fbl->dof_coc_tile_v_fb);
430   DRW_draw_pass(psl->dof_dilate_h_ps);
431 #endif
432
433   GPU_framebuffer_bind(fbl->dof_blur1_fb);
434   DRW_draw_pass(psl->dof_blur1_ps);
435
436   GPU_framebuffer_bind(fbl->dof_blur2_fb);
437   DRW_draw_pass(psl->dof_blur2_ps);
438
439   GPU_framebuffer_bind(fbl->color_only_fb);
440   DRW_draw_pass(psl->dof_resolve_ps);
441
442   DRW_stats_group_end();
443 }