diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-11-01 03:03:36 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2017-11-01 03:17:35 +0300 |
commit | 345ffe3e4d9f9a37e95f65afb02510fb2cca428a (patch) | |
tree | a7c44906515adfa085bf8fc0b253d03455c6fbe0 /source/blender/draw/engines | |
parent | d836adb2757d61a26687d1d89f83dcf9dea88e98 (diff) |
Eevee: Effects: Split each effect in it's own file.
This also:
- make sure to only compile the shader needed by the active effects.
- same thing for the shading groups.
- disable TAA if motion blur is active (avoid infinite refresh).
Diffstat (limited to 'source/blender/draw/engines')
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_bloom.c | 333 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_depth_of_field.c | 283 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_effects.c | 1675 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_engine.c | 56 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_lightprobes.c | 3 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_materials.c | 3 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_motion_blur.c | 207 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_occlusion.c | 252 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_private.h | 76 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_screen_raytrace.c | 337 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_temporal_sampling.c | 197 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_volumes.c | 578 |
12 files changed, 2371 insertions, 1629 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_bloom.c b/source/blender/draw/engines/eevee/eevee_bloom.c new file mode 100644 index 00000000000..1bb3878278a --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_bloom.c @@ -0,0 +1,333 @@ +/* + * 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 + * + */ + +/* Eevee's bloom shader + */ + +/** \file eevee_bloom.c + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "BKE_global.h" /* for G.debug_value */ + +#include "BLI_dynstr.h" + +#include "eevee_private.h" +#include "GPU_extensions.h" +#include "GPU_texture.h" + +static struct { + /* Bloom */ + struct GPUShader *bloom_blit_sh[2]; + struct GPUShader *bloom_downsample_sh[2]; + struct GPUShader *bloom_upsample_sh[2]; + struct GPUShader *bloom_resolve_sh[2]; +} e_data = {NULL}; /* Engine data */ + +extern char datatoc_effect_bloom_frag_glsl[]; + +static void eevee_create_shader_bloom(void) +{ + 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" + "#define HIGH_QUALITY\n"); + + e_data.bloom_downsample_sh[0] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_DOWNSAMPLE\n"); + e_data.bloom_downsample_sh[1] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_DOWNSAMPLE\n" + "#define HIGH_QUALITY\n"); + + e_data.bloom_upsample_sh[0] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_UPSAMPLE\n"); + e_data.bloom_upsample_sh[1] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_UPSAMPLE\n" + "#define HIGH_QUALITY\n"); + + e_data.bloom_resolve_sh[0] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_RESOLVE\n"); + e_data.bloom_resolve_sh[1] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_RESOLVE\n" + "#define HIGH_QUALITY\n"); +} + +int EEVEE_bloom_init(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_EffectsInfo *effects = stl->effects; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + SceneLayer *scene_layer = draw_ctx->scene_layer; + IDProperty *props = BKE_scene_layer_engine_evaluated_get(scene_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); + + if (BKE_collection_engine_property_value_get_bool(props, "bloom_enable")) { + const float *viewport_size = DRW_viewport_size_get(); + + /* Shaders */ + if (!e_data.bloom_blit_sh[0]) { + eevee_create_shader_bloom(); + } + + /* Bloom */ + int blitsize[2], texsize[2]; + + /* Blit Buffer */ + effects->source_texel_size[0] = 1.0f / viewport_size[0]; + effects->source_texel_size[1] = 1.0f / viewport_size[1]; + + blitsize[0] = (int)viewport_size[0]; + blitsize[1] = (int)viewport_size[1]; + + effects->blit_texel_size[0] = 1.0f / (float)blitsize[0]; + effects->blit_texel_size[1] = 1.0f / (float)blitsize[1]; + + DRWFboTexture tex_blit = {&txl->bloom_blit, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}; + DRW_framebuffer_init(&fbl->bloom_blit_fb, &draw_engine_eevee_type, + (int)blitsize[0], (int)blitsize[1], + &tex_blit, 1); + + /* Parameters */ + float threshold = BKE_collection_engine_property_value_get_float(props, "bloom_threshold"); + float knee = BKE_collection_engine_property_value_get_float(props, "bloom_knee"); + float intensity = BKE_collection_engine_property_value_get_float(props, "bloom_intensity"); + const float *color = BKE_collection_engine_property_value_get_float_array(props, "bloom_color"); + float radius = BKE_collection_engine_property_value_get_float(props, "bloom_radius"); + effects->bloom_clamp = BKE_collection_engine_property_value_get_float(props, "bloom_clamp"); + + /* determine the iteration count */ + const float minDim = (float)MIN2(blitsize[0], blitsize[1]); + const float maxIter = (radius - 8.0f) + log(minDim) / log(2); + const int maxIterInt = effects->bloom_iteration_ct = (int)maxIter; + + CLAMP(effects->bloom_iteration_ct, 1, MAX_BLOOM_STEP); + + effects->bloom_sample_scale = 0.5f + maxIter - (float)maxIterInt; + effects->bloom_curve_threshold[0] = threshold - knee; + effects->bloom_curve_threshold[1] = knee * 2.0f; + effects->bloom_curve_threshold[2] = 0.25f / max_ff(1e-5f, knee); + effects->bloom_curve_threshold[3] = threshold; + + mul_v3_v3fl(effects->bloom_color, color, intensity); + + /* Downsample buffers */ + copy_v2_v2_int(texsize, blitsize); + for (int i = 0; i < effects->bloom_iteration_ct; ++i) { + texsize[0] /= 2; texsize[1] /= 2; + + if (GPU_type_matches(GPU_DEVICE_AMD_VEGA, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) { + texsize[0] = MAX2(texsize[0], 17); + texsize[1] = MAX2(texsize[1], 17); + } + else { + texsize[0] = MAX2(texsize[0], 2); + texsize[1] = MAX2(texsize[1], 2); + } + + effects->downsamp_texel_size[i][0] = 1.0f / (float)texsize[0]; + effects->downsamp_texel_size[i][1] = 1.0f / (float)texsize[1]; + + DRWFboTexture tex_bloom = {&txl->bloom_downsample[i], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}; + DRW_framebuffer_init(&fbl->bloom_down_fb[i], &draw_engine_eevee_type, + (int)texsize[0], (int)texsize[1], + &tex_bloom, 1); + } + + /* Upsample buffers */ + copy_v2_v2_int(texsize, blitsize); + for (int i = 0; i < effects->bloom_iteration_ct - 1; ++i) { + texsize[0] /= 2; texsize[1] /= 2; + + if (GPU_type_matches(GPU_DEVICE_AMD_VEGA, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) { + texsize[0] = MAX2(texsize[0], 17); + texsize[1] = MAX2(texsize[1], 17); + } + else { + texsize[0] = MAX2(texsize[0], 2); + texsize[1] = MAX2(texsize[1], 2); + } + + DRWFboTexture tex_bloom = {&txl->bloom_upsample[i], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}; + DRW_framebuffer_init(&fbl->bloom_accum_fb[i], &draw_engine_eevee_type, + (int)texsize[0], (int)texsize[1], + &tex_bloom, 1); + } + + return EFFECT_BLOOM | EFFECT_POST_BUFFER; + } + + /* Cleanup to release memory */ + DRW_TEXTURE_FREE_SAFE(txl->bloom_blit); + DRW_FRAMEBUFFER_FREE_SAFE(fbl->bloom_blit_fb); + + /* Bloom and dof share this buffer. This + * tells dof to reconfigure it's framebuffer. */ + if (txl->bloom_downsample[0] != NULL) { + DRW_FRAMEBUFFER_FREE_SAFE(fbl->dof_down_fb); + } + + for (int i = 0; i < MAX_BLOOM_STEP - 1; ++i) { + DRW_TEXTURE_FREE_SAFE(txl->bloom_downsample[i]); + DRW_TEXTURE_FREE_SAFE(txl->bloom_upsample[i]); + DRW_FRAMEBUFFER_FREE_SAFE(fbl->bloom_down_fb[i]); + DRW_FRAMEBUFFER_FREE_SAFE(fbl->bloom_accum_fb[i]); + } + + return 0; +} + +static DRWShadingGroup *eevee_create_bloom_pass(const char *name, EEVEE_EffectsInfo *effects, struct GPUShader *sh, DRWPass **pass, bool upsample) +{ + struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get(); + + *pass = DRW_pass_create(name, DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, *pass); + DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_uniform_buffer(grp, "sourceBuffer", &effects->unf_source_buffer); + DRW_shgroup_uniform_vec2(grp, "sourceBufferTexelSize", effects->unf_source_texel_size, 1); + if (upsample) { + DRW_shgroup_uniform_buffer(grp, "baseBuffer", &effects->unf_base_buffer); + DRW_shgroup_uniform_float(grp, "sampleScale", &effects->bloom_sample_scale, 1); + } + + return grp; +} + +void EEVEE_bloom_cache_init(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + + if ((effects->enabled_effects & EFFECT_BLOOM) != 0) { + /** Bloom algorithm + * + * Overview : + * - Downsample the color buffer doing a small blur during each step. + * - Accumulate bloom color using previously downsampled color buffers + * and do an upsample blur for each new accumulated layer. + * - Finally add accumulation buffer onto the source color buffer. + * + * [1/1] is original copy resolution (can be half or quater res for performance) + * + * [DOWNSAMPLE CHAIN] [UPSAMPLE CHAIN] + * + * Source Color ── [Blit] ──> Bright Color Extract [1/1] Final Color + * | Λ + * [Downsample First] Source Color ─> + [Resolve] + * v | + * Color Downsampled [1/2] ────────────> + Accumulation Buffer [1/2] + * | Λ + * ─── ─── + * Repeat Repeat + * ─── ─── + * v | + * Color Downsampled [1/N-1] ──────────> + Accumulation Buffer [1/N-1] + * | Λ + * [Downsample] [Upsample] + * v | + * Color Downsampled [1/N] ─────────────────────────┘ + **/ + DRWShadingGroup *grp; + const bool use_highres = true; + const bool use_antiflicker = true; + eevee_create_bloom_pass("Bloom Downsample First", effects, e_data.bloom_downsample_sh[use_antiflicker], &psl->bloom_downsample_first, false); + eevee_create_bloom_pass("Bloom Downsample", effects, e_data.bloom_downsample_sh[0], &psl->bloom_downsample, false); + eevee_create_bloom_pass("Bloom Upsample", effects, e_data.bloom_upsample_sh[use_highres], &psl->bloom_upsample, true); + + grp = eevee_create_bloom_pass("Bloom Blit", effects, e_data.bloom_blit_sh[use_antiflicker], &psl->bloom_blit, false); + DRW_shgroup_uniform_vec4(grp, "curveThreshold", effects->bloom_curve_threshold, 1); + DRW_shgroup_uniform_float(grp, "clampIntensity", &effects->bloom_clamp, 1); + + grp = eevee_create_bloom_pass("Bloom Resolve", effects, e_data.bloom_resolve_sh[use_highres], &psl->bloom_resolve, true); + DRW_shgroup_uniform_vec3(grp, "bloomColor", effects->bloom_color, 1); + } +} + +void EEVEE_bloom_draw(EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + + /* Bloom */ + if ((effects->enabled_effects & EFFECT_BLOOM) != 0) { + struct GPUTexture *last; + + /* Extract bright pixels */ + copy_v2_v2(effects->unf_source_texel_size, effects->source_texel_size); + effects->unf_source_buffer = effects->source_buffer; + + DRW_framebuffer_bind(fbl->bloom_blit_fb); + DRW_draw_pass(psl->bloom_blit); + + /* Downsample */ + copy_v2_v2(effects->unf_source_texel_size, effects->blit_texel_size); + effects->unf_source_buffer = txl->bloom_blit; + + DRW_framebuffer_bind(fbl->bloom_down_fb[0]); + DRW_draw_pass(psl->bloom_downsample_first); + + last = txl->bloom_downsample[0]; + + for (int i = 1; i < effects->bloom_iteration_ct; ++i) { + copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[i - 1]); + effects->unf_source_buffer = last; + + DRW_framebuffer_bind(fbl->bloom_down_fb[i]); + DRW_draw_pass(psl->bloom_downsample); + + /* Used in next loop */ + last = txl->bloom_downsample[i]; + } + + /* Upsample and accumulate */ + for (int i = effects->bloom_iteration_ct - 2; i >= 0; --i) { + copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[i]); + effects->unf_source_buffer = txl->bloom_downsample[i]; + effects->unf_base_buffer = last; + + DRW_framebuffer_bind(fbl->bloom_accum_fb[i]); + DRW_draw_pass(psl->bloom_upsample); + + last = txl->bloom_upsample[i]; + } + + /* Resolve */ + copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[0]); + effects->unf_source_buffer = last; + effects->unf_base_buffer = effects->source_buffer; + + DRW_framebuffer_bind(effects->target_buffer); + DRW_draw_pass(psl->bloom_resolve); + SWAP_BUFFERS(); + } +} + +void EEVEE_bloom_free(void) +{ + for (int i = 0; i < 2; ++i) { + DRW_SHADER_FREE_SAFE(e_data.bloom_blit_sh[i]); + DRW_SHADER_FREE_SAFE(e_data.bloom_downsample_sh[i]); + DRW_SHADER_FREE_SAFE(e_data.bloom_upsample_sh[i]); + DRW_SHADER_FREE_SAFE(e_data.bloom_resolve_sh[i]); + } +} diff --git a/source/blender/draw/engines/eevee/eevee_depth_of_field.c b/source/blender/draw/engines/eevee/eevee_depth_of_field.c new file mode 100644 index 00000000000..c5836c75406 --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c @@ -0,0 +1,283 @@ +/* + * 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 + * + */ + +/* Depth of field post process effect + */ + +/** \file eevee_depth_of_field.c + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "DNA_anim_types.h" +#include "DNA_camera_types.h" +#include "DNA_object_force.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" +#include "DNA_world_types.h" + +#include "BKE_global.h" /* for G.debug_value */ +#include "BKE_camera.h" +#include "BKE_mesh.h" +#include "BKE_object.h" +#include "BKE_animsys.h" +#include "BKE_screen.h" + +#include "ED_screen.h" + +#include "DEG_depsgraph.h" + +#include "BLI_dynstr.h" +#include "BLI_rand.h" + +#include "eevee_private.h" +#include "GPU_extensions.h" +#include "GPU_framebuffer.h" +#include "GPU_texture.h" + +static struct { + /* Depth Of Field */ + struct GPUShader *dof_downsample_sh; + struct GPUShader *dof_scatter_sh; + struct GPUShader *dof_resolve_sh; +} e_data = {NULL}; /* Engine data */ + +extern char datatoc_effect_dof_vert_glsl[]; +extern char datatoc_effect_dof_geom_glsl[]; +extern char datatoc_effect_dof_frag_glsl[]; + +static void eevee_create_shader_depth_of_field(void) +{ + 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"); +} + +int EEVEE_depth_of_field_init(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_EffectsInfo *effects = stl->effects; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + SceneLayer *scene_layer = draw_ctx->scene_layer; + IDProperty *props = BKE_scene_layer_engine_evaluated_get(scene_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); + + if (BKE_collection_engine_property_value_get_bool(props, "dof_enable")) { + Scene *scene = draw_ctx->scene; + View3D *v3d = draw_ctx->v3d; + RegionView3D *rv3d = draw_ctx->rv3d; + + if (!e_data.dof_downsample_sh) { + eevee_create_shader_depth_of_field(); + } + + if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + const float *viewport_size = DRW_viewport_size_get(); + 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}; + + /* Reuse buffer from Bloom if available */ + /* WATCH IT : must have the same size */ + struct GPUTexture **dof_down_near; + + if ((effects->enabled_effects & EFFECT_BLOOM) != 0) { + dof_down_near = &txl->bloom_downsample[0]; + } + else { + dof_down_near = &txl->dof_down_near; + } + + /* Setup buffers */ + DRWFboTexture tex_down[3] = {{dof_down_near, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, /* filter to not interfeer with bloom */ + {&txl->dof_down_far, DRW_TEX_RGB_11_11_10, 0}, + {&txl->dof_coc, DRW_TEX_RG_16, 0}}; + DRW_framebuffer_init(&fbl->dof_down_fb, &draw_engine_eevee_type, buffer_size[0], buffer_size[1], tex_down, 3); + + DRWFboTexture tex_scatter_far = {&txl->dof_far_blur, DRW_TEX_RGBA_16, DRW_TEX_FILTER}; + DRW_framebuffer_init(&fbl->dof_scatter_far_fb, &draw_engine_eevee_type, buffer_size[0], buffer_size[1], &tex_scatter_far, 1); + + DRWFboTexture tex_scatter_near = {&txl->dof_near_blur, DRW_TEX_RGBA_16, DRW_TEX_FILTER}; + DRW_framebuffer_init(&fbl->dof_scatter_near_fb, &draw_engine_eevee_type, 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 = cam->gpu_dof.rotation; + float ratio = 1.0f / cam->gpu_dof.ratio; + 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] / (rv3d->viewcamtexcofac[0] * sensor_scaled); + effects->dof_bokeh[0] = blades; + effects->dof_bokeh[1] = rotation; + effects->dof_bokeh[2] = ratio; + effects->dof_bokeh[3] = BKE_collection_engine_property_value_get_float(props, "bokeh_max_size"); + + return EFFECT_DOF | EFFECT_POST_BUFFER; + } + } + + /* Cleanup to release memory */ + DRW_TEXTURE_FREE_SAFE(txl->dof_down_near); + DRW_TEXTURE_FREE_SAFE(txl->dof_down_far); + DRW_TEXTURE_FREE_SAFE(txl->dof_coc); + DRW_TEXTURE_FREE_SAFE(txl->dof_far_blur); + DRW_TEXTURE_FREE_SAFE(txl->dof_near_blur); + DRW_FRAMEBUFFER_FREE_SAFE(fbl->dof_down_fb); + DRW_FRAMEBUFFER_FREE_SAFE(fbl->dof_scatter_far_fb); + DRW_FRAMEBUFFER_FREE_SAFE(fbl->dof_scatter_near_fb); + + return 0; +} + +void EEVEE_depth_of_field_cache_init(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_EffectsInfo *effects = stl->effects; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + + if ((effects->enabled_effects & EFFECT_DOF) != 0) { + /** 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; + struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get(); + + 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); + DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); + 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); + DRW_shgroup_uniform_buffer(grp, "cocBuffer", &txl->dof_coc); + DRW_shgroup_uniform_vec2(grp, "layerSelection", effects->dof_layer_select, 1); + DRW_shgroup_uniform_vec4(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); + DRW_shgroup_uniform_buffer(grp, "nearBuffer", &txl->dof_near_blur); + DRW_shgroup_uniform_buffer(grp, "farBuffer", &txl->dof_far_blur); + DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); + 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); + } +} + +void EEVEE_depth_of_field_draw(EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + + /* 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 */ + if ((effects->enabled_effects & EFFECT_BLOOM) != 0) { + /* Reuse bloom half res buffer */ + effects->unf_source_buffer = txl->bloom_downsample[0]; + } + else { + 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(); + } +} + +void EEVEE_depth_of_field_free(void) +{ + 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); +} diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index f5e47cb0a9d..d535014212d 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -28,51 +28,12 @@ #include "DRW_render.h" -#include "DNA_anim_types.h" -#include "DNA_camera_types.h" -#include "DNA_object_force.h" -#include "DNA_screen_types.h" -#include "DNA_smoke_types.h" -#include "DNA_view3d_types.h" -#include "DNA_world_types.h" - #include "BKE_global.h" /* for G.debug_value */ -#include "BKE_camera.h" -#include "BKE_modifier.h" -#include "BKE_mesh.h" -#include "BKE_object.h" -#include "BKE_animsys.h" -#include "BKE_screen.h" - -#include "ED_screen.h" - -#include "DEG_depsgraph.h" - -#include "BLI_dynstr.h" -#include "BLI_rand.h" #include "eevee_private.h" -#include "GPU_draw.h" -#include "GPU_extensions.h" -#include "GPU_framebuffer.h" #include "GPU_texture.h" -typedef struct EEVEE_LightProbeData { - short probe_id, shadow_id; -} EEVEE_LightProbeData; - -/* SSR shader variations */ -enum { - SSR_SAMPLES = (1 << 0) | (1 << 1), - SSR_RESOLVE = (1 << 2), - SSR_FULL_TRACE = (1 << 3), - SSR_MAX_SHADER = (1 << 4), -}; - static struct { - char *volumetric_common_lib; - char *volumetric_common_lamps_lib; - /* Downsample Depth */ struct GPUShader *minz_downlevel_sh; struct GPUShader *maxz_downlevel_sh; @@ -83,176 +44,49 @@ static struct { struct GPUShader *minz_copydepth_sh; struct GPUShader *maxz_copydepth_sh; - /* Motion Blur */ - struct GPUShader *motion_blur_sh; - - /* Bloom */ - struct GPUShader *bloom_blit_sh[2]; - struct GPUShader *bloom_downsample_sh[2]; - 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; - - /* Volumetric */ - struct GPUShader *volumetric_clear_sh; - struct GPUShader *volumetric_scatter_sh; - struct GPUShader *volumetric_integration_sh; - struct GPUShader *volumetric_resolve_sh; - - /* Screen Space Reflection */ - struct GPUShader *ssr_sh[SSR_MAX_SHADER]; - /* Simple Downsample */ struct GPUShader *downsample_sh; struct GPUShader *downsample_cube_sh; - /* Ground Truth Ambient Occlusion */ - struct GPUShader *gtao_sh; - struct GPUShader *gtao_debug_sh; - - /* Temporal Anti Aliasing */ - struct GPUShader *taa_resolve_sh; - /* Theses are just references, not actually allocated */ struct GPUTexture *depth_src; struct GPUTexture *color_src; - /* List of all smoke domains rendered within this frame. */ - ListBase smoke_domains; - int depth_src_layer; float cube_texel_size; } e_data = {NULL}; /* Engine data */ -extern char datatoc_ambient_occlusion_lib_glsl[]; -extern char datatoc_bsdf_common_lib_glsl[]; -extern char datatoc_bsdf_direct_lib_glsl[]; -extern char datatoc_bsdf_sampling_lib_glsl[]; -extern char datatoc_octahedron_lib_glsl[]; -extern char datatoc_effect_temporal_aa_glsl[]; -extern char datatoc_effect_ssr_frag_glsl[]; extern char datatoc_effect_minmaxz_frag_glsl[]; -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_effect_downsample_frag_glsl[]; extern char datatoc_effect_downsample_cube_frag_glsl[]; -extern char datatoc_effect_gtao_frag_glsl[]; -extern char datatoc_irradiance_lib_glsl[]; -extern char datatoc_lamps_lib_glsl[]; -extern char datatoc_lightprobe_lib_glsl[]; extern char datatoc_lightprobe_vert_glsl[]; extern char datatoc_lightprobe_geom_glsl[]; -extern char datatoc_raytrace_lib_glsl[]; -extern char datatoc_tonemap_frag_glsl[]; -extern char datatoc_volumetric_frag_glsl[]; -extern char datatoc_volumetric_geom_glsl[]; -extern char datatoc_volumetric_vert_glsl[]; -extern char datatoc_volumetric_resolve_frag_glsl[]; -extern char datatoc_volumetric_scatter_frag_glsl[]; -extern char datatoc_volumetric_integration_frag_glsl[]; -extern char datatoc_volumetric_lib_glsl[]; -extern char datatoc_gpu_shader_fullscreen_vert_glsl[]; - -static void eevee_motion_blur_camera_get_matrix_at_time( - const bContext *C, Scene *scene, ARegion *ar, RegionView3D *rv3d, View3D *v3d, Object *camera, float time, float r_mat[4][4]) -{ - EvaluationContext eval_ctx; - float obmat[4][4]; - - /* HACK */ - Object cam_cpy; Camera camdata_cpy; - memcpy(&cam_cpy, camera, sizeof(cam_cpy)); - memcpy(&camdata_cpy, camera->data, sizeof(camdata_cpy)); - cam_cpy.data = &camdata_cpy; - - CTX_data_eval_ctx(C, &eval_ctx); - - /* Past matrix */ - /* FIXME : This is a temporal solution that does not take care of parent animations */ - /* Recalc Anim manualy */ - BKE_animsys_evaluate_animdata(scene, &cam_cpy.id, cam_cpy.adt, time, ADT_RECALC_ALL); - BKE_animsys_evaluate_animdata(scene, &camdata_cpy.id, camdata_cpy.adt, time, ADT_RECALC_ALL); - BKE_object_where_is_calc_time(&eval_ctx, scene, &cam_cpy, time); - - /* Compute winmat */ - CameraParams params; - BKE_camera_params_init(¶ms); - - /* copy of BKE_camera_params_from_view3d */ - { - params.lens = v3d->lens; - params.clipsta = v3d->near; - params.clipend = v3d->far; - - /* camera view */ - BKE_camera_params_from_object(¶ms, &cam_cpy); - - params.zoom = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom); - params.offsetx = 2.0f * rv3d->camdx * params.zoom; - params.offsety = 2.0f * rv3d->camdy * params.zoom; - - params.shiftx *= params.zoom; - params.shifty *= params.zoom; - - params.zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB / params.zoom; - } - - BKE_camera_params_compute_viewplane(¶ms, ar->winx, ar->winy, 1.0f, 1.0f); - BKE_camera_params_compute_matrix(¶ms); - - /* FIXME Should be done per view (MULTIVIEW) */ - normalize_m4_m4(obmat, cam_cpy.obmat); - invert_m4(obmat); - mul_m4_m4m4(r_mat, params.winmat, obmat); -} - -static struct GPUShader *eevee_effects_ssr_shader_get(int options) +static void eevee_create_shader_downsample(void) { - if (e_data.ssr_sh[options] == NULL) { - DynStr *ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_ambient_occlusion_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_raytrace_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_effect_ssr_frag_glsl); - char *ssr_shader_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); - - int samples = (SSR_SAMPLES & options) + 1; - - DynStr *ds_defines = BLI_dynstr_new(); - BLI_dynstr_appendf(ds_defines, SHADER_DEFINES); - BLI_dynstr_appendf(ds_defines, "#define RAY_COUNT %d\n", samples); - if (options & SSR_RESOLVE) { - BLI_dynstr_appendf(ds_defines, "#define STEP_RESOLVE\n"); - } - else { - BLI_dynstr_appendf(ds_defines, "#define STEP_RAYTRACE\n"); - BLI_dynstr_appendf(ds_defines, "#define PLANAR_PROBE_RAYTRACE\n"); - } - if (options & SSR_FULL_TRACE) { - BLI_dynstr_appendf(ds_defines, "#define FULLRES\n"); - } - char *ssr_define_str = BLI_dynstr_get_cstring(ds_defines); - BLI_dynstr_free(ds_defines); - - e_data.ssr_sh[options] = DRW_shader_create_fullscreen(ssr_shader_str, ssr_define_str); - - MEM_freeN(ssr_shader_str); - MEM_freeN(ssr_define_str); - } - - return e_data.ssr_sh[options]; + e_data.downsample_sh = DRW_shader_create_fullscreen(datatoc_effect_downsample_frag_glsl, NULL); + e_data.downsample_cube_sh = DRW_shader_create(datatoc_lightprobe_vert_glsl, + datatoc_lightprobe_geom_glsl, + datatoc_effect_downsample_cube_frag_glsl, NULL); + + e_data.minz_downlevel_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n"); + e_data.maxz_downlevel_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n"); + e_data.minz_downdepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n" + "#define INPUT_DEPTH\n"); + e_data.maxz_downdepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n" + "#define INPUT_DEPTH\n"); + e_data.minz_downdepth_layer_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n" + "#define LAYERED\n" + "#define INPUT_DEPTH\n"); + e_data.maxz_downdepth_layer_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n" + "#define LAYERED\n" + "#define INPUT_DEPTH\n"); + e_data.minz_copydepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n" + "#define INPUT_DEPTH\n" + "#define COPY_DEPTH\n"); + e_data.maxz_copydepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n" + "#define INPUT_DEPTH\n" + "#define COPY_DEPTH\n"); } void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) @@ -262,119 +96,11 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects; - const DRWContextState *draw_ctx = DRW_context_state_get(); - SceneLayer *scene_layer = draw_ctx->scene_layer; - Scene *scene = draw_ctx->scene; - View3D *v3d = draw_ctx->v3d; - RegionView3D *rv3d = draw_ctx->rv3d; - ARegion *ar = draw_ctx->ar; - IDProperty *props = BKE_scene_layer_engine_evaluated_get(scene_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); - const float *viewport_size = DRW_viewport_size_get(); - BLI_listbase_clear(&e_data.smoke_domains); - /* Shaders */ - if (!e_data.motion_blur_sh) { - DynStr *ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_ambient_occlusion_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_effect_gtao_frag_glsl); - char *frag_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); - - e_data.gtao_sh = DRW_shader_create_fullscreen(frag_str, NULL); - e_data.gtao_debug_sh = DRW_shader_create_fullscreen(frag_str, "#define DEBUG_AO\n"); - - MEM_freeN(frag_str); - - e_data.taa_resolve_sh = DRW_shader_create_fullscreen(datatoc_effect_temporal_aa_glsl, NULL); - - e_data.downsample_sh = DRW_shader_create_fullscreen(datatoc_effect_downsample_frag_glsl, NULL); - e_data.downsample_cube_sh = DRW_shader_create(datatoc_lightprobe_vert_glsl, - datatoc_lightprobe_geom_glsl, - datatoc_effect_downsample_cube_frag_glsl, NULL); - - ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_volumetric_lib_glsl); - e_data.volumetric_common_lib = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); - - ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_lamps_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_volumetric_lib_glsl); - e_data.volumetric_common_lamps_lib = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); - - e_data.volumetric_clear_sh = DRW_shader_create_with_lib(datatoc_volumetric_vert_glsl, - datatoc_volumetric_geom_glsl, - datatoc_volumetric_frag_glsl, - e_data.volumetric_common_lib, - "#define VOLUMETRICS\n" - "#define CLEAR\n"); - e_data.volumetric_scatter_sh = DRW_shader_create_with_lib(datatoc_volumetric_vert_glsl, - datatoc_volumetric_geom_glsl, - datatoc_volumetric_scatter_frag_glsl, - e_data.volumetric_common_lamps_lib, - SHADER_DEFINES - "#define VOLUMETRICS\n" - "#define VOLUME_SHADOW\n"); - e_data.volumetric_integration_sh = DRW_shader_create_with_lib(datatoc_volumetric_vert_glsl, - datatoc_volumetric_geom_glsl, - datatoc_volumetric_integration_frag_glsl, - e_data.volumetric_common_lib, NULL); - e_data.volumetric_resolve_sh = DRW_shader_create_with_lib(datatoc_gpu_shader_fullscreen_vert_glsl, NULL, - datatoc_volumetric_resolve_frag_glsl, - e_data.volumetric_common_lib, NULL); - - e_data.minz_downlevel_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n"); - e_data.maxz_downlevel_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n"); - e_data.minz_downdepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n" - "#define INPUT_DEPTH\n"); - e_data.maxz_downdepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n" - "#define INPUT_DEPTH\n"); - e_data.minz_downdepth_layer_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n" - "#define LAYERED\n" - "#define INPUT_DEPTH\n"); - e_data.maxz_downdepth_layer_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n" - "#define LAYERED\n" - "#define INPUT_DEPTH\n"); - e_data.minz_copydepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MIN_PASS\n" - "#define INPUT_DEPTH\n" - "#define COPY_DEPTH\n"); - e_data.maxz_copydepth_sh = DRW_shader_create_fullscreen(datatoc_effect_minmaxz_frag_glsl, "#define MAX_PASS\n" - "#define INPUT_DEPTH\n" - "#define COPY_DEPTH\n"); - - e_data.motion_blur_sh = DRW_shader_create_fullscreen(datatoc_effect_motion_blur_frag_glsl, NULL); - - 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"); - - 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" - "#define HIGH_QUALITY\n"); - - e_data.bloom_downsample_sh[0] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_DOWNSAMPLE\n"); - e_data.bloom_downsample_sh[1] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_DOWNSAMPLE\n" - "#define HIGH_QUALITY\n"); - - e_data.bloom_upsample_sh[0] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_UPSAMPLE\n"); - e_data.bloom_upsample_sh[1] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_UPSAMPLE\n" - "#define HIGH_QUALITY\n"); - - e_data.bloom_resolve_sh[0] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_RESOLVE\n"); - e_data.bloom_resolve_sh[1] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_RESOLVE\n" - "#define HIGH_QUALITY\n"); + if (!e_data.downsample_sh) { + eevee_create_shader_downsample(); } if (!stl->effects) { @@ -383,537 +109,34 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) effects = stl->effects; - int enabled_effects = 0; - - if (BKE_collection_engine_property_value_get_bool(props, "motion_blur_enable") && (draw_ctx->evil_C != NULL)) { - /* Update Motion Blur Matrices */ - if (rv3d->persp == RV3D_CAMOB && v3d->camera) { - float persmat[4][4]; - float ctime = BKE_scene_frame_get(scene); - float delta = BKE_collection_engine_property_value_get_float(props, "motion_blur_shutter"); - - /* Current matrix */ - eevee_motion_blur_camera_get_matrix_at_time(draw_ctx->evil_C, scene, ar, rv3d, v3d, v3d->camera, ctime, effects->current_ndc_to_world); - - /* Viewport Matrix */ - DRW_viewport_matrix_get(persmat, DRW_MAT_PERS); - - /* Only continue if camera is not being keyed */ - if (compare_m4m4(persmat, effects->current_ndc_to_world, 0.0001f)) { - - /* Past matrix */ - eevee_motion_blur_camera_get_matrix_at_time(draw_ctx->evil_C, scene, ar, rv3d, v3d, v3d->camera, ctime - delta, effects->past_world_to_ndc); - -#if 0 /* for future high quality blur */ - /* Future matrix */ - eevee_motion_blur_camera_get_matrix_at_time(scene, ar, rv3d, v3d, v3d->camera, ctime + delta, effects->future_world_to_ndc); -#endif - invert_m4(effects->current_ndc_to_world); - - effects->motion_blur_samples = BKE_collection_engine_property_value_get_int(props, "motion_blur_samples"); - enabled_effects |= EFFECT_MOTION_BLUR; - } - } - } - - if (BKE_collection_engine_property_value_get_bool(props, "bloom_enable")) { - /* Bloom */ - int blitsize[2], texsize[2]; - - /* Blit Buffer */ - effects->source_texel_size[0] = 1.0f / viewport_size[0]; - effects->source_texel_size[1] = 1.0f / viewport_size[1]; - - blitsize[0] = (int)viewport_size[0]; - blitsize[1] = (int)viewport_size[1]; - - effects->blit_texel_size[0] = 1.0f / (float)blitsize[0]; - effects->blit_texel_size[1] = 1.0f / (float)blitsize[1]; - - DRWFboTexture tex_blit = {&txl->bloom_blit, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}; - DRW_framebuffer_init(&fbl->bloom_blit_fb, &draw_engine_eevee_type, - (int)blitsize[0], (int)blitsize[1], - &tex_blit, 1); - - /* Parameters */ - float threshold = BKE_collection_engine_property_value_get_float(props, "bloom_threshold"); - float knee = BKE_collection_engine_property_value_get_float(props, "bloom_knee"); - float intensity = BKE_collection_engine_property_value_get_float(props, "bloom_intensity"); - const float *color = BKE_collection_engine_property_value_get_float_array(props, "bloom_color"); - float radius = BKE_collection_engine_property_value_get_float(props, "bloom_radius"); - effects->bloom_clamp = BKE_collection_engine_property_value_get_float(props, "bloom_clamp"); - - /* determine the iteration count */ - const float minDim = (float)MIN2(blitsize[0], blitsize[1]); - const float maxIter = (radius - 8.0f) + log(minDim) / log(2); - const int maxIterInt = effects->bloom_iteration_ct = (int)maxIter; - - CLAMP(effects->bloom_iteration_ct, 1, MAX_BLOOM_STEP); - - effects->bloom_sample_scale = 0.5f + maxIter - (float)maxIterInt; - effects->bloom_curve_threshold[0] = threshold - knee; - effects->bloom_curve_threshold[1] = knee * 2.0f; - effects->bloom_curve_threshold[2] = 0.25f / max_ff(1e-5f, knee); - effects->bloom_curve_threshold[3] = threshold; - - mul_v3_v3fl(effects->bloom_color, color, intensity); - - /* Downsample buffers */ - copy_v2_v2_int(texsize, blitsize); - for (int i = 0; i < effects->bloom_iteration_ct; ++i) { - texsize[0] /= 2; texsize[1] /= 2; - - if (GPU_type_matches(GPU_DEVICE_AMD_VEGA, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) { - texsize[0] = MAX2(texsize[0], 17); - texsize[1] = MAX2(texsize[1], 17); - } - else { - texsize[0] = MAX2(texsize[0], 2); - texsize[1] = MAX2(texsize[1], 2); - } - - effects->downsamp_texel_size[i][0] = 1.0f / (float)texsize[0]; - effects->downsamp_texel_size[i][1] = 1.0f / (float)texsize[1]; - - DRWFboTexture tex_bloom = {&txl->bloom_downsample[i], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}; - DRW_framebuffer_init(&fbl->bloom_down_fb[i], &draw_engine_eevee_type, - (int)texsize[0], (int)texsize[1], - &tex_bloom, 1); - } - - /* Upsample buffers */ - copy_v2_v2_int(texsize, blitsize); - for (int i = 0; i < effects->bloom_iteration_ct - 1; ++i) { - texsize[0] /= 2; texsize[1] /= 2; - - if (GPU_type_matches(GPU_DEVICE_AMD_VEGA, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) { - texsize[0] = MAX2(texsize[0], 17); - texsize[1] = MAX2(texsize[1], 17); - } - else { - texsize[0] = MAX2(texsize[0], 2); - texsize[1] = MAX2(texsize[1], 2); - } - - DRWFboTexture tex_bloom = {&txl->bloom_upsample[i], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}; - DRW_framebuffer_init(&fbl->bloom_accum_fb[i], &draw_engine_eevee_type, - (int)texsize[0], (int)texsize[1], - &tex_bloom, 1); - } - - enabled_effects |= EFFECT_BLOOM; - } - - if (BKE_collection_engine_property_value_get_bool(props, "dof_enable")) { - /* 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}; - - struct GPUTexture **dof_down_near = &txl->dof_down_near; - bool fb_reset = false; - - /* Reuse buffer from Bloom if available */ - /* WATCH IT : must have the same size */ - if ((enabled_effects & EFFECT_BLOOM) != 0) { - dof_down_near = &txl->bloom_downsample[0]; /* should always exists */ - if ((effects->enabled_effects & EFFECT_BLOOM) == 0) { - fb_reset = true; - } - } - else if ((effects->enabled_effects & EFFECT_BLOOM) != 0) { - fb_reset = true; - } - - /* if framebuffer config must be changed */ - if (fb_reset && (fbl->dof_down_fb != NULL)) { - DRW_framebuffer_free(fbl->dof_down_fb); - fbl->dof_down_fb = NULL; - } - - /* Setup buffers */ - DRWFboTexture tex_down[3] = {{dof_down_near, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, /* filter to not interfeer with bloom */ - {&txl->dof_down_far, DRW_TEX_RGB_11_11_10, 0}, - {&txl->dof_coc, DRW_TEX_RG_16, 0}}; - DRW_framebuffer_init(&fbl->dof_down_fb, &draw_engine_eevee_type, buffer_size[0], buffer_size[1], tex_down, 3); - - DRWFboTexture tex_scatter_far = {&txl->dof_far_blur, DRW_TEX_RGBA_16, DRW_TEX_FILTER}; - DRW_framebuffer_init(&fbl->dof_scatter_far_fb, &draw_engine_eevee_type, buffer_size[0], buffer_size[1], &tex_scatter_far, 1); - - DRWFboTexture tex_scatter_near = {&txl->dof_near_blur, DRW_TEX_RGBA_16, DRW_TEX_FILTER}; - DRW_framebuffer_init(&fbl->dof_scatter_near_fb, &draw_engine_eevee_type, 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 = cam->gpu_dof.rotation; - float ratio = 1.0f / cam->gpu_dof.ratio; - 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] / (rv3d->viewcamtexcofac[0] * sensor_scaled); - effects->dof_bokeh[0] = blades; - effects->dof_bokeh[1] = rotation; - effects->dof_bokeh[2] = ratio; - effects->dof_bokeh[3] = BKE_collection_engine_property_value_get_float(props, "bokeh_max_size"); - - enabled_effects |= EFFECT_DOF; - } - } - - if (BKE_collection_engine_property_value_get_int(props, "taa_samples") != 1) { - float persmat[4][4], viewmat[4][4]; - - enabled_effects |= EFFECT_TAA | EFFECT_DOUBLE_BUFFER; - - /* Until we support reprojection, we need to make sure - * that the history buffer contains correct information. */ - bool view_is_valid = stl->g_data->valid_double_buffer; - - view_is_valid = view_is_valid && (stl->g_data->view_updated == false); - - effects->taa_total_sample = BKE_collection_engine_property_value_get_int(props, "taa_samples"); - MAX2(effects->taa_total_sample, 0); - - DRW_viewport_matrix_get(persmat, DRW_MAT_PERS); - DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW); - DRW_viewport_matrix_get(effects->overide_winmat, DRW_MAT_WIN); - view_is_valid = view_is_valid && compare_m4m4(persmat, effects->prev_drw_persmat, FLT_MIN); - copy_m4_m4(effects->prev_drw_persmat, persmat); - - /* Prevent ghosting from probe data. */ - view_is_valid = view_is_valid && (effects->prev_drw_support == DRW_state_draw_support()); - effects->prev_drw_support = DRW_state_draw_support(); - - if (view_is_valid && - ((effects->taa_total_sample == 0) || - (effects->taa_current_sample < effects->taa_total_sample))) - { - effects->taa_current_sample += 1; - - effects->taa_alpha = 1.0f / (float)(effects->taa_current_sample); - - double ht_point[2]; - double ht_offset[2] = {0.0, 0.0}; - unsigned int ht_primes[2] = {2, 3}; - - BLI_halton_2D(ht_primes, ht_offset, effects->taa_current_sample - 1, ht_point); - - window_translate_m4( - effects->overide_winmat, persmat, - ((float)(ht_point[0]) * 2.0f - 1.0f) / viewport_size[0], - ((float)(ht_point[1]) * 2.0f - 1.0f) / viewport_size[1]); - - mul_m4_m4m4(effects->overide_persmat, effects->overide_winmat, viewmat); - invert_m4_m4(effects->overide_persinv, effects->overide_persmat); - invert_m4_m4(effects->overide_wininv, effects->overide_winmat); - - DRW_viewport_matrix_override_set(effects->overide_persmat, DRW_MAT_PERS); - DRW_viewport_matrix_override_set(effects->overide_persinv, DRW_MAT_PERSINV); - DRW_viewport_matrix_override_set(effects->overide_winmat, DRW_MAT_WIN); - DRW_viewport_matrix_override_set(effects->overide_wininv, DRW_MAT_WININV); - } - else { - effects->taa_current_sample = 1; - } - - DRWFboTexture tex_double_buffer = {&txl->depth_double_buffer, DRW_TEX_DEPTH_24}; - - DRW_framebuffer_init(&fbl->depth_double_buffer_fb, &draw_engine_eevee_type, - (int)viewport_size[0], (int)viewport_size[1], - &tex_double_buffer, 1); - } - else { - /* Cleanup to release memory */ - DRW_TEXTURE_FREE_SAFE(txl->depth_double_buffer); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->depth_double_buffer_fb); - } - - effects->enabled_effects = enabled_effects; - - if (BKE_collection_engine_property_value_get_bool(props, "volumetric_enable")) { - - effects->enabled_effects |= EFFECT_VOLUMETRIC; - - if (sldata->volumetrics == NULL) { - sldata->volumetrics = MEM_callocN(sizeof(EEVEE_VolumetricsInfo), "EEVEE_VolumetricsInfo"); - } - - EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics; - - int tile_size = BKE_collection_engine_property_value_get_int(props, "volumetric_tile_size"); - - /* Find Froxel Texture resolution. */ - int froxel_tex_size[3]; - - froxel_tex_size[0] = (int)ceilf(fmaxf(1.0f, viewport_size[0] / (float)tile_size)); - froxel_tex_size[1] = (int)ceilf(fmaxf(1.0f, viewport_size[1] / (float)tile_size)); - froxel_tex_size[2] = max_ii(BKE_collection_engine_property_value_get_int(props, "volumetric_samples"), 1); - - volumetrics->volume_coord_scale[0] = viewport_size[0] / (float)(tile_size * froxel_tex_size[0]); - volumetrics->volume_coord_scale[1] = viewport_size[1] / (float)(tile_size * froxel_tex_size[1]); - - /* TODO compute snap to maxZBuffer for clustered rendering */ - - if ((volumetrics->froxel_tex_size[0] != froxel_tex_size[0]) || - (volumetrics->froxel_tex_size[1] != froxel_tex_size[1]) || - (volumetrics->froxel_tex_size[2] != froxel_tex_size[2])) - { - DRW_TEXTURE_FREE_SAFE(txl->volume_prop_scattering); - DRW_TEXTURE_FREE_SAFE(txl->volume_prop_extinction); - DRW_TEXTURE_FREE_SAFE(txl->volume_prop_emission); - DRW_TEXTURE_FREE_SAFE(txl->volume_prop_phase); - DRW_TEXTURE_FREE_SAFE(txl->volume_scatter); - DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance); - DRW_TEXTURE_FREE_SAFE(txl->volume_scatter_history); - DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance_history); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb); - volumetrics->froxel_tex_size[0] = froxel_tex_size[0]; - volumetrics->froxel_tex_size[1] = froxel_tex_size[1]; - volumetrics->froxel_tex_size[2] = froxel_tex_size[2]; - - volumetrics->inv_tex_size[0] = 1.0f / (float)(volumetrics->froxel_tex_size[0]); - volumetrics->inv_tex_size[1] = 1.0f / (float)(volumetrics->froxel_tex_size[1]); - volumetrics->inv_tex_size[2] = 1.0f / (float)(volumetrics->froxel_tex_size[2]); - } - - /* Like frostbite's paper, 5% blend of the new frame. */ - volumetrics->history_alpha = (txl->volume_prop_scattering == NULL) ? 0.0f : 0.95f; - - if (txl->volume_prop_scattering == NULL) { - /* Volume properties: We evaluate all volumetric objects - * and store their final properties into each froxel */ - txl->volume_prop_scattering = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); - txl->volume_prop_extinction = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); - txl->volume_prop_emission = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); - txl->volume_prop_phase = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RG_16, DRW_TEX_FILTER, NULL); - - /* Volume scattering: We compute for each froxel the - * Scattered light towards the view. We also resolve temporal - * super sampling during this stage. */ - txl->volume_scatter = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); - txl->volume_transmittance = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); - - /* Final integration: We compute for each froxel the - * amount of scattered light and extinction coef at this - * given depth. We use theses textures as double buffer - * for the volumetric history. */ - txl->volume_scatter_history = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); - txl->volume_transmittance_history = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); - } - - /* Temporal Super sampling jitter */ - double ht_point[3]; - double ht_offset[3] = {0.0, 0.0}; - unsigned int ht_primes[3] = {3, 7, 2}; - unsigned int current_sample = 0; - - /* If TAA is in use do not use the history buffer. */ - bool do_taa = ((effects->enabled_effects & EFFECT_TAA) != 0); - - if (draw_ctx->evil_C != NULL) { - struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); - do_taa = do_taa && (ED_screen_animation_no_scrub(wm) == NULL); - } - - if (do_taa) { - volumetrics->history_alpha = 0.0f; - current_sample = effects->taa_current_sample - 1; - effects->volume_current_sample = -1; - } - else { - const unsigned int max_sample = (ht_primes[0] * ht_primes[1] * ht_primes[2]); - current_sample = effects->volume_current_sample = (effects->volume_current_sample + 1) % max_sample; - if (current_sample != max_sample - 1) { - DRW_viewport_request_redraw(); - } - } - BLI_halton_3D(ht_primes, ht_offset, current_sample, ht_point); - - volumetrics->jitter[0] = (float)ht_point[0]; - volumetrics->jitter[1] = (float)ht_point[1]; - volumetrics->jitter[2] = (float)ht_point[2]; - - /* Framebuffer setup */ - DRWFboTexture tex_vol[4] = {{&txl->volume_prop_scattering, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, - {&txl->volume_prop_extinction, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, - {&txl->volume_prop_emission, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, - {&txl->volume_prop_phase, DRW_TEX_RG_16, DRW_TEX_FILTER}}; - - DRW_framebuffer_init(&fbl->volumetric_fb, &draw_engine_eevee_type, - (int)froxel_tex_size[0], (int)froxel_tex_size[1], - tex_vol, 4); - - DRWFboTexture tex_vol_scat[2] = {{&txl->volume_scatter, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, - {&txl->volume_transmittance, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}}; - - DRW_framebuffer_init(&fbl->volumetric_scat_fb, &draw_engine_eevee_type, - (int)froxel_tex_size[0], (int)froxel_tex_size[1], - tex_vol_scat, 2); - - DRWFboTexture tex_vol_integ[2] = {{&txl->volume_scatter_history, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, - {&txl->volume_transmittance_history, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}}; - - DRW_framebuffer_init(&fbl->volumetric_integ_fb, &draw_engine_eevee_type, - (int)froxel_tex_size[0], (int)froxel_tex_size[1], - tex_vol_integ, 2); - - volumetrics->integration_start = BKE_collection_engine_property_value_get_float(props, "volumetric_start"); - volumetrics->integration_end = BKE_collection_engine_property_value_get_float(props, "volumetric_end"); - volumetrics->sample_distribution = 4.0f * (1.00001f - BKE_collection_engine_property_value_get_float(props, "volumetric_sample_distribution")); - volumetrics->use_volume_shadows = BKE_collection_engine_property_value_get_bool(props, "volumetric_shadows"); - volumetrics->light_clamp = BKE_collection_engine_property_value_get_float(props, "volumetric_light_clamp"); - - if (volumetrics->use_volume_shadows) { - volumetrics->shadow_step_count = (float)BKE_collection_engine_property_value_get_int(props, "volumetric_shadow_samples"); - } - else { - volumetrics->shadow_step_count = 0; - } - - if (DRW_viewport_is_persp_get()) { - const float clip_start = stl->g_data->viewvecs[0][2]; - /* Negate */ - float near = volumetrics->integration_start = min_ff(-volumetrics->integration_start, clip_start - 1e-4f); - float far = volumetrics->integration_end = min_ff(-volumetrics->integration_end, near - 1e-4f); - - volumetrics->depth_param[0] = (far - near * exp2(1.0f / volumetrics->sample_distribution)) / (far - near); - volumetrics->depth_param[1] = (1.0f - volumetrics->depth_param[0]) / near; - volumetrics->depth_param[2] = volumetrics->sample_distribution; - } - else { - const float clip_start = stl->g_data->viewvecs[0][2]; - const float clip_end = stl->g_data->viewvecs[1][2]; - volumetrics->integration_start = min_ff(volumetrics->integration_end, clip_start); - volumetrics->integration_end = max_ff(-volumetrics->integration_end, clip_end); - - volumetrics->depth_param[0] = volumetrics->integration_start; - volumetrics->depth_param[1] = volumetrics->integration_end; - volumetrics->depth_param[2] = 1.0f / (volumetrics->integration_end - volumetrics->integration_start); - } - - /* Disable clamp if equal to 0. */ - if (volumetrics->light_clamp == 0.0) { - volumetrics->light_clamp = FLT_MAX; - } - - volumetrics->use_lights = BKE_collection_engine_property_value_get_bool(props, "volumetric_lights"); - } - else { - /* Cleanup */ - DRW_TEXTURE_FREE_SAFE(txl->volume_prop_scattering); - DRW_TEXTURE_FREE_SAFE(txl->volume_prop_extinction); - DRW_TEXTURE_FREE_SAFE(txl->volume_prop_emission); - DRW_TEXTURE_FREE_SAFE(txl->volume_prop_phase); - DRW_TEXTURE_FREE_SAFE(txl->volume_scatter); - DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance); - DRW_TEXTURE_FREE_SAFE(txl->volume_scatter_history); - DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance_history); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb); - } - - /* Only allocate if at least one effect is activated */ - if (effects->enabled_effects != 0) { - /* Ping Pong buffer */ + effects->enabled_effects = 0; + effects->enabled_effects |= EEVEE_motion_blur_init(sldata, vedata); + effects->enabled_effects |= EEVEE_bloom_init(sldata, vedata); + effects->enabled_effects |= EEVEE_depth_of_field_init(sldata, vedata); + effects->enabled_effects |= EEVEE_temporal_sampling_init(sldata, vedata); + effects->enabled_effects |= EEVEE_occlusion_init(sldata, vedata); + effects->enabled_effects |= EEVEE_screen_raytrace_init(sldata, vedata); + effects->enabled_effects |= EEVEE_volumes_init(sldata, vedata); + + /** + * Ping Pong buffer + */ + if ((effects->enabled_effects & EFFECT_POST_BUFFER) != 0) { DRWFboTexture tex = {&txl->color_post, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}; - DRW_framebuffer_init(&fbl->effect_fb, &draw_engine_eevee_type, (int)viewport_size[0], (int)viewport_size[1], &tex, 1); } - - if (BKE_collection_engine_property_value_get_bool(props, "gtao_enable")) { - /* Ambient Occlusion*/ - effects->enabled_effects |= EFFECT_GTAO; - - effects->ao_dist = BKE_collection_engine_property_value_get_float(props, "gtao_distance"); - effects->ao_factor = BKE_collection_engine_property_value_get_float(props, "gtao_factor"); - effects->ao_quality = 1.0f - BKE_collection_engine_property_value_get_float(props, "gtao_quality"); - effects->ao_samples = BKE_collection_engine_property_value_get_int(props, "gtao_samples"); - effects->ao_samples_inv = 1.0f / effects->ao_samples; - - effects->ao_settings = 1.0; /* USE_AO */ - if (BKE_collection_engine_property_value_get_bool(props, "gtao_use_bent_normals")) { - effects->ao_settings += 2.0; /* USE_BENT_NORMAL */ - } - if (BKE_collection_engine_property_value_get_bool(props, "gtao_denoise")) { - effects->ao_settings += 4.0; /* USE_DENOISE */ - } - - effects->ao_bounce_fac = (float)BKE_collection_engine_property_value_get_bool(props, "gtao_bounce"); - - effects->ao_texsize[0] = ((int)viewport_size[0]); - effects->ao_texsize[1] = ((int)viewport_size[1]); - - /* Round up to multiple of 2 */ - if ((effects->ao_texsize[0] & 0x1) != 0) { - effects->ao_texsize[0] += 1; - } - if ((effects->ao_texsize[1] & 0x1) != 0) { - effects->ao_texsize[1] += 1; - } - - CLAMP(effects->ao_samples, 1, 32); - - if (effects->hori_tex_layers != effects->ao_samples) { - DRW_TEXTURE_FREE_SAFE(txl->gtao_horizons); - } - - if (txl->gtao_horizons == NULL) { - effects->hori_tex_layers = effects->ao_samples; - txl->gtao_horizons = DRW_texture_create_2D_array((int)viewport_size[0], (int)viewport_size[1], effects->hori_tex_layers, DRW_TEX_RG_8, 0, NULL); - } - - DRWFboTexture tex = {&txl->gtao_horizons, DRW_TEX_RG_8, 0}; - - DRW_framebuffer_init(&fbl->gtao_fb, &draw_engine_eevee_type, - effects->ao_texsize[0], effects->ao_texsize[1], - &tex, 1); - - if (G.debug_value == 6) { - DRWFboTexture tex_debug = {&stl->g_data->gtao_horizons_debug, DRW_TEX_RGBA_8, DRW_TEX_TEMP}; - - DRW_framebuffer_init(&fbl->gtao_debug_fb, &draw_engine_eevee_type, - (int)viewport_size[0], (int)viewport_size[1], - &tex_debug, 1); - } - } else { - /* Cleanup */ - DRW_TEXTURE_FREE_SAFE(txl->gtao_horizons); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->gtao_fb); - effects->ao_settings = 0.0f; + /* Cleanup to release memory */ + DRW_TEXTURE_FREE_SAFE(txl->color_post); + DRW_FRAMEBUFFER_FREE_SAFE(fbl->effect_fb); } - /* MinMax Pyramid */ + /** + * MinMax Pyramid + */ DRWFboTexture texmin = {&stl->g_data->minzbuffer, DRW_TEX_DEPTH_24, DRW_TEX_MIPMAP | DRW_TEX_TEMP}; - DRW_framebuffer_init(&fbl->downsample_fb, &draw_engine_eevee_type, (int)viewport_size[0] / 2, (int)viewport_size[1] / 2, &texmin, 1); @@ -923,7 +146,9 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) txl->maxzbuffer = DRW_texture_create_2D((int)viewport_size[0] / 2, (int)viewport_size[1] / 2, DRW_TEX_DEPTH_24, DRW_TEX_MIPMAP, NULL); } - /* Compute Mipmap texel alignement. */ + /** + * Compute Mipmap texel alignement. + */ for (int i = 0; i < 10; ++i) { float mip_size[2] = {viewport_size[0], viewport_size[1]}; for (int j = 0; j < i; ++j) { @@ -934,78 +159,11 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) stl->g_data->mip_ratio[i][1] = viewport_size[1] / (mip_size[1] * powf(2.0f, floorf(log2f(floorf(viewport_size[1] / mip_size[1]))))); } - /* Compute pixel size, (shared with contact shadows) */ - copy_v2_v2(effects->ssr_pixelsize, viewport_size); - invert_v2(effects->ssr_pixelsize); - - if (BKE_collection_engine_property_value_get_bool(props, "ssr_enable")) { - effects->enabled_effects |= EFFECT_SSR; - - if (BKE_collection_engine_property_value_get_bool(props, "ssr_refraction")) { - effects->enabled_effects |= EFFECT_REFRACT; - - DRWFboTexture tex = {&txl->refract_color, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP}; - - DRW_framebuffer_init(&fbl->refract_fb, &draw_engine_eevee_type, (int)viewport_size[0], (int)viewport_size[1], &tex, 1); - } - - /* Enable double buffering to be able to read previous frame color */ - effects->enabled_effects |= EFFECT_DOUBLE_BUFFER; - - effects->ssr_ray_count = BKE_collection_engine_property_value_get_int(props, "ssr_ray_count"); - effects->reflection_trace_full = !BKE_collection_engine_property_value_get_bool(props, "ssr_halfres"); - effects->ssr_use_normalization = BKE_collection_engine_property_value_get_bool(props, "ssr_normalize_weight"); - effects->ssr_quality = 1.0f - BKE_collection_engine_property_value_get_float(props, "ssr_quality"); - effects->ssr_thickness = BKE_collection_engine_property_value_get_float(props, "ssr_thickness"); - effects->ssr_border_fac = BKE_collection_engine_property_value_get_float(props, "ssr_border_fade"); - effects->ssr_firefly_fac = BKE_collection_engine_property_value_get_float(props, "ssr_firefly_fac"); - effects->ssr_max_roughness = BKE_collection_engine_property_value_get_float(props, "ssr_max_roughness"); - - if (effects->ssr_firefly_fac < 1e-8f) { - effects->ssr_firefly_fac = FLT_MAX; - } - - /* Important, can lead to breakage otherwise. */ - CLAMP(effects->ssr_ray_count, 1, 4); - const int divisor = (effects->reflection_trace_full) ? 1 : 2; - int tracing_res[2] = {(int)viewport_size[0] / divisor, (int)viewport_size[1] / divisor}; - const bool high_qual_input = true; /* TODO dither low quality input */ - - /* MRT for the shading pass in order to output needed data for the SSR pass. */ - /* TODO create one texture layer per lobe */ - if (txl->ssr_specrough_input == NULL) { - DRWTextureFormat specrough_format = (high_qual_input) ? DRW_TEX_RGBA_16 : DRW_TEX_RGBA_8; - txl->ssr_specrough_input = DRW_texture_create_2D((int)viewport_size[0], (int)viewport_size[1], specrough_format, 0, NULL); - } - - /* Reattach textures to the right buffer (because we are alternating between buffers) */ - /* TODO multiple FBO per texture!!!! */ - DRW_framebuffer_texture_detach(txl->ssr_specrough_input); - DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 2, 0); - - /* Raytracing output */ - /* TODO try integer format for hit coord to increase precision */ - DRWFboTexture tex_output[4] = {{&stl->g_data->ssr_hit_output[0], DRW_TEX_RGBA_16, DRW_TEX_TEMP}, - {&stl->g_data->ssr_hit_output[1], DRW_TEX_RGBA_16, DRW_TEX_TEMP}, - {&stl->g_data->ssr_hit_output[2], DRW_TEX_RGBA_16, DRW_TEX_TEMP}, - {&stl->g_data->ssr_hit_output[3], DRW_TEX_RGBA_16, DRW_TEX_TEMP}}; - - DRW_framebuffer_init(&fbl->screen_tracing_fb, &draw_engine_eevee_type, tracing_res[0], tracing_res[1], tex_output, effects->ssr_ray_count); - } - else { - /* Cleanup to release memory */ - DRW_TEXTURE_FREE_SAFE(txl->ssr_specrough_input); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->screen_tracing_fb); - for (int i = 0; i < 4; ++i) { - stl->g_data->ssr_hit_output[i] = NULL; - } - } - - /* Normal buffer for deferred passes. */ - if ((((effects->enabled_effects & EFFECT_GTAO) != 0) && G.debug_value == 6) || - ((effects->enabled_effects & EFFECT_SSR) != 0)) - { + /** + * Normal buffer for deferred passes. + */ + if ((effects->enabled_effects & EFFECT_NORMAL_BUFFER) != 0) { if (txl->ssr_normal_input == NULL) { DRWTextureFormat nor_format = DRW_TEX_RG_16; txl->ssr_normal_input = DRW_texture_create_2D((int)viewport_size[0], (int)viewport_size[1], nor_format, 0, NULL); @@ -1021,10 +179,11 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) DRW_TEXTURE_FREE_SAFE(txl->ssr_normal_input); } - /* Setup double buffer so we can access last frame as it was before post processes */ + /** + * Setup double buffer so we can access last frame as it was before post processes. + */ if ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0) { DRWFboTexture tex_double_buffer = {&txl->color_double_buffer, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}; - DRW_framebuffer_init(&fbl->double_buffer, &draw_engine_eevee_type, (int)viewport_size[0], (int)viewport_size[1], &tex_double_buffer, 1); @@ -1036,250 +195,15 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) } } -static DRWShadingGroup *eevee_create_bloom_pass(const char *name, EEVEE_EffectsInfo *effects, struct GPUShader *sh, DRWPass **pass, bool upsample) -{ - struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get(); - - *pass = DRW_pass_create(name, DRW_STATE_WRITE_COLOR); - - DRWShadingGroup *grp = DRW_shgroup_create(sh, *pass); - DRW_shgroup_call_add(grp, quad, NULL); - DRW_shgroup_uniform_buffer(grp, "sourceBuffer", &effects->unf_source_buffer); - DRW_shgroup_uniform_vec2(grp, "sourceBufferTexelSize", effects->unf_source_texel_size, 1); - if (upsample) { - DRW_shgroup_uniform_buffer(grp, "baseBuffer", &effects->unf_base_buffer); - DRW_shgroup_uniform_float(grp, "sampleScale", &effects->bloom_sample_scale, 1); - } - - return grp; -} - -void EEVEE_effects_cache_volume_object_add(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, Scene *scene, Object *ob) -{ - float *texcoloc = NULL; - float *texcosize = NULL; - struct ModifierData *md = NULL; - EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics; - Material *ma = give_current_material(ob, 1); - - if (ma == NULL) { - return; - } - - struct GPUMaterial *mat = EEVEE_material_mesh_volume_get(scene, ma); - - DRWShadingGroup *grp = DRW_shgroup_material_empty_tri_batch_create(mat, vedata->psl->volumetric_objects_ps, volumetrics->froxel_tex_size[2]); - - /* Making sure it's updated. */ - invert_m4_m4(ob->imat, ob->obmat); - - BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, NULL, &texcosize); - - if (grp) { - DRW_shgroup_uniform_mat4(grp, "volumeObjectMatrix", (float *)ob->imat); - DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texcoloc, 1); - DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texcosize, 1); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)vedata->stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1); - DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); - DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1); - } - - /* Smoke Simulation */ - if (((ob->base_flag & BASE_FROMDUPLI) == 0) && - (md = modifiers_findByType(ob, eModifierType_Smoke)) && - (modifier_isEnabled(scene, md, eModifierMode_Realtime))) - { - SmokeModifierData *smd = (SmokeModifierData *)md; - SmokeDomainSettings *sds = smd->domain; - /* Don't show smoke before simulation starts, this could be made an option in the future. */ - const bool show_smoke = (CFRA >= sds->point_cache[0]->startframe); - - if (sds->fluid && show_smoke) { - if (!sds->wt || !(sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) { - GPU_create_smoke(smd, 0); - } - else if (sds->wt && (sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) { - GPU_create_smoke(smd, 1); - } - BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(smd)); - } - - if (sds->tex != NULL) { - DRW_shgroup_uniform_buffer(grp, "sampdensity", &sds->tex); - } - if (sds->tex_flame != NULL) { - DRW_shgroup_uniform_buffer(grp, "sampflame", &sds->tex_flame); - } - } -} - -void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) +void EEVEE_effects_cache_init(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get(); - if ((effects->enabled_effects & EFFECT_TAA) != 0) { - psl->taa_resolve = DRW_pass_create("Temporal AA Resolve", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.taa_resolve_sh, psl->taa_resolve); - - DRW_shgroup_uniform_buffer(grp, "historyBuffer", &txl->color_double_buffer); - DRW_shgroup_uniform_buffer(grp, "colorBuffer", &txl->color); - DRW_shgroup_uniform_float(grp, "alpha", &effects->taa_alpha, 1); - DRW_shgroup_call_add(grp, quad, NULL); - } - - if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics; - static int zero = 0; - DRWShadingGroup *grp; - - /* World pass is not additive as it also clear the buffer. */ - psl->volumetric_world_ps = DRW_pass_create("Volumetric World", DRW_STATE_WRITE_COLOR); - - /* World Volumetric */ - struct World *wo = scene->world; - if (wo != NULL && wo->use_nodes && wo->nodetree) { - struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo); - - grp = DRW_shgroup_material_empty_tri_batch_create(mat, psl->volumetric_world_ps, volumetrics->froxel_tex_size[2]); - - if (grp) { - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1); - DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); - DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1); - } - } - else { - grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_clear_sh, psl->volumetric_world_ps, volumetrics->froxel_tex_size[2]); - - DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1); - } - - /* Volumetric Objects */ - psl->volumetric_objects_ps = DRW_pass_create("Volumetric Properties", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); - - psl->volumetric_scatter_ps = DRW_pass_create("Volumetric Scattering", DRW_STATE_WRITE_COLOR); - grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_scatter_sh, psl->volumetric_scatter_ps, volumetrics->froxel_tex_size[2]); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); - DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1); - DRW_shgroup_uniform_mat4(grp, "PastViewProjectionMatrix", (float *)stl->g_data->prev_persmat); - DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); - DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); - DRW_shgroup_uniform_int(grp, "light_count", (volumetrics->use_lights) ? &sldata->lamps->num_light : &zero, 1); - DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool); - DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_pool); - DRW_shgroup_uniform_float(grp, "volume_light_clamp", &volumetrics->light_clamp, 1); - DRW_shgroup_uniform_float(grp, "volume_shadows_steps", &volumetrics->shadow_step_count, 1); - DRW_shgroup_uniform_float(grp, "volume_history_alpha", &volumetrics->history_alpha, 1); - DRW_shgroup_uniform_buffer(grp, "volumeScattering", &txl->volume_prop_scattering); - DRW_shgroup_uniform_buffer(grp, "volumeExtinction", &txl->volume_prop_extinction); - DRW_shgroup_uniform_buffer(grp, "volumeEmission", &txl->volume_prop_emission); - DRW_shgroup_uniform_buffer(grp, "volumePhase", &txl->volume_prop_phase); - DRW_shgroup_uniform_buffer(grp, "historyScattering", &txl->volume_scatter_history); - DRW_shgroup_uniform_buffer(grp, "historyTransmittance", &txl->volume_transmittance_history); - - psl->volumetric_integration_ps = DRW_pass_create("Volumetric Integration", DRW_STATE_WRITE_COLOR); - grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_integration_sh, psl->volumetric_integration_ps, volumetrics->froxel_tex_size[2]); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); - DRW_shgroup_uniform_buffer(grp, "volumeScattering", &txl->volume_scatter); - DRW_shgroup_uniform_buffer(grp, "volumeExtinction", &txl->volume_transmittance); - - psl->volumetric_resolve_ps = DRW_pass_create("Volumetric Resolve", DRW_STATE_WRITE_COLOR); - grp = DRW_shgroup_create(e_data.volumetric_resolve_sh, psl->volumetric_resolve_ps); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); - DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); - DRW_shgroup_uniform_buffer(grp, "inScattering", &txl->volume_scatter_history); - DRW_shgroup_uniform_buffer(grp, "inTransmittance", &txl->volume_transmittance_history); - DRW_shgroup_uniform_buffer(grp, "inSceneColor", &e_data.color_src); - DRW_shgroup_uniform_buffer(grp, "inSceneDepth", &e_data.depth_src); - DRW_shgroup_call_add(grp, quad, NULL); - } - - if ((effects->enabled_effects & EFFECT_SSR) != 0) { - int options = (effects->reflection_trace_full) ? SSR_FULL_TRACE : 0; - options |= (effects->ssr_ray_count - 1); - - struct GPUShader *trace_shader = eevee_effects_ssr_shader_get(options); - struct GPUShader *resolve_shader = eevee_effects_ssr_shader_get(SSR_RESOLVE | options); - - psl->ssr_raytrace = DRW_pass_create("SSR Raytrace", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(trace_shader, psl->ssr_raytrace); - DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); - DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input); - DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &txl->ssr_specrough_input); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); - DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer); - DRW_shgroup_uniform_buffer(grp, "minzBuffer", &stl->g_data->minzbuffer); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10); - DRW_shgroup_uniform_vec4(grp, "ssrParameters", &effects->ssr_quality, 1); - DRW_shgroup_uniform_int(grp, "planar_count", &sldata->probes->num_planar, 1); - DRW_shgroup_uniform_float(grp, "maxRoughness", &effects->ssr_max_roughness, 1); - DRW_shgroup_uniform_buffer(grp, "planarDepth", &vedata->txl->planar_depth); - DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); - DRW_shgroup_call_add(grp, quad, NULL); - - psl->ssr_resolve = DRW_pass_create("SSR Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); - grp = DRW_shgroup_create(resolve_shader, psl->ssr_resolve); - DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); - DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input); - DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &txl->ssr_specrough_input); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); - DRW_shgroup_uniform_buffer(grp, "prevColorBuffer", &txl->color_double_buffer); - DRW_shgroup_uniform_mat4(grp, "PastViewProjectionMatrix", (float *)stl->g_data->prev_persmat); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_int(grp, "planar_count", &sldata->probes->num_planar, 1); - DRW_shgroup_uniform_int(grp, "probe_count", &sldata->probes->num_render_cube, 1); - DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10); - DRW_shgroup_uniform_float(grp, "borderFadeFactor", &effects->ssr_border_fac, 1); - DRW_shgroup_uniform_float(grp, "maxRoughness", &effects->ssr_max_roughness, 1); - DRW_shgroup_uniform_float(grp, "lodCubeMax", &sldata->probes->lod_cube_max, 1); - DRW_shgroup_uniform_float(grp, "lodPlanarMax", &sldata->probes->lod_planar_max, 1); - DRW_shgroup_uniform_float(grp, "fireflyFactor", &effects->ssr_firefly_fac, 1); - DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); - DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); - DRW_shgroup_uniform_buffer(grp, "probeCubes", &sldata->probe_pool); - DRW_shgroup_uniform_buffer(grp, "probePlanars", &vedata->txl->planar_pool); - DRW_shgroup_uniform_buffer(grp, "hitBuffer0", &stl->g_data->ssr_hit_output[0]); - if (effects->ssr_ray_count > 1) { - DRW_shgroup_uniform_buffer(grp, "hitBuffer1", &stl->g_data->ssr_hit_output[1]); - } - if (effects->ssr_ray_count > 2) { - DRW_shgroup_uniform_buffer(grp, "hitBuffer2", &stl->g_data->ssr_hit_output[2]); - } - if (effects->ssr_ray_count > 3) { - DRW_shgroup_uniform_buffer(grp, "hitBuffer3", &stl->g_data->ssr_hit_output[3]); - } - - DRW_shgroup_uniform_vec4(grp, "aoParameters[0]", &effects->ao_dist, 2); - if (effects->use_ao) { - DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &vedata->txl->gtao_horizons); - DRW_shgroup_uniform_ivec2(grp, "aoHorizonTexSize", (int *)vedata->stl->effects->ao_texsize, 1); - } - else { - /* Use shadow_pool as fallback to avoid sampling problem on certain platform, see: T52593 */ - DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &sldata->shadow_pool); - } - - DRW_shgroup_call_add(grp, quad, NULL); - } - { psl->color_downsample_ps = DRW_pass_create("Downsample", DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(e_data.downsample_sh, psl->color_downsample_ps); @@ -1301,10 +225,14 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) { /* Perform min/max downsample */ + DRWShadingGroup *grp; + +#if 0 /* Not used for now */ psl->minz_downlevel_ps = DRW_pass_create("HiZ Min Down Level", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.minz_downlevel_sh, psl->minz_downlevel_ps); + grp = DRW_shgroup_create(e_data.minz_downlevel_sh, psl->minz_downlevel_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &stl->g_data->minzbuffer); DRW_shgroup_call_add(grp, quad, NULL); +#endif psl->maxz_downlevel_ps = DRW_pass_create("HiZ Max Down Level", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.maxz_downlevel_sh, psl->maxz_downlevel_ps); @@ -1312,21 +240,25 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_call_add(grp, quad, NULL); /* Copy depth buffer to halfres top level of HiZ */ +#if 0 /* Not used for now */ psl->minz_downdepth_ps = DRW_pass_create("HiZ Min Copy Depth Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.minz_downdepth_sh, psl->minz_downdepth_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_call_add(grp, quad, NULL); +#endif psl->maxz_downdepth_ps = DRW_pass_create("HiZ Max Copy Depth Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.maxz_downdepth_sh, psl->maxz_downdepth_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_call_add(grp, quad, NULL); +#if 0 /* Not used for now */ psl->minz_downdepth_layer_ps = DRW_pass_create("HiZ Min Copy DepthLayer Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.minz_downdepth_layer_sh, psl->minz_downdepth_layer_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1); DRW_shgroup_call_add(grp, quad, NULL); +#endif psl->maxz_downdepth_layer_ps = DRW_pass_create("HiZ Max Copy DepthLayer Halfres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.maxz_downdepth_layer_sh, psl->maxz_downdepth_layer_ps); @@ -1335,150 +267,27 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_call_add(grp, quad, NULL); /* Copy depth buffer to halfres top level of HiZ */ +#if 0 /* Not used for now */ psl->minz_copydepth_ps = DRW_pass_create("HiZ Min Copy Depth Fullres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.minz_copydepth_sh, psl->minz_copydepth_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_call_add(grp, quad, NULL); +#endif psl->maxz_copydepth_ps = DRW_pass_create("HiZ Max Copy Depth Fullres", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.maxz_copydepth_sh, psl->maxz_copydepth_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_call_add(grp, quad, NULL); } - - { - psl->ao_horizon_search = DRW_pass_create("GTAO Horizon Search", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.gtao_sh, psl->ao_horizon_search); - DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer); - DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10); - DRW_shgroup_uniform_vec4(grp, "aoParameters[0]", &stl->effects->ao_dist, 2); - DRW_shgroup_uniform_float(grp, "sampleNbr", &stl->effects->ao_sample_nbr, 1); - DRW_shgroup_uniform_ivec2(grp, "aoHorizonTexSize", (int *)stl->effects->ao_texsize, 1); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); - DRW_shgroup_call_add(grp, quad, NULL); - - psl->ao_horizon_debug = DRW_pass_create("GTAO Horizon Debug", DRW_STATE_WRITE_COLOR); - grp = DRW_shgroup_create(e_data.gtao_debug_sh, psl->ao_horizon_debug); - DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer); - DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); - DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input); - DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &txl->gtao_horizons); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); - DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10); - DRW_shgroup_uniform_vec4(grp, "aoParameters[0]", &stl->effects->ao_dist, 2); - DRW_shgroup_uniform_ivec2(grp, "aoHorizonTexSize", (int *)stl->effects->ao_texsize, 1); - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); - DRW_shgroup_call_add(grp, quad, NULL); - } - - { - psl->motion_blur = DRW_pass_create("Motion Blur", DRW_STATE_WRITE_COLOR); - - DRWShadingGroup *grp = DRW_shgroup_create(e_data.motion_blur_sh, psl->motion_blur); - DRW_shgroup_uniform_int(grp, "samples", &effects->motion_blur_samples, 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", &effects->source_buffer); - DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_call_add(grp, quad, NULL); - } - - { - /** Bloom algorithm - * - * Overview : - * - Downsample the color buffer doing a small blur during each step. - * - Accumulate bloom color using previously downsampled color buffers - * and do an upsample blur for each new accumulated layer. - * - Finally add accumulation buffer onto the source color buffer. - * - * [1/1] is original copy resolution (can be half or quater res for performance) - * - * [DOWNSAMPLE CHAIN] [UPSAMPLE CHAIN] - * - * Source Color ── [Blit] ──> Bright Color Extract [1/1] Final Color - * | Λ - * [Downsample First] Source Color ─> + [Resolve] - * v | - * Color Downsampled [1/2] ────────────> + Accumulation Buffer [1/2] - * | Λ - * ─── ─── - * Repeat Repeat - * ─── ─── - * v | - * Color Downsampled [1/N-1] ──────────> + Accumulation Buffer [1/N-1] - * | Λ - * [Downsample] [Upsample] - * v | - * Color Downsampled [1/N] ─────────────────────────┘ - **/ - DRWShadingGroup *grp; - const bool use_highres = true; - const bool use_antiflicker = true; - eevee_create_bloom_pass("Bloom Downsample First", effects, e_data.bloom_downsample_sh[use_antiflicker], &psl->bloom_downsample_first, false); - eevee_create_bloom_pass("Bloom Downsample", effects, e_data.bloom_downsample_sh[0], &psl->bloom_downsample, false); - eevee_create_bloom_pass("Bloom Upsample", effects, e_data.bloom_upsample_sh[use_highres], &psl->bloom_upsample, true); - grp = eevee_create_bloom_pass("Bloom Blit", effects, e_data.bloom_blit_sh[use_antiflicker], &psl->bloom_blit, false); - DRW_shgroup_uniform_vec4(grp, "curveThreshold", effects->bloom_curve_threshold, 1); - DRW_shgroup_uniform_float(grp, "clampIntensity", &effects->bloom_clamp, 1); - grp = eevee_create_bloom_pass("Bloom Resolve", effects, e_data.bloom_resolve_sh[use_highres], &psl->bloom_resolve, true); - DRW_shgroup_uniform_vec3(grp, "bloomColor", effects->bloom_color, 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); - DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); - 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); - DRW_shgroup_uniform_buffer(grp, "cocBuffer", &txl->dof_coc); - DRW_shgroup_uniform_vec2(grp, "layerSelection", effects->dof_layer_select, 1); - DRW_shgroup_uniform_vec4(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); - DRW_shgroup_uniform_buffer(grp, "nearBuffer", &txl->dof_near_blur); - DRW_shgroup_uniform_buffer(grp, "farBuffer", &txl->dof_far_blur); - DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); - 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); - } } +#if 0 /* Not required for now */ static void min_downsample_cb(void *vedata, int UNUSED(level)) { EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; DRW_draw_pass(psl->minz_downlevel_ps); } +#endif static void max_downsample_cb(void *vedata, int UNUSED(level)) { @@ -1503,12 +312,12 @@ void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src, int l { EEVEE_PassList *psl = vedata->psl; EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_StorageList *stl = vedata->stl; EEVEE_TextureList *txl = vedata->txl; e_data.depth_src = depth_src; e_data.depth_src_layer = layer; +#if 0 /* Not required for now */ DRW_stats_group_start("Min buffer"); /* Copy depth buffer to min texture top level */ DRW_framebuffer_texture_attach(fbl->downsample_fb, stl->g_data->minzbuffer, 0, 0); @@ -1524,6 +333,7 @@ void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src, int l /* Create lower levels */ DRW_framebuffer_recursive_downsample(fbl->downsample_fb, stl->g_data->minzbuffer, 8, &min_downsample_cb, vedata); DRW_stats_group_end(); +#endif DRW_stats_group_start("Max buffer"); /* Copy depth buffer to max texture top level */ @@ -1540,6 +350,9 @@ void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src, int l /* Create lower levels */ DRW_framebuffer_recursive_downsample(fbl->downsample_fb, txl->maxzbuffer, 8, &max_downsample_cb, vedata); DRW_stats_group_end(); + + /* Restore */ + DRW_framebuffer_bind(fbl->main); } /** @@ -1568,314 +381,32 @@ void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_ DRW_stats_group_end(); } -void EEVEE_effects_do_volumetrics(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) -{ - EEVEE_PassList *psl = vedata->psl; - EEVEE_TextureList *txl = vedata->txl; - EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_EffectsInfo *effects = stl->effects; - - if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) { - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - - e_data.color_src = txl->color; - e_data.depth_src = dtxl->depth; - - /* Step 1: Participating Media Properties */ - DRW_framebuffer_bind(fbl->volumetric_fb); - DRW_draw_pass(psl->volumetric_world_ps); - DRW_draw_pass(psl->volumetric_objects_ps); - - /* Step 2: Scatter Light */ - DRW_framebuffer_bind(fbl->volumetric_scat_fb); - DRW_draw_pass(psl->volumetric_scatter_ps); - - /* Step 3: Integration */ - DRW_framebuffer_bind(fbl->volumetric_integ_fb); - DRW_draw_pass(psl->volumetric_integration_ps); - - /* Step 4: Apply for opaque */ - DRW_framebuffer_bind(fbl->effect_fb); - DRW_draw_pass(psl->volumetric_resolve_ps); - - /* Swap volume history buffers */ - SWAP(struct GPUFrameBuffer *, fbl->volumetric_scat_fb, fbl->volumetric_integ_fb); - SWAP(GPUTexture *, txl->volume_scatter, txl->volume_scatter_history); - SWAP(GPUTexture *, txl->volume_transmittance, txl->volume_transmittance_history); - - /* Swap the buffers and rebind depth to the current buffer */ - DRW_framebuffer_texture_detach(dtxl->depth); - SWAP(struct GPUFrameBuffer *, fbl->main, fbl->effect_fb); - SWAP(GPUTexture *, txl->color, txl->color_post); - DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0); - } -} - -void EEVEE_effects_do_refraction(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) -{ - EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_TextureList *txl = vedata->txl; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_EffectsInfo *effects = stl->effects; - - if ((effects->enabled_effects & EFFECT_REFRACT) != 0) { - DRW_framebuffer_texture_attach(fbl->refract_fb, txl->refract_color, 0, 0); - DRW_framebuffer_blit(fbl->main, fbl->refract_fb, false); - EEVEE_downsample_buffer(vedata, fbl->downsample_fb, txl->refract_color, 9); - } -} - -void EEVEE_effects_do_ssr(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) -{ - EEVEE_PassList *psl = vedata->psl; - EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_TextureList *txl = vedata->txl; - EEVEE_EffectsInfo *effects = stl->effects; - - if (((effects->enabled_effects & EFFECT_SSR) != 0) && stl->g_data->valid_double_buffer) { - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - e_data.depth_src = dtxl->depth; - - for (int i = 0; i < effects->ssr_ray_count; ++i) { - DRW_framebuffer_texture_attach(fbl->screen_tracing_fb, stl->g_data->ssr_hit_output[i], i, 0); - } - DRW_framebuffer_bind(fbl->screen_tracing_fb); - - /* Raytrace. */ - DRW_draw_pass(psl->ssr_raytrace); - - for (int i = 0; i < effects->ssr_ray_count; ++i) { - DRW_framebuffer_texture_detach(stl->g_data->ssr_hit_output[i]); - } - - EEVEE_downsample_buffer(vedata, fbl->downsample_fb, txl->color_double_buffer, 9); - - /* Resolve at fullres */ - DRW_framebuffer_texture_detach(dtxl->depth); - DRW_framebuffer_texture_detach(txl->ssr_normal_input); - DRW_framebuffer_texture_detach(txl->ssr_specrough_input); - DRW_framebuffer_bind(fbl->main); - DRW_draw_pass(psl->ssr_resolve); - - /* Restore */ - DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0); - DRW_framebuffer_texture_attach(fbl->main, txl->ssr_normal_input, 1, 0); - DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 2, 0); - } - - if ((effects->enabled_effects & EFFECT_GTAO) != 0 && G.debug_value == 6) { - /* GTAO Debug */ - DRW_framebuffer_texture_attach(fbl->gtao_debug_fb, stl->g_data->gtao_horizons_debug, 0, 0); - DRW_framebuffer_bind(fbl->gtao_debug_fb); - - DRW_draw_pass(psl->ao_horizon_debug); - - /* Restore */ - DRW_framebuffer_texture_detach(stl->g_data->gtao_horizons_debug); - } - - DRW_framebuffer_bind(fbl->main); -} - -void EEVEE_effects_do_gtao(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) -{ - EEVEE_PassList *psl = vedata->psl; - EEVEE_TextureList *txl = vedata->txl; - EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_EffectsInfo *effects = stl->effects; - - if ((effects->enabled_effects & EFFECT_GTAO) != 0) { - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - e_data.depth_src = dtxl->depth; - - DRW_stats_group_start("GTAO Horizon Scan"); - for (effects->ao_sample_nbr = 0.0; - effects->ao_sample_nbr < effects->ao_samples; - ++effects->ao_sample_nbr) - { - DRW_framebuffer_texture_detach(txl->gtao_horizons); - DRW_framebuffer_texture_layer_attach(fbl->gtao_fb, txl->gtao_horizons, 0, (int)effects->ao_sample_nbr, 0); - DRW_framebuffer_bind(fbl->gtao_fb); - - DRW_draw_pass(psl->ao_horizon_search); - } - DRW_stats_group_end(); - - /* Restore */ - DRW_framebuffer_bind(fbl->main); - } -} - -#define SWAP_DOUBLE_BUFFERS() { \ - if (swap_double_buffer) { \ - SWAP(struct GPUFrameBuffer *, fbl->main, fbl->double_buffer); \ - SWAP(GPUTexture *, txl->color, txl->color_double_buffer); \ - swap_double_buffer = false; \ - } \ -} ((void)0) - -#define SWAP_BUFFERS() { \ - if (effects->target_buffer != fbl->main) { \ - SWAP_DOUBLE_BUFFERS(); \ - effects->source_buffer = txl->color_post; \ - effects->target_buffer = fbl->main; \ - } \ - else { \ - SWAP_DOUBLE_BUFFERS(); \ - effects->source_buffer = txl->color; \ - effects->target_buffer = fbl->effect_fb; \ - } \ -} ((void)0) - void EEVEE_draw_effects(EEVEE_Data *vedata) { - EEVEE_PassList *psl = vedata->psl; EEVEE_TextureList *txl = vedata->txl; EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - - /* only once per frame after the first post process */ - bool swap_double_buffer = ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0); - - /* Default framebuffer and texture */ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + /* only once per frame after the first post process */ + effects->swap_double_buffer = ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0); + /* Init pointers */ effects->source_buffer = txl->color; /* latest updated texture */ effects->target_buffer = fbl->effect_fb; /* next target to render to */ - /* Temporal Anti-Aliasing */ - /* MUST COME FIRST. */ - if ((effects->enabled_effects & EFFECT_TAA) != 0) { - if (effects->taa_current_sample != 1) { - DRW_framebuffer_bind(fbl->effect_fb); - DRW_draw_pass(psl->taa_resolve); - - /* Restore the depth from sample 1. */ - DRW_framebuffer_blit(fbl->depth_double_buffer_fb, fbl->main, true); - - /* Special Swap */ - SWAP(struct GPUFrameBuffer *, fbl->effect_fb, fbl->double_buffer); - SWAP(GPUTexture *, txl->color_post, txl->color_double_buffer); - swap_double_buffer = false; - effects->source_buffer = txl->color_double_buffer; - effects->target_buffer = fbl->main; - } - else { - /* Save the depth buffer for the next frame. - * This saves us from doing anything special - * in the other mode engines. */ - DRW_framebuffer_blit(fbl->main, fbl->depth_double_buffer_fb, true); - } - - if ((effects->taa_total_sample == 0) || - (effects->taa_current_sample < effects->taa_total_sample)) - { - DRW_viewport_request_redraw(); - } - } + /* Temporal Anti-Aliasing MUST come first */ + EEVEE_temporal_sampling_draw(vedata); /* Detach depth for effects to use it */ DRW_framebuffer_texture_detach(dtxl->depth); - /* Motion Blur */ - if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) { - 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 */ - if ((effects->enabled_effects & EFFECT_BLOOM) != 0) { - /* Reuse bloom half res buffer */ - effects->unf_source_buffer = txl->bloom_downsample[0]; - } - else { - 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 */ - if ((effects->enabled_effects & EFFECT_BLOOM) != 0) { - struct GPUTexture *last; - - /* Extract bright pixels */ - copy_v2_v2(effects->unf_source_texel_size, effects->source_texel_size); - effects->unf_source_buffer = effects->source_buffer; - - DRW_framebuffer_bind(fbl->bloom_blit_fb); - DRW_draw_pass(psl->bloom_blit); - - /* Downsample */ - copy_v2_v2(effects->unf_source_texel_size, effects->blit_texel_size); - effects->unf_source_buffer = txl->bloom_blit; - - DRW_framebuffer_bind(fbl->bloom_down_fb[0]); - DRW_draw_pass(psl->bloom_downsample_first); - - last = txl->bloom_downsample[0]; - - for (int i = 1; i < effects->bloom_iteration_ct; ++i) { - copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[i - 1]); - effects->unf_source_buffer = last; - - DRW_framebuffer_bind(fbl->bloom_down_fb[i]); - DRW_draw_pass(psl->bloom_downsample); - - /* Used in next loop */ - last = txl->bloom_downsample[i]; - } - - /* Upsample and accumulate */ - for (int i = effects->bloom_iteration_ct - 2; i >= 0; --i) { - copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[i]); - effects->unf_source_buffer = txl->bloom_downsample[i]; - effects->unf_base_buffer = last; - - DRW_framebuffer_bind(fbl->bloom_accum_fb[i]); - DRW_draw_pass(psl->bloom_upsample); - - last = txl->bloom_upsample[i]; - } - - /* Resolve */ - copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[0]); - effects->unf_source_buffer = last; - effects->unf_base_buffer = effects->source_buffer; - - DRW_framebuffer_bind(effects->target_buffer); - DRW_draw_pass(psl->bloom_resolve); - SWAP_BUFFERS(); - } + /* Post process stack (order matters) */ + EEVEE_motion_blur_draw(vedata); + EEVEE_depth_of_field_draw(vedata); + EEVEE_bloom_draw(vedata); /* Restore default framebuffer */ DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0); @@ -1931,37 +462,11 @@ void EEVEE_draw_effects(EEVEE_Data *vedata) } } -void EEVEE_effects_free_smoke_texture(void) -{ - /* Free Smoke Textures after rendering */ - for (LinkData *link = e_data.smoke_domains.first; link; link = link->next) { - SmokeModifierData *smd = (SmokeModifierData *)link->data; - GPU_free_smoke(smd); - } - BLI_freelistN(&e_data.smoke_domains); -} - void EEVEE_effects_free(void) { - MEM_SAFE_FREE(e_data.volumetric_common_lib); - MEM_SAFE_FREE(e_data.volumetric_common_lamps_lib); - - for (int i = 0; i < SSR_MAX_SHADER; ++i) { - DRW_SHADER_FREE_SAFE(e_data.ssr_sh[i]); - } DRW_SHADER_FREE_SAFE(e_data.downsample_sh); DRW_SHADER_FREE_SAFE(e_data.downsample_cube_sh); - DRW_SHADER_FREE_SAFE(e_data.taa_resolve_sh); - - DRW_SHADER_FREE_SAFE(e_data.gtao_sh); - DRW_SHADER_FREE_SAFE(e_data.gtao_debug_sh); - - DRW_SHADER_FREE_SAFE(e_data.volumetric_clear_sh); - DRW_SHADER_FREE_SAFE(e_data.volumetric_scatter_sh); - DRW_SHADER_FREE_SAFE(e_data.volumetric_integration_sh); - DRW_SHADER_FREE_SAFE(e_data.volumetric_resolve_sh); - DRW_SHADER_FREE_SAFE(e_data.minz_downlevel_sh); DRW_SHADER_FREE_SAFE(e_data.maxz_downlevel_sh); DRW_SHADER_FREE_SAFE(e_data.minz_downdepth_sh); @@ -1970,18 +475,4 @@ void EEVEE_effects_free(void) DRW_SHADER_FREE_SAFE(e_data.maxz_downdepth_layer_sh); DRW_SHADER_FREE_SAFE(e_data.minz_copydepth_sh); DRW_SHADER_FREE_SAFE(e_data.maxz_copydepth_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]); - DRW_SHADER_FREE_SAFE(e_data.bloom_upsample_sh[0]); - DRW_SHADER_FREE_SAFE(e_data.bloom_resolve_sh[0]); - DRW_SHADER_FREE_SAFE(e_data.bloom_blit_sh[1]); - DRW_SHADER_FREE_SAFE(e_data.bloom_downsample_sh[1]); - DRW_SHADER_FREE_SAFE(e_data.bloom_upsample_sh[1]); - DRW_SHADER_FREE_SAFE(e_data.bloom_resolve_sh[1]); } diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index 12e4c12b148..78c22ee261c 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -86,10 +86,17 @@ static void EEVEE_cache_init(void *vedata) EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; EEVEE_SceneLayerData *sldata = EEVEE_scene_layer_data_get(); - EEVEE_materials_cache_init(vedata); - EEVEE_lights_cache_init(sldata, psl); - EEVEE_lightprobes_cache_init(sldata, vedata); + EEVEE_bloom_cache_init(sldata, vedata); + EEVEE_depth_of_field_cache_init(sldata, vedata); EEVEE_effects_cache_init(sldata, vedata); + EEVEE_lightprobes_cache_init(sldata, vedata); + EEVEE_lights_cache_init(sldata, psl); + EEVEE_materials_cache_init(vedata); + EEVEE_motion_blur_cache_init(sldata, vedata); + EEVEE_occlusion_cache_init(sldata, vedata); + EEVEE_screen_raytrace_cache_init(sldata, vedata); + EEVEE_temporal_sampling_cache_init(sldata, vedata); + EEVEE_volumes_cache_init(sldata, vedata); } static void EEVEE_cache_populate(void *vedata, Object *ob) @@ -220,11 +227,8 @@ static void EEVEE_draw_scene(void *vedata) EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1); DRW_stats_group_end(); - /* Compute GTAO Horizons */ - EEVEE_effects_do_gtao(sldata, vedata); - - /* Restore main FB */ - DRW_framebuffer_bind(fbl->main); + EEVEE_occlusion_compute(sldata, vedata); + EEVEE_volumes_compute(sldata, vedata); /* Shading pass */ DRW_stats_group_start("Shading"); @@ -233,18 +237,11 @@ static void EEVEE_draw_scene(void *vedata) DRW_draw_pass(psl->material_pass); DRW_stats_group_end(); - /* Screen Space Reflections */ - DRW_stats_group_start("SSR"); - EEVEE_effects_do_ssr(sldata, vedata); - DRW_stats_group_end(); - + /* Effects pre-transparency */ + EEVEE_reflection_compute(sldata, vedata); + EEVEE_occlusion_draw_debug(sldata, vedata); DRW_draw_pass(psl->probe_display); - - /* Prepare Refraction */ - EEVEE_effects_do_refraction(sldata, vedata); - - /* Restore main FB */ - DRW_framebuffer_bind(fbl->main); + EEVEE_refraction_compute(sldata, vedata); /* Opaque refraction */ DRW_stats_group_start("Opaque Refraction"); @@ -253,16 +250,12 @@ static void EEVEE_draw_scene(void *vedata) DRW_draw_pass(psl->refract_pass); DRW_stats_group_end(); - /* Volumetrics */ - DRW_stats_group_start("Volumetrics"); - EEVEE_effects_do_volumetrics(sldata, vedata); - DRW_stats_group_end(); + /* Volumetrics Resolve Opaque */ + EEVEE_volumes_resolve(sldata, vedata); /* Transparent */ DRW_pass_sort_shgroup_z(psl->transparent_pass); - DRW_stats_group_start("Transparent"); DRW_draw_pass(psl->transparent_pass); - DRW_stats_group_end(); /* Post Process */ DRW_stats_group_start("Post FX"); @@ -277,7 +270,7 @@ static void EEVEE_draw_scene(void *vedata) } } - EEVEE_effects_free_smoke_texture(); + EEVEE_volumes_free_smoke_textures(); stl->g_data->view_updated = false; } @@ -292,10 +285,17 @@ static void EEVEE_view_update(void *vedata) static void EEVEE_engine_free(void) { - EEVEE_materials_free(); + EEVEE_bloom_free(); + EEVEE_depth_of_field_free(); EEVEE_effects_free(); - EEVEE_lights_free(); EEVEE_lightprobes_free(); + EEVEE_lights_free(); + EEVEE_materials_free(); + EEVEE_motion_blur_free(); + EEVEE_occlusion_free(); + EEVEE_screen_raytrace_free(); + EEVEE_temporal_sampling_free(); + EEVEE_volumes_free(); } static void EEVEE_layer_collection_settings_create(RenderEngine *UNUSED(engine), IDProperty *props) diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 2eefcc3aa5d..3f0bcc840d0 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -471,7 +471,6 @@ void EEVEE_lightprobes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *veda DRWShadingGroup *grp = stl->g_data->planar_downsample = DRW_shgroup_instance_create(e_data.probe_planar_downsample_sh, psl->probe_planar_downsample_ps, geom); DRW_shgroup_uniform_buffer(grp, "source", &txl->planar_pool); DRW_shgroup_uniform_float(grp, "fireflyFactor", &stl->effects->ssr_firefly_fac, 1); - DRW_shgroup_uniform_vec2(grp, "texelSize", stl->g_data->texel_size, 1); } } @@ -1159,7 +1158,7 @@ static void render_scene_to_planar( EEVEE_create_minmax_buffer(vedata, tmp_planar_depth, layer); /* Compute GTAO Horizons */ - EEVEE_effects_do_gtao(sldata, vedata); + EEVEE_occlusion_compute(sldata, vedata); /* Rebind Planar FB */ DRW_framebuffer_bind(fbl->planarref_fb); diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 1d551796a60..ddbe51ee3e8 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -359,7 +359,6 @@ static void add_standard_uniforms( DRW_shgroup_uniform_bool(shgrp, "specToggle", &sldata->probes->specular_toggle, 1); DRW_shgroup_uniform_bool(shgrp, "ssrToggle", &sldata->probes->ssr_toggle, 1); DRW_shgroup_uniform_float(shgrp, "lodCubeMax", &sldata->probes->lod_cube_max, 1); - DRW_shgroup_uniform_float(shgrp, "lodPlanarMax", &sldata->probes->lod_planar_max, 1); DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); DRW_shgroup_uniform_buffer(shgrp, "probeCubes", &sldata->probe_pool); DRW_shgroup_uniform_buffer(shgrp, "probePlanars", &vedata->txl->planar_pool); @@ -1284,7 +1283,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl /* Volumetrics */ if (vedata->stl->effects->use_volumetrics && use_volume_material) { - EEVEE_effects_cache_volume_object_add(sldata, vedata, scene, ob); + EEVEE_volumes_cache_object_add(sldata, vedata, scene, ob); } } diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c new file mode 100644 index 00000000000..5ca2dfe1949 --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c @@ -0,0 +1,207 @@ +/* + * 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 + * + */ + +/* Gather all screen space effects technique such as Bloom, Motion Blur, DoF, SSAO, SSR, ... + */ + +/** \file eevee_effects.c + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "DNA_anim_types.h" +#include "DNA_camera_types.h" +#include "DNA_screen_types.h" + +#include "BKE_global.h" /* for G.debug_value */ +#include "BKE_camera.h" +#include "BKE_object.h" +#include "BKE_animsys.h" +#include "BKE_screen.h" + +#include "ED_screen.h" + +#include "DEG_depsgraph.h" + +#include "eevee_private.h" +#include "GPU_texture.h" + +static struct { + /* Motion Blur */ + struct GPUShader *motion_blur_sh; +} e_data = {NULL}; /* Engine data */ + +extern char datatoc_effect_motion_blur_frag_glsl[]; + +static void eevee_motion_blur_camera_get_matrix_at_time( + const bContext *C, Scene *scene, ARegion *ar, RegionView3D *rv3d, View3D *v3d, Object *camera, float time, float r_mat[4][4]) +{ + EvaluationContext eval_ctx; + float obmat[4][4]; + + /* HACK */ + Object cam_cpy; Camera camdata_cpy; + memcpy(&cam_cpy, camera, sizeof(cam_cpy)); + memcpy(&camdata_cpy, camera->data, sizeof(camdata_cpy)); + cam_cpy.data = &camdata_cpy; + + CTX_data_eval_ctx(C, &eval_ctx); + + /* Past matrix */ + /* FIXME : This is a temporal solution that does not take care of parent animations */ + /* Recalc Anim manualy */ + BKE_animsys_evaluate_animdata(scene, &cam_cpy.id, cam_cpy.adt, time, ADT_RECALC_ALL); + BKE_animsys_evaluate_animdata(scene, &camdata_cpy.id, camdata_cpy.adt, time, ADT_RECALC_ALL); + BKE_object_where_is_calc_time(&eval_ctx, scene, &cam_cpy, time); + + /* Compute winmat */ + CameraParams params; + BKE_camera_params_init(¶ms); + + /* copy of BKE_camera_params_from_view3d */ + { + params.lens = v3d->lens; + params.clipsta = v3d->near; + params.clipend = v3d->far; + + /* camera view */ + BKE_camera_params_from_object(¶ms, &cam_cpy); + + params.zoom = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom); + + params.offsetx = 2.0f * rv3d->camdx * params.zoom; + params.offsety = 2.0f * rv3d->camdy * params.zoom; + + params.shiftx *= params.zoom; + params.shifty *= params.zoom; + + params.zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB / params.zoom; + } + + BKE_camera_params_compute_viewplane(¶ms, ar->winx, ar->winy, 1.0f, 1.0f); + BKE_camera_params_compute_matrix(¶ms); + + /* FIXME Should be done per view (MULTIVIEW) */ + normalize_m4_m4(obmat, cam_cpy.obmat); + invert_m4(obmat); + mul_m4_m4m4(r_mat, params.winmat, obmat); +} + +static void eevee_create_shader_motion_blur(void) +{ + e_data.motion_blur_sh = DRW_shader_create_fullscreen(datatoc_effect_motion_blur_frag_glsl, NULL); +} + +int EEVEE_motion_blur_init(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + SceneLayer *scene_layer = draw_ctx->scene_layer; + Scene *scene = draw_ctx->scene; + View3D *v3d = draw_ctx->v3d; + RegionView3D *rv3d = draw_ctx->rv3d; + ARegion *ar = draw_ctx->ar; + IDProperty *props = BKE_scene_layer_engine_evaluated_get(scene_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); + + if (BKE_collection_engine_property_value_get_bool(props, "motion_blur_enable") && (draw_ctx->evil_C != NULL)) { + /* Update Motion Blur Matrices */ + if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + float persmat[4][4]; + float ctime = BKE_scene_frame_get(scene); + float delta = BKE_collection_engine_property_value_get_float(props, "motion_blur_shutter"); + + /* Current matrix */ + eevee_motion_blur_camera_get_matrix_at_time(draw_ctx->evil_C, scene, ar, rv3d, v3d, v3d->camera, ctime, effects->current_ndc_to_world); + + /* Viewport Matrix */ + DRW_viewport_matrix_get(persmat, DRW_MAT_PERS); + + /* Only continue if camera is not being keyed */ + if (compare_m4m4(persmat, effects->current_ndc_to_world, 0.0001f)) { + + /* Past matrix */ + eevee_motion_blur_camera_get_matrix_at_time(draw_ctx->evil_C, scene, ar, rv3d, v3d, v3d->camera, ctime - delta, effects->past_world_to_ndc); + +#if 0 /* for future high quality blur */ + /* Future matrix */ + eevee_motion_blur_camera_get_matrix_at_time(scene, ar, rv3d, v3d, v3d->camera, ctime + delta, effects->future_world_to_ndc); +#endif + invert_m4(effects->current_ndc_to_world); + + effects->motion_blur_samples = BKE_collection_engine_property_value_get_int(props, "motion_blur_samples"); + + if (!e_data.motion_blur_sh) { + eevee_create_shader_motion_blur(); + } + + return EFFECT_MOTION_BLUR | EFFECT_POST_BUFFER; + } + } + } + + return 0; +} + +void EEVEE_motion_blur_cache_init(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + + struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get(); + + if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) { + psl->motion_blur = DRW_pass_create("Motion Blur", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(e_data.motion_blur_sh, psl->motion_blur); + DRW_shgroup_uniform_int(grp, "samples", &effects->motion_blur_samples, 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", &effects->source_buffer); + DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_call_add(grp, quad, NULL); + } +} + +void EEVEE_motion_blur_draw(EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + + /* Motion Blur */ + if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) { + DRW_framebuffer_bind(effects->target_buffer); + DRW_draw_pass(psl->motion_blur); + SWAP_BUFFERS(); + } +} + +void EEVEE_motion_blur_free(void) +{ + DRW_SHADER_FREE_SAFE(e_data.motion_blur_sh); +} diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c new file mode 100644 index 00000000000..86a9fb2ff1a --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -0,0 +1,252 @@ +/* + * 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 + * + */ + +/* Implementation of the screen space Ground Truth Ambient Occlusion. + */ + +/** \file eevee_occlusion.c + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "DNA_anim_types.h" + +#include "BKE_global.h" /* for G.debug_value */ + +#include "BLI_dynstr.h" + +#include "eevee_private.h" + +static struct { + /* Ground Truth Ambient Occlusion */ + struct GPUShader *gtao_sh; + struct GPUShader *gtao_debug_sh; +} e_data = {NULL}; /* Engine data */ + +extern char datatoc_ambient_occlusion_lib_glsl[]; +extern char datatoc_bsdf_common_lib_glsl[]; +extern char datatoc_effect_gtao_frag_glsl[]; + +static void eevee_create_shader_occlusion(void) +{ + DynStr *ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_ambient_occlusion_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_effect_gtao_frag_glsl); + char *frag_str = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); + + e_data.gtao_sh = DRW_shader_create_fullscreen(frag_str, NULL); + e_data.gtao_debug_sh = DRW_shader_create_fullscreen(frag_str, "#define DEBUG_AO\n"); + + MEM_freeN(frag_str); +} + +int EEVEE_occlusion_init(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_EffectsInfo *effects = stl->effects; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + SceneLayer *scene_layer = draw_ctx->scene_layer; + IDProperty *props = BKE_scene_layer_engine_evaluated_get(scene_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); + + if (BKE_collection_engine_property_value_get_bool(props, "gtao_enable")) { + const float *viewport_size = DRW_viewport_size_get(); + + /* Shaders */ + if (!e_data.gtao_sh) { + eevee_create_shader_occlusion(); + } + + effects->ao_dist = BKE_collection_engine_property_value_get_float(props, "gtao_distance"); + effects->ao_factor = BKE_collection_engine_property_value_get_float(props, "gtao_factor"); + effects->ao_quality = 1.0f - BKE_collection_engine_property_value_get_float(props, "gtao_quality"); + effects->ao_samples = BKE_collection_engine_property_value_get_int(props, "gtao_samples"); + effects->ao_samples_inv = 1.0f / effects->ao_samples; + + effects->ao_settings = 1.0; /* USE_AO */ + if (BKE_collection_engine_property_value_get_bool(props, "gtao_use_bent_normals")) { + effects->ao_settings += 2.0; /* USE_BENT_NORMAL */ + } + if (BKE_collection_engine_property_value_get_bool(props, "gtao_denoise")) { + effects->ao_settings += 4.0; /* USE_DENOISE */ + } + + effects->ao_bounce_fac = (float)BKE_collection_engine_property_value_get_bool(props, "gtao_bounce"); + + effects->ao_texsize[0] = ((int)viewport_size[0]); + effects->ao_texsize[1] = ((int)viewport_size[1]); + + /* Round up to multiple of 2 */ + if ((effects->ao_texsize[0] & 0x1) != 0) { + effects->ao_texsize[0] += 1; + } + if ((effects->ao_texsize[1] & 0x1) != 0) { + effects->ao_texsize[1] += 1; + } + + CLAMP(effects->ao_samples, 1, 32); + + if (effects->hori_tex_layers != effects->ao_samples) { + DRW_TEXTURE_FREE_SAFE(txl->gtao_horizons); + } + + if (txl->gtao_horizons == NULL) { + effects->hori_tex_layers = effects->ao_samples; + txl->gtao_horizons = DRW_texture_create_2D_array((int)viewport_size[0], (int)viewport_size[1], effects->hori_tex_layers, DRW_TEX_RG_8, 0, NULL); + } + + DRWFboTexture tex = {&txl->gtao_horizons, DRW_TEX_RG_8, 0}; + + DRW_framebuffer_init(&fbl->gtao_fb, &draw_engine_eevee_type, + effects->ao_texsize[0], effects->ao_texsize[1], + &tex, 1); + + if (G.debug_value == 6) { + DRWFboTexture tex_debug = {&stl->g_data->gtao_horizons_debug, DRW_TEX_RGBA_8, DRW_TEX_TEMP}; + + DRW_framebuffer_init(&fbl->gtao_debug_fb, &draw_engine_eevee_type, + (int)viewport_size[0], (int)viewport_size[1], + &tex_debug, 1); + } + + return EFFECT_GTAO | EFFECT_NORMAL_BUFFER; + } + + /* Cleanup */ + DRW_TEXTURE_FREE_SAFE(txl->gtao_horizons); + DRW_FRAMEBUFFER_FREE_SAFE(fbl->gtao_fb); + effects->ao_settings = 0.0f; + + return 0; +} + +void EEVEE_occlusion_cache_init(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_EffectsInfo *effects = stl->effects; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + + struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get(); + + if ((effects->enabled_effects & EFFECT_GTAO) != 0) { + /** Occlusion algorithm overview + * + * We separate the computation into 2 steps. + * + * - First we scan the neighborhood pixels to find the maximum horizon angle. + * We save this angle in a RG8 array texture. + * + * - Then we use this angle to compute occlusion with the shading normal at + * the shading stage. This let us do correct shadowing for each diffuse / specular + * lobe present in the shader using the correct normal. + **/ + psl->ao_horizon_search = DRW_pass_create("GTAO Horizon Search", DRW_STATE_WRITE_COLOR); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.gtao_sh, psl->ao_horizon_search); + DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer); + DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); + DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10); + DRW_shgroup_uniform_vec4(grp, "aoParameters[0]", &stl->effects->ao_dist, 2); + DRW_shgroup_uniform_float(grp, "sampleNbr", &stl->effects->ao_sample_nbr, 1); + DRW_shgroup_uniform_ivec2(grp, "aoHorizonTexSize", (int *)stl->effects->ao_texsize, 1); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_call_add(grp, quad, NULL); + + if (G.debug_value == 6) { + psl->ao_horizon_debug = DRW_pass_create("GTAO Horizon Debug", DRW_STATE_WRITE_COLOR); + grp = DRW_shgroup_create(e_data.gtao_debug_sh, psl->ao_horizon_debug); + DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer); + DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input); + DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &txl->gtao_horizons); + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); + DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10); + DRW_shgroup_uniform_vec4(grp, "aoParameters[0]", &stl->effects->ao_dist, 2); + DRW_shgroup_uniform_ivec2(grp, "aoHorizonTexSize", (int *)stl->effects->ao_texsize, 1); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_call_add(grp, quad, NULL); + } + } +} + +void EEVEE_occlusion_compute(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + + if ((effects->enabled_effects & EFFECT_GTAO) != 0) { + DRW_stats_group_start("GTAO Horizon Scan"); + for (effects->ao_sample_nbr = 0.0; + effects->ao_sample_nbr < effects->ao_samples; + ++effects->ao_sample_nbr) + { + DRW_framebuffer_texture_detach(txl->gtao_horizons); + DRW_framebuffer_texture_layer_attach(fbl->gtao_fb, txl->gtao_horizons, 0, (int)effects->ao_sample_nbr, 0); + DRW_framebuffer_bind(fbl->gtao_fb); + + DRW_draw_pass(psl->ao_horizon_search); + } + + /* Restore */ + DRW_framebuffer_bind(fbl->main); + + DRW_stats_group_end(); + } +} + +void EEVEE_occlusion_draw_debug(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + + if (((effects->enabled_effects & EFFECT_GTAO) != 0) && (G.debug_value == 6)) { + DRW_stats_group_start("GTAO Debug"); + + DRW_framebuffer_texture_attach(fbl->gtao_debug_fb, stl->g_data->gtao_horizons_debug, 0, 0); + DRW_framebuffer_bind(fbl->gtao_debug_fb); + + DRW_draw_pass(psl->ao_horizon_debug); + + /* Restore */ + DRW_framebuffer_texture_detach(stl->g_data->gtao_horizons_debug); + DRW_framebuffer_bind(fbl->main); + + DRW_stats_group_end(); + } +} + +void EEVEE_occlusion_free(void) +{ + DRW_SHADER_FREE_SAFE(e_data.gtao_sh); + DRW_SHADER_FREE_SAFE(e_data.gtao_debug_sh); +} diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 38d4a4b52e1..ff4d194fb01 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -66,6 +66,27 @@ extern struct DrawEngineType draw_engine_eevee_type; "#define MAX_CASCADE_NUM " STRINGIFY(MAX_CASCADE_NUM) "\n" \ SHADER_IRRADIANCE +#define SWAP_DOUBLE_BUFFERS() { \ + if (effects->swap_double_buffer) { \ + SWAP(struct GPUFrameBuffer *, fbl->main, fbl->double_buffer); \ + SWAP(GPUTexture *, txl->color, txl->color_double_buffer); \ + effects->swap_double_buffer = false; \ + } \ +} ((void)0) + +#define SWAP_BUFFERS() { \ + if (effects->target_buffer != fbl->main) { \ + SWAP_DOUBLE_BUFFERS(); \ + effects->source_buffer = txl->color_post; \ + effects->target_buffer = fbl->main; \ + } \ + else { \ + SWAP_DOUBLE_BUFFERS(); \ + effects->source_buffer = txl->color; \ + effects->target_buffer = fbl->effect_fb; \ + } \ +} ((void)0) + /* World shader variations */ enum { VAR_WORLD_BACKGROUND = 0, @@ -396,6 +417,7 @@ enum { /* ************ EFFECTS DATA ************* */ typedef struct EEVEE_EffectsInfo { int enabled_effects; + bool swap_double_buffer; /* Volumetrics */ bool use_volumetrics; @@ -472,6 +494,8 @@ enum { EFFECT_REFRACT = (1 << 6), EFFECT_GTAO = (1 << 7), EFFECT_TAA = (1 << 8), + EFFECT_POST_BUFFER = (1 << 9), /* Not really an effect but a feature */ + EFFECT_NORMAL_BUFFER = (1 << 10), /* Not really an effect but a feature */ }; /* ************** SCENE LAYER DATA ************** */ @@ -631,19 +655,61 @@ void EEVEE_lightprobes_cache_finish(EEVEE_SceneLayerData *sldata, EEVEE_Data *ve void EEVEE_lightprobes_refresh(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); void EEVEE_lightprobes_free(void); +/* eevee_depth_of_field.c */ +int EEVEE_depth_of_field_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_depth_of_field_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_depth_of_field_draw(EEVEE_Data *vedata); +void EEVEE_depth_of_field_free(void); + +/* eevee_bloom.c */ +int EEVEE_bloom_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_bloom_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_bloom_draw(EEVEE_Data *vedata); +void EEVEE_bloom_free(void); + +/* eevee_occlusion.c */ +int EEVEE_occlusion_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_occlusion_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_occlusion_compute(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_occlusion_draw_debug(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_occlusion_free(void); + +/* eevee_screen_raytrace.c */ +int EEVEE_screen_raytrace_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_screen_raytrace_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_refraction_compute(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_reflection_compute(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_screen_raytrace_free(void); + +/* eevee_motion_blur.c */ +int EEVEE_motion_blur_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_motion_blur_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_motion_blur_draw(EEVEE_Data *vedata); +void EEVEE_motion_blur_free(void); + +/* eevee_temporal_sampling.c */ +int EEVEE_temporal_sampling_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_temporal_sampling_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata); +void EEVEE_temporal_sampling_free(void); + +/* eevee_volumes.c */ +int EEVEE_volumes_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_volumes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_volumes_cache_object_add(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, struct Scene *scene, Object *ob); +void EEVEE_volumes_compute(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_volumes_resolve(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_volumes_free_smoke_textures(void); +void EEVEE_volumes_free(void); + /* eevee_effects.c */ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); -void EEVEE_effects_cache_volume_object_add(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, struct Scene *scene, Object *ob); void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer); void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, struct GPUTexture *texture_src, int level); void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, struct GPUTexture *texture_src, int level); -void EEVEE_effects_do_volumetrics(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); -void EEVEE_effects_do_ssr(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); -void EEVEE_effects_do_refraction(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); void EEVEE_effects_do_gtao(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata); void EEVEE_draw_effects(EEVEE_Data *vedata); -void EEVEE_effects_free_smoke_texture(void); void EEVEE_effects_free(void); /* Shadow Matrix */ diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c new file mode 100644 index 00000000000..b4e81c0e49a --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -0,0 +1,337 @@ +/* + * 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 + * + */ + +/* Screen space reflections and refractions techniques. + */ + +/** \file eevee_screen_raytrace.c + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "BLI_dynstr.h" + +#include "eevee_private.h" +#include "GPU_texture.h" + +/* SSR shader variations */ +enum { + SSR_SAMPLES = (1 << 0) | (1 << 1), + SSR_RESOLVE = (1 << 2), + SSR_FULL_TRACE = (1 << 3), + SSR_MAX_SHADER = (1 << 4), +}; + +static struct { + /* Screen Space Reflection */ + struct GPUShader *ssr_sh[SSR_MAX_SHADER]; + + /* Theses are just references, not actually allocated */ + struct GPUTexture *depth_src; + struct GPUTexture *color_src; +} e_data = {NULL}; /* Engine data */ + +extern char datatoc_ambient_occlusion_lib_glsl[]; +extern char datatoc_bsdf_common_lib_glsl[]; +extern char datatoc_bsdf_sampling_lib_glsl[]; +extern char datatoc_octahedron_lib_glsl[]; +extern char datatoc_effect_ssr_frag_glsl[]; +extern char datatoc_lightprobe_lib_glsl[]; +extern char datatoc_raytrace_lib_glsl[]; + +static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options) +{ + if (e_data.ssr_sh[options] == NULL) { + DynStr *ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_ambient_occlusion_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_raytrace_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_effect_ssr_frag_glsl); + char *ssr_shader_str = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); + + int samples = (SSR_SAMPLES & options) + 1; + + DynStr *ds_defines = BLI_dynstr_new(); + BLI_dynstr_appendf(ds_defines, SHADER_DEFINES); + BLI_dynstr_appendf(ds_defines, "#define RAY_COUNT %d\n", samples); + if (options & SSR_RESOLVE) { + BLI_dynstr_appendf(ds_defines, "#define STEP_RESOLVE\n"); + } + else { + BLI_dynstr_appendf(ds_defines, "#define STEP_RAYTRACE\n"); + BLI_dynstr_appendf(ds_defines, "#define PLANAR_PROBE_RAYTRACE\n"); + } + if (options & SSR_FULL_TRACE) { + BLI_dynstr_appendf(ds_defines, "#define FULLRES\n"); + } + char *ssr_define_str = BLI_dynstr_get_cstring(ds_defines); + BLI_dynstr_free(ds_defines); + + e_data.ssr_sh[options] = DRW_shader_create_fullscreen(ssr_shader_str, ssr_define_str); + + MEM_freeN(ssr_shader_str); + MEM_freeN(ssr_define_str); + } + + return e_data.ssr_sh[options]; +} + +int EEVEE_screen_raytrace_init(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_EffectsInfo *effects = stl->effects; + const float *viewport_size = DRW_viewport_size_get(); + + const DRWContextState *draw_ctx = DRW_context_state_get(); + SceneLayer *scene_layer = draw_ctx->scene_layer; + IDProperty *props = BKE_scene_layer_engine_evaluated_get(scene_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); + + /* Compute pixel size, (shared with contact shadows) */ + copy_v2_v2(effects->ssr_pixelsize, viewport_size); + invert_v2(effects->ssr_pixelsize); + + if (BKE_collection_engine_property_value_get_bool(props, "ssr_enable")) { + const bool use_refraction = BKE_collection_engine_property_value_get_bool(props, "ssr_refraction"); + + if (use_refraction) { + DRWFboTexture tex = {&txl->refract_color, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP}; + + DRW_framebuffer_init(&fbl->refract_fb, &draw_engine_eevee_type, (int)viewport_size[0], (int)viewport_size[1], &tex, 1); + } + + effects->ssr_ray_count = BKE_collection_engine_property_value_get_int(props, "ssr_ray_count"); + effects->reflection_trace_full = !BKE_collection_engine_property_value_get_bool(props, "ssr_halfres"); + effects->ssr_use_normalization = BKE_collection_engine_property_value_get_bool(props, "ssr_normalize_weight"); + effects->ssr_quality = 1.0f - BKE_collection_engine_property_value_get_float(props, "ssr_quality"); + effects->ssr_thickness = BKE_collection_engine_property_value_get_float(props, "ssr_thickness"); + effects->ssr_border_fac = BKE_collection_engine_property_value_get_float(props, "ssr_border_fade"); + effects->ssr_firefly_fac = BKE_collection_engine_property_value_get_float(props, "ssr_firefly_fac"); + effects->ssr_max_roughness = BKE_collection_engine_property_value_get_float(props, "ssr_max_roughness"); + + if (effects->ssr_firefly_fac < 1e-8f) { + effects->ssr_firefly_fac = FLT_MAX; + } + + /* Important, can lead to breakage otherwise. */ + CLAMP(effects->ssr_ray_count, 1, 4); + + const int divisor = (effects->reflection_trace_full) ? 1 : 2; + int tracing_res[2] = {(int)viewport_size[0] / divisor, (int)viewport_size[1] / divisor}; + const bool high_qual_input = true; /* TODO dither low quality input */ + + /* MRT for the shading pass in order to output needed data for the SSR pass. */ + /* TODO create one texture layer per lobe */ + if (txl->ssr_specrough_input == NULL) { + DRWTextureFormat specrough_format = (high_qual_input) ? DRW_TEX_RGBA_16 : DRW_TEX_RGBA_8; + txl->ssr_specrough_input = DRW_texture_create_2D((int)viewport_size[0], (int)viewport_size[1], specrough_format, 0, NULL); + } + + /* Reattach textures to the right buffer (because we are alternating between buffers) */ + /* TODO multiple FBO per texture!!!! */ + DRW_framebuffer_texture_detach(txl->ssr_specrough_input); + DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 2, 0); + + /* Raytracing output */ + /* TODO try integer format for hit coord to increase precision */ + DRWFboTexture tex_output[4] = {{&stl->g_data->ssr_hit_output[0], DRW_TEX_RGBA_16, DRW_TEX_TEMP}, + {&stl->g_data->ssr_hit_output[1], DRW_TEX_RGBA_16, DRW_TEX_TEMP}, + {&stl->g_data->ssr_hit_output[2], DRW_TEX_RGBA_16, DRW_TEX_TEMP}, + {&stl->g_data->ssr_hit_output[3], DRW_TEX_RGBA_16, DRW_TEX_TEMP}}; + + DRW_framebuffer_init(&fbl->screen_tracing_fb, &draw_engine_eevee_type, tracing_res[0], tracing_res[1], tex_output, effects->ssr_ray_count); + + /* Enable double buffering to be able to read previous frame color */ + return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_DOUBLE_BUFFER | ((use_refraction) ? EFFECT_REFRACT : 0); + } + + /* Cleanup to release memory */ + DRW_TEXTURE_FREE_SAFE(txl->ssr_specrough_input); + DRW_FRAMEBUFFER_FREE_SAFE(fbl->screen_tracing_fb); + for (int i = 0; i < 4; ++i) { + stl->g_data->ssr_hit_output[i] = NULL; + } + + return 0; +} + +void EEVEE_screen_raytrace_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_EffectsInfo *effects = stl->effects; + + struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get(); + + if ((effects->enabled_effects & EFFECT_SSR) != 0) { + int options = (effects->reflection_trace_full) ? SSR_FULL_TRACE : 0; + options |= (effects->ssr_ray_count - 1); + + struct GPUShader *trace_shader = eevee_effects_screen_raytrace_shader_get(options); + struct GPUShader *resolve_shader = eevee_effects_screen_raytrace_shader_get(SSR_RESOLVE | options); + + /** Screen space raytracing overview + * + * Following Frostbite stochastic SSR. + * + * - First pass Trace rays accross the depth buffer. The hit position and pdf are + * recorded in a RGBA16F render target for each ray (sample). + * + * - We downsample the previous frame color buffer. + * + * - For each final pixel, we gather neighboors rays and choose a color buffer + * mipmap for each ray using its pdf. (filtered importance sampling) + * We then evaluate the lighting from the probes and mix the results together. + */ + psl->ssr_raytrace = DRW_pass_create("SSR Raytrace", DRW_STATE_WRITE_COLOR); + DRWShadingGroup *grp = DRW_shgroup_create(trace_shader, psl->ssr_raytrace); + DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); + DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input); + DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &txl->ssr_specrough_input); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer); + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); + DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10); + DRW_shgroup_uniform_vec4(grp, "ssrParameters", &effects->ssr_quality, 1); + DRW_shgroup_uniform_int(grp, "planar_count", &sldata->probes->num_planar, 1); + DRW_shgroup_uniform_float(grp, "maxRoughness", &effects->ssr_max_roughness, 1); + DRW_shgroup_uniform_buffer(grp, "planarDepth", &vedata->txl->planar_depth); + DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); + DRW_shgroup_call_add(grp, quad, NULL); + + psl->ssr_resolve = DRW_pass_create("SSR Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); + grp = DRW_shgroup_create(resolve_shader, psl->ssr_resolve); + DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); + DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input); + DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &txl->ssr_specrough_input); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_buffer(grp, "prevColorBuffer", &txl->color_double_buffer); + DRW_shgroup_uniform_mat4(grp, "PastViewProjectionMatrix", (float *)stl->g_data->prev_persmat); + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); + DRW_shgroup_uniform_int(grp, "planar_count", &sldata->probes->num_planar, 1); + DRW_shgroup_uniform_int(grp, "probe_count", &sldata->probes->num_render_cube, 1); + DRW_shgroup_uniform_vec2(grp, "mipRatio[0]", (float *)stl->g_data->mip_ratio, 10); + DRW_shgroup_uniform_float(grp, "borderFadeFactor", &effects->ssr_border_fac, 1); + DRW_shgroup_uniform_float(grp, "maxRoughness", &effects->ssr_max_roughness, 1); + DRW_shgroup_uniform_float(grp, "lodCubeMax", &sldata->probes->lod_cube_max, 1); + DRW_shgroup_uniform_float(grp, "lodPlanarMax", &sldata->probes->lod_planar_max, 1); + DRW_shgroup_uniform_float(grp, "fireflyFactor", &effects->ssr_firefly_fac, 1); + DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); + DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); + DRW_shgroup_uniform_buffer(grp, "probeCubes", &sldata->probe_pool); + DRW_shgroup_uniform_buffer(grp, "probePlanars", &vedata->txl->planar_pool); + DRW_shgroup_uniform_buffer(grp, "hitBuffer0", &stl->g_data->ssr_hit_output[0]); + if (effects->ssr_ray_count > 1) { + DRW_shgroup_uniform_buffer(grp, "hitBuffer1", &stl->g_data->ssr_hit_output[1]); + } + if (effects->ssr_ray_count > 2) { + DRW_shgroup_uniform_buffer(grp, "hitBuffer2", &stl->g_data->ssr_hit_output[2]); + } + if (effects->ssr_ray_count > 3) { + DRW_shgroup_uniform_buffer(grp, "hitBuffer3", &stl->g_data->ssr_hit_output[3]); + } + + DRW_shgroup_uniform_vec4(grp, "aoParameters[0]", &effects->ao_dist, 2); + if (effects->use_ao) { + DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &vedata->txl->gtao_horizons); + DRW_shgroup_uniform_ivec2(grp, "aoHorizonTexSize", (int *)vedata->stl->effects->ao_texsize, 1); + } + else { + /* Use shadow_pool as fallback to avoid sampling problem on certain platform, see: T52593 */ + DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &sldata->shadow_pool); + } + + DRW_shgroup_call_add(grp, quad, NULL); + } +} + +void EEVEE_refraction_compute(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + + if ((effects->enabled_effects & EFFECT_REFRACT) != 0) { + DRW_framebuffer_texture_attach(fbl->refract_fb, txl->refract_color, 0, 0); + DRW_framebuffer_blit(fbl->main, fbl->refract_fb, false); + EEVEE_downsample_buffer(vedata, fbl->downsample_fb, txl->refract_color, 9); + } +} + +void EEVEE_reflection_compute(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_EffectsInfo *effects = stl->effects; + + if (((effects->enabled_effects & EFFECT_SSR) != 0) && stl->g_data->valid_double_buffer) { + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + e_data.depth_src = dtxl->depth; + + DRW_stats_group_start("SSR"); + + for (int i = 0; i < effects->ssr_ray_count; ++i) { + DRW_framebuffer_texture_attach(fbl->screen_tracing_fb, stl->g_data->ssr_hit_output[i], i, 0); + } + DRW_framebuffer_bind(fbl->screen_tracing_fb); + + /* Raytrace. */ + DRW_draw_pass(psl->ssr_raytrace); + + for (int i = 0; i < effects->ssr_ray_count; ++i) { + DRW_framebuffer_texture_detach(stl->g_data->ssr_hit_output[i]); + } + + EEVEE_downsample_buffer(vedata, fbl->downsample_fb, txl->color_double_buffer, 9); + + /* Resolve at fullres */ + DRW_framebuffer_texture_detach(dtxl->depth); + DRW_framebuffer_texture_detach(txl->ssr_normal_input); + DRW_framebuffer_texture_detach(txl->ssr_specrough_input); + DRW_framebuffer_bind(fbl->main); + DRW_draw_pass(psl->ssr_resolve); + + /* Restore */ + DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0); + DRW_framebuffer_texture_attach(fbl->main, txl->ssr_normal_input, 1, 0); + DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 2, 0); + DRW_framebuffer_bind(fbl->main); + + DRW_stats_group_end(); + } +} + +void EEVEE_screen_raytrace_free(void) +{ + for (int i = 0; i < SSR_MAX_SHADER; ++i) { + DRW_SHADER_FREE_SAFE(e_data.ssr_sh[i]); + } +} diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c new file mode 100644 index 00000000000..02becfb260f --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c @@ -0,0 +1,197 @@ +/* + * 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 + * + */ + +/* Temporal super sampling technique + */ + +/** \file eevee_temporal_sampling.c + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "BLI_rand.h" + +#include "eevee_private.h" +#include "GPU_texture.h" + +static struct { + /* Temporal Anti Aliasing */ + struct GPUShader *taa_resolve_sh; +} e_data = {NULL}; /* Engine data */ + +extern char datatoc_effect_temporal_aa_glsl[]; + +static void eevee_create_shader_temporal_sampling(void) +{ + e_data.taa_resolve_sh = DRW_shader_create_fullscreen(datatoc_effect_temporal_aa_glsl, NULL); +} + +int EEVEE_temporal_sampling_init(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_EffectsInfo *effects = stl->effects; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + SceneLayer *scene_layer = draw_ctx->scene_layer; + IDProperty *props = BKE_scene_layer_engine_evaluated_get(scene_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); + + if (BKE_collection_engine_property_value_get_int(props, "taa_samples") != 1 && + /* FIXME the motion blur camera evaluation is tagging view_updated + * thus making the TAA always reset and never stopping rendering. */ + (effects->enabled_effects & EFFECT_MOTION_BLUR) == 0) + { + const float *viewport_size = DRW_viewport_size_get(); + float persmat[4][4], viewmat[4][4]; + + if (!e_data.taa_resolve_sh) { + eevee_create_shader_temporal_sampling(); + } + + /* Until we support reprojection, we need to make sure + * that the history buffer contains correct information. */ + bool view_is_valid = stl->g_data->valid_double_buffer; + + view_is_valid = view_is_valid && (stl->g_data->view_updated == false); + + effects->taa_total_sample = BKE_collection_engine_property_value_get_int(props, "taa_samples"); + MAX2(effects->taa_total_sample, 0); + + DRW_viewport_matrix_get(persmat, DRW_MAT_PERS); + DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW); + DRW_viewport_matrix_get(effects->overide_winmat, DRW_MAT_WIN); + view_is_valid = view_is_valid && compare_m4m4(persmat, effects->prev_drw_persmat, FLT_MIN); + copy_m4_m4(effects->prev_drw_persmat, persmat); + + /* Prevent ghosting from probe data. */ + view_is_valid = view_is_valid && (effects->prev_drw_support == DRW_state_draw_support()); + effects->prev_drw_support = DRW_state_draw_support(); + + if (view_is_valid && + ((effects->taa_total_sample == 0) || + (effects->taa_current_sample < effects->taa_total_sample))) + { + effects->taa_current_sample += 1; + + effects->taa_alpha = 1.0f / (float)(effects->taa_current_sample); + + double ht_point[2]; + double ht_offset[2] = {0.0, 0.0}; + unsigned int ht_primes[2] = {2, 3}; + + BLI_halton_2D(ht_primes, ht_offset, effects->taa_current_sample - 1, ht_point); + + window_translate_m4( + effects->overide_winmat, persmat, + ((float)(ht_point[0]) * 2.0f - 1.0f) / viewport_size[0], + ((float)(ht_point[1]) * 2.0f - 1.0f) / viewport_size[1]); + + mul_m4_m4m4(effects->overide_persmat, effects->overide_winmat, viewmat); + invert_m4_m4(effects->overide_persinv, effects->overide_persmat); + invert_m4_m4(effects->overide_wininv, effects->overide_winmat); + + DRW_viewport_matrix_override_set(effects->overide_persmat, DRW_MAT_PERS); + DRW_viewport_matrix_override_set(effects->overide_persinv, DRW_MAT_PERSINV); + DRW_viewport_matrix_override_set(effects->overide_winmat, DRW_MAT_WIN); + DRW_viewport_matrix_override_set(effects->overide_wininv, DRW_MAT_WININV); + } + else { + effects->taa_current_sample = 1; + } + + DRWFboTexture tex_double_buffer = {&txl->depth_double_buffer, DRW_TEX_DEPTH_24}; + + DRW_framebuffer_init(&fbl->depth_double_buffer_fb, &draw_engine_eevee_type, + (int)viewport_size[0], (int)viewport_size[1], + &tex_double_buffer, 1); + + return EFFECT_TAA | EFFECT_DOUBLE_BUFFER | EFFECT_POST_BUFFER; + } + + /* Cleanup to release memory */ + DRW_TEXTURE_FREE_SAFE(txl->depth_double_buffer); + DRW_FRAMEBUFFER_FREE_SAFE(fbl->depth_double_buffer_fb); + + return 0; +} + +void EEVEE_temporal_sampling_cache_init(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_EffectsInfo *effects = stl->effects; + + if ((effects->enabled_effects & EFFECT_TAA) != 0) { + psl->taa_resolve = DRW_pass_create("Temporal AA Resolve", DRW_STATE_WRITE_COLOR); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.taa_resolve_sh, psl->taa_resolve); + + DRW_shgroup_uniform_buffer(grp, "historyBuffer", &txl->color_double_buffer); + DRW_shgroup_uniform_buffer(grp, "colorBuffer", &txl->color); + DRW_shgroup_uniform_float(grp, "alpha", &effects->taa_alpha, 1); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + } +} + +void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + + if ((effects->enabled_effects & EFFECT_TAA) != 0) { + if (effects->taa_current_sample != 1) { + DRW_framebuffer_bind(fbl->effect_fb); + DRW_draw_pass(psl->taa_resolve); + + /* Restore the depth from sample 1. */ + DRW_framebuffer_blit(fbl->depth_double_buffer_fb, fbl->main, true); + + /* Special Swap */ + SWAP(struct GPUFrameBuffer *, fbl->effect_fb, fbl->double_buffer); + SWAP(GPUTexture *, txl->color_post, txl->color_double_buffer); + effects->swap_double_buffer = false; + effects->source_buffer = txl->color_double_buffer; + effects->target_buffer = fbl->main; + } + else { + /* Save the depth buffer for the next frame. + * This saves us from doing anything special + * in the other mode engines. */ + DRW_framebuffer_blit(fbl->main, fbl->depth_double_buffer_fb, true); + } + + if ((effects->taa_total_sample == 0) || + (effects->taa_current_sample < effects->taa_total_sample)) + { + DRW_viewport_request_redraw(); + } + } +} + +void EEVEE_temporal_sampling_free(void) +{ + DRW_SHADER_FREE_SAFE(e_data.taa_resolve_sh); +} diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c new file mode 100644 index 00000000000..d604240f4ef --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -0,0 +1,578 @@ +/* + * 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 + * + */ + +/* Volumetric effects rendering using frostbite approach. + */ + +/** \file eevee_volume.c + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "DNA_object_force.h" +#include "DNA_smoke_types.h" +#include "DNA_world_types.h" + +#include "BKE_global.h" /* for G.debug_value */ +#include "BKE_modifier.h" +#include "BKE_mesh.h" +#include "BKE_object.h" + +#include "ED_screen.h" + +#include "BLI_dynstr.h" +#include "BLI_rand.h" + +#include "eevee_private.h" +#include "GPU_draw.h" +#include "GPU_texture.h" + +static struct { + char *volumetric_common_lib; + char *volumetric_common_lamps_lib; + + struct GPUShader *volumetric_clear_sh; + struct GPUShader *volumetric_scatter_sh; + struct GPUShader *volumetric_integration_sh; + struct GPUShader *volumetric_resolve_sh; + + GPUTexture *color_src; + GPUTexture *depth_src; + + /* List of all smoke domains rendered within this frame. */ + ListBase smoke_domains; +} e_data = {NULL}; /* Engine data */ + +extern char datatoc_bsdf_common_lib_glsl[]; +extern char datatoc_bsdf_direct_lib_glsl[]; +extern char datatoc_octahedron_lib_glsl[]; +extern char datatoc_irradiance_lib_glsl[]; +extern char datatoc_lamps_lib_glsl[]; +extern char datatoc_volumetric_frag_glsl[]; +extern char datatoc_volumetric_geom_glsl[]; +extern char datatoc_volumetric_vert_glsl[]; +extern char datatoc_volumetric_resolve_frag_glsl[]; +extern char datatoc_volumetric_scatter_frag_glsl[]; +extern char datatoc_volumetric_integration_frag_glsl[]; +extern char datatoc_volumetric_lib_glsl[]; +extern char datatoc_gpu_shader_fullscreen_vert_glsl[]; + +static void eevee_create_shader_volumes(void) +{ + DynStr *ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_volumetric_lib_glsl); + e_data.volumetric_common_lib = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); + + ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_lamps_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_volumetric_lib_glsl); + e_data.volumetric_common_lamps_lib = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); + + e_data.volumetric_clear_sh = DRW_shader_create_with_lib(datatoc_volumetric_vert_glsl, + datatoc_volumetric_geom_glsl, + datatoc_volumetric_frag_glsl, + e_data.volumetric_common_lib, + "#define VOLUMETRICS\n" + "#define CLEAR\n"); + e_data.volumetric_scatter_sh = DRW_shader_create_with_lib(datatoc_volumetric_vert_glsl, + datatoc_volumetric_geom_glsl, + datatoc_volumetric_scatter_frag_glsl, + e_data.volumetric_common_lamps_lib, + SHADER_DEFINES + "#define VOLUMETRICS\n" + "#define VOLUME_SHADOW\n"); + e_data.volumetric_integration_sh = DRW_shader_create_with_lib(datatoc_volumetric_vert_glsl, + datatoc_volumetric_geom_glsl, + datatoc_volumetric_integration_frag_glsl, + e_data.volumetric_common_lib, NULL); + e_data.volumetric_resolve_sh = DRW_shader_create_with_lib(datatoc_gpu_shader_fullscreen_vert_glsl, NULL, + datatoc_volumetric_resolve_frag_glsl, + e_data.volumetric_common_lib, NULL); +} + +int EEVEE_volumes_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_EffectsInfo *effects = stl->effects; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + SceneLayer *scene_layer = draw_ctx->scene_layer; + IDProperty *props = BKE_scene_layer_engine_evaluated_get(scene_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); + + const float *viewport_size = DRW_viewport_size_get(); + + BLI_listbase_clear(&e_data.smoke_domains); + + if (BKE_collection_engine_property_value_get_bool(props, "volumetric_enable")) { + + /* Shaders */ + if (!e_data.volumetric_scatter_sh) { + eevee_create_shader_volumes(); + } + + if (sldata->volumetrics == NULL) { + sldata->volumetrics = MEM_callocN(sizeof(EEVEE_VolumetricsInfo), "EEVEE_VolumetricsInfo"); + } + + EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics; + + int tile_size = BKE_collection_engine_property_value_get_int(props, "volumetric_tile_size"); + + /* Find Froxel Texture resolution. */ + int froxel_tex_size[3]; + + froxel_tex_size[0] = (int)ceilf(fmaxf(1.0f, viewport_size[0] / (float)tile_size)); + froxel_tex_size[1] = (int)ceilf(fmaxf(1.0f, viewport_size[1] / (float)tile_size)); + froxel_tex_size[2] = max_ii(BKE_collection_engine_property_value_get_int(props, "volumetric_samples"), 1); + + volumetrics->volume_coord_scale[0] = viewport_size[0] / (float)(tile_size * froxel_tex_size[0]); + volumetrics->volume_coord_scale[1] = viewport_size[1] / (float)(tile_size * froxel_tex_size[1]); + + /* TODO compute snap to maxZBuffer for clustered rendering */ + + if ((volumetrics->froxel_tex_size[0] != froxel_tex_size[0]) || + (volumetrics->froxel_tex_size[1] != froxel_tex_size[1]) || + (volumetrics->froxel_tex_size[2] != froxel_tex_size[2])) + { + DRW_TEXTURE_FREE_SAFE(txl->volume_prop_scattering); + DRW_TEXTURE_FREE_SAFE(txl->volume_prop_extinction); + DRW_TEXTURE_FREE_SAFE(txl->volume_prop_emission); + DRW_TEXTURE_FREE_SAFE(txl->volume_prop_phase); + DRW_TEXTURE_FREE_SAFE(txl->volume_scatter); + DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance); + DRW_TEXTURE_FREE_SAFE(txl->volume_scatter_history); + DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance_history); + DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb); + DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb); + DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb); + volumetrics->froxel_tex_size[0] = froxel_tex_size[0]; + volumetrics->froxel_tex_size[1] = froxel_tex_size[1]; + volumetrics->froxel_tex_size[2] = froxel_tex_size[2]; + + volumetrics->inv_tex_size[0] = 1.0f / (float)(volumetrics->froxel_tex_size[0]); + volumetrics->inv_tex_size[1] = 1.0f / (float)(volumetrics->froxel_tex_size[1]); + volumetrics->inv_tex_size[2] = 1.0f / (float)(volumetrics->froxel_tex_size[2]); + } + + /* Like frostbite's paper, 5% blend of the new frame. */ + volumetrics->history_alpha = (txl->volume_prop_scattering == NULL) ? 0.0f : 0.95f; + + if (txl->volume_prop_scattering == NULL) { + /* Volume properties: We evaluate all volumetric objects + * and store their final properties into each froxel */ + txl->volume_prop_scattering = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_prop_extinction = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_prop_emission = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_prop_phase = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RG_16, DRW_TEX_FILTER, NULL); + + /* Volume scattering: We compute for each froxel the + * Scattered light towards the view. We also resolve temporal + * super sampling during this stage. */ + txl->volume_scatter = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_transmittance = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + + /* Final integration: We compute for each froxel the + * amount of scattered light and extinction coef at this + * given depth. We use theses textures as double buffer + * for the volumetric history. */ + txl->volume_scatter_history = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + txl->volume_transmittance_history = DRW_texture_create_3D(froxel_tex_size[0], froxel_tex_size[1], froxel_tex_size[2], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER, NULL); + } + + /* Temporal Super sampling jitter */ + double ht_point[3]; + double ht_offset[3] = {0.0, 0.0}; + unsigned int ht_primes[3] = {3, 7, 2}; + unsigned int current_sample = 0; + + /* If TAA is in use do not use the history buffer. */ + bool do_taa = ((effects->enabled_effects & EFFECT_TAA) != 0); + + if (draw_ctx->evil_C != NULL) { + struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); + do_taa = do_taa && (ED_screen_animation_no_scrub(wm) == NULL); + } + + if (do_taa) { + volumetrics->history_alpha = 0.0f; + current_sample = effects->taa_current_sample - 1; + effects->volume_current_sample = -1; + } + else { + const unsigned int max_sample = (ht_primes[0] * ht_primes[1] * ht_primes[2]); + current_sample = effects->volume_current_sample = (effects->volume_current_sample + 1) % max_sample; + if (current_sample != max_sample - 1) { + DRW_viewport_request_redraw(); + } + } + BLI_halton_3D(ht_primes, ht_offset, current_sample, ht_point); + + volumetrics->jitter[0] = (float)ht_point[0]; + volumetrics->jitter[1] = (float)ht_point[1]; + volumetrics->jitter[2] = (float)ht_point[2]; + + /* Framebuffer setup */ + DRWFboTexture tex_vol[4] = {{&txl->volume_prop_scattering, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, + {&txl->volume_prop_extinction, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, + {&txl->volume_prop_emission, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, + {&txl->volume_prop_phase, DRW_TEX_RG_16, DRW_TEX_FILTER}}; + + DRW_framebuffer_init(&fbl->volumetric_fb, &draw_engine_eevee_type, + (int)froxel_tex_size[0], (int)froxel_tex_size[1], + tex_vol, 4); + + DRWFboTexture tex_vol_scat[2] = {{&txl->volume_scatter, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, + {&txl->volume_transmittance, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}}; + + DRW_framebuffer_init(&fbl->volumetric_scat_fb, &draw_engine_eevee_type, + (int)froxel_tex_size[0], (int)froxel_tex_size[1], + tex_vol_scat, 2); + + DRWFboTexture tex_vol_integ[2] = {{&txl->volume_scatter_history, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, + {&txl->volume_transmittance_history, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}}; + + DRW_framebuffer_init(&fbl->volumetric_integ_fb, &draw_engine_eevee_type, + (int)froxel_tex_size[0], (int)froxel_tex_size[1], + tex_vol_integ, 2); + + volumetrics->integration_start = BKE_collection_engine_property_value_get_float(props, "volumetric_start"); + volumetrics->integration_end = BKE_collection_engine_property_value_get_float(props, "volumetric_end"); + volumetrics->sample_distribution = 4.0f * (1.00001f - BKE_collection_engine_property_value_get_float(props, "volumetric_sample_distribution")); + volumetrics->use_volume_shadows = BKE_collection_engine_property_value_get_bool(props, "volumetric_shadows"); + volumetrics->light_clamp = BKE_collection_engine_property_value_get_float(props, "volumetric_light_clamp"); + + if (volumetrics->use_volume_shadows) { + volumetrics->shadow_step_count = (float)BKE_collection_engine_property_value_get_int(props, "volumetric_shadow_samples"); + } + else { + volumetrics->shadow_step_count = 0; + } + + if (DRW_viewport_is_persp_get()) { + const float clip_start = stl->g_data->viewvecs[0][2]; + /* Negate */ + float near = volumetrics->integration_start = min_ff(-volumetrics->integration_start, clip_start - 1e-4f); + float far = volumetrics->integration_end = min_ff(-volumetrics->integration_end, near - 1e-4f); + + volumetrics->depth_param[0] = (far - near * exp2(1.0f / volumetrics->sample_distribution)) / (far - near); + volumetrics->depth_param[1] = (1.0f - volumetrics->depth_param[0]) / near; + volumetrics->depth_param[2] = volumetrics->sample_distribution; + } + else { + const float clip_start = stl->g_data->viewvecs[0][2]; + const float clip_end = stl->g_data->viewvecs[1][2]; + volumetrics->integration_start = min_ff(volumetrics->integration_end, clip_start); + volumetrics->integration_end = max_ff(-volumetrics->integration_end, clip_end); + + volumetrics->depth_param[0] = volumetrics->integration_start; + volumetrics->depth_param[1] = volumetrics->integration_end; + volumetrics->depth_param[2] = 1.0f / (volumetrics->integration_end - volumetrics->integration_start); + } + + /* Disable clamp if equal to 0. */ + if (volumetrics->light_clamp == 0.0) { + volumetrics->light_clamp = FLT_MAX; + } + + volumetrics->use_lights = BKE_collection_engine_property_value_get_bool(props, "volumetric_lights"); + + return EFFECT_VOLUMETRIC; + } + + /* Cleanup to release memory */ + DRW_TEXTURE_FREE_SAFE(txl->volume_prop_scattering); + DRW_TEXTURE_FREE_SAFE(txl->volume_prop_extinction); + DRW_TEXTURE_FREE_SAFE(txl->volume_prop_emission); + DRW_TEXTURE_FREE_SAFE(txl->volume_prop_phase); + DRW_TEXTURE_FREE_SAFE(txl->volume_scatter); + DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance); + DRW_TEXTURE_FREE_SAFE(txl->volume_scatter_history); + DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance_history); + DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb); + DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb); + DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb); + + return 0; +} + +void EEVEE_volumes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_EffectsInfo *effects = stl->effects; + + if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) { + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics; + static int zero = 0; + DRWShadingGroup *grp; + + /* Quick breakdown of the Volumetric rendering: + * + * The rendering is separated in 4 stages: + * + * - Material Parameters : we collect volume properties of + * all participating media in the scene and store them in + * a 3D texture aligned with the 3D frustum. + * This is done in 2 passes, one that clear the texture + * and/or evaluate the world volumes, and the 2nd one that + * additively render object volumes. + * + * - Light Scattering : the volume properties then are sampled + * and light scattering is evaluated for each cell of the + * volume texture. Temporal supersampling (if enabled) occurs here. + * + * - Volume Integration : the scattered light and extinction is + * integrated (accumulated) along the viewrays. The result is stored + * for every cell in another texture. + * + * - Fullscreen Resolve : From the previous stage, we get two + * 3D textures that contains integrated scatered light and extinction + * for "every" positions in the frustum. We only need to sample + * them and blend the scene color with thoses factors. This also + * work for alpha blended materials. + **/ + + /* World pass is not additive as it also clear the buffer. */ + psl->volumetric_world_ps = DRW_pass_create("Volumetric World", DRW_STATE_WRITE_COLOR); + + /* World Volumetric */ + struct World *wo = scene->world; + if (wo != NULL && wo->use_nodes && wo->nodetree) { + struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo); + + grp = DRW_shgroup_material_empty_tri_batch_create(mat, psl->volumetric_world_ps, volumetrics->froxel_tex_size[2]); + + if (grp) { + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); + DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1); + DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); + DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); + DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1); + } + } + else { + /* If no world or volume material is present just clear the buffer with this drawcall */ + grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_clear_sh, psl->volumetric_world_ps, volumetrics->froxel_tex_size[2]); + + DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1); + } + + /* Volumetric Objects */ + psl->volumetric_objects_ps = DRW_pass_create("Volumetric Properties", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); + + psl->volumetric_scatter_ps = DRW_pass_create("Volumetric Scattering", DRW_STATE_WRITE_COLOR); + grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_scatter_sh, psl->volumetric_scatter_ps, volumetrics->froxel_tex_size[2]); + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); + DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); + DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); + DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1); + DRW_shgroup_uniform_mat4(grp, "PastViewProjectionMatrix", (float *)stl->g_data->prev_persmat); + DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); + DRW_shgroup_uniform_int(grp, "light_count", (volumetrics->use_lights) ? &sldata->lamps->num_light : &zero, 1); + DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool); + DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_pool); + DRW_shgroup_uniform_float(grp, "volume_light_clamp", &volumetrics->light_clamp, 1); + DRW_shgroup_uniform_float(grp, "volume_shadows_steps", &volumetrics->shadow_step_count, 1); + DRW_shgroup_uniform_float(grp, "volume_history_alpha", &volumetrics->history_alpha, 1); + DRW_shgroup_uniform_buffer(grp, "volumeScattering", &txl->volume_prop_scattering); + DRW_shgroup_uniform_buffer(grp, "volumeExtinction", &txl->volume_prop_extinction); + DRW_shgroup_uniform_buffer(grp, "volumeEmission", &txl->volume_prop_emission); + DRW_shgroup_uniform_buffer(grp, "volumePhase", &txl->volume_prop_phase); + DRW_shgroup_uniform_buffer(grp, "historyScattering", &txl->volume_scatter_history); + DRW_shgroup_uniform_buffer(grp, "historyTransmittance", &txl->volume_transmittance_history); + + psl->volumetric_integration_ps = DRW_pass_create("Volumetric Integration", DRW_STATE_WRITE_COLOR); + grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_integration_sh, psl->volumetric_integration_ps, volumetrics->froxel_tex_size[2]); + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); + DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); + DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); + DRW_shgroup_uniform_buffer(grp, "volumeScattering", &txl->volume_scatter); + DRW_shgroup_uniform_buffer(grp, "volumeExtinction", &txl->volume_transmittance); + + psl->volumetric_resolve_ps = DRW_pass_create("Volumetric Resolve", DRW_STATE_WRITE_COLOR); + grp = DRW_shgroup_create(e_data.volumetric_resolve_sh, psl->volumetric_resolve_ps); + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); + DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); + DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); + DRW_shgroup_uniform_buffer(grp, "inScattering", &txl->volume_scatter); + DRW_shgroup_uniform_buffer(grp, "inTransmittance", &txl->volume_transmittance); + DRW_shgroup_uniform_buffer(grp, "inSceneColor", &e_data.color_src); + DRW_shgroup_uniform_buffer(grp, "inSceneDepth", &e_data.depth_src); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + } +} + +void EEVEE_volumes_cache_object_add(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, Scene *scene, Object *ob) +{ + float *texcoloc = NULL; + float *texcosize = NULL; + struct ModifierData *md = NULL; + EEVEE_VolumetricsInfo *volumetrics = sldata->volumetrics; + Material *ma = give_current_material(ob, 1); + + if (ma == NULL) { + return; + } + + struct GPUMaterial *mat = EEVEE_material_mesh_volume_get(scene, ma); + + DRWShadingGroup *grp = DRW_shgroup_material_empty_tri_batch_create(mat, vedata->psl->volumetric_objects_ps, volumetrics->froxel_tex_size[2]); + + /* Making sure it's updated. */ + invert_m4_m4(ob->imat, ob->obmat); + + BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, NULL, &texcosize); + + if (grp) { + DRW_shgroup_uniform_mat4(grp, "volumeObjectMatrix", (float *)ob->imat); + DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texcoloc, 1); + DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texcosize, 1); + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)vedata->stl->g_data->viewvecs, 2); + DRW_shgroup_uniform_ivec3(grp, "volumeTextureSize", (int *)volumetrics->froxel_tex_size, 1); + DRW_shgroup_uniform_vec2(grp, "volume_uv_ratio", (float *)volumetrics->volume_coord_scale, 1); + DRW_shgroup_uniform_vec3(grp, "volume_param", (float *)volumetrics->depth_param, 1); + DRW_shgroup_uniform_vec3(grp, "volume_jitter", (float *)volumetrics->jitter, 1); + } + + /* Smoke Simulation */ + if (((ob->base_flag & BASE_FROMDUPLI) == 0) && + (md = modifiers_findByType(ob, eModifierType_Smoke)) && + (modifier_isEnabled(scene, md, eModifierMode_Realtime))) + { + SmokeModifierData *smd = (SmokeModifierData *)md; + SmokeDomainSettings *sds = smd->domain; + /* Don't show smoke before simulation starts, this could be made an option in the future. */ + const bool show_smoke = (CFRA >= sds->point_cache[0]->startframe); + + if (sds->fluid && show_smoke) { + if (!sds->wt || !(sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) { + GPU_create_smoke(smd, 0); + } + else if (sds->wt && (sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) { + GPU_create_smoke(smd, 1); + } + BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(smd)); + } + + if (sds->tex != NULL) { + DRW_shgroup_uniform_buffer(grp, "sampdensity", &sds->tex); + } + if (sds->tex_flame != NULL) { + DRW_shgroup_uniform_buffer(grp, "sampflame", &sds->tex_flame); + } + } +} + +void EEVEE_volumes_compute(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) { + DRW_stats_group_start("Volumetrics"); + + /* Step 1: Participating Media Properties */ + DRW_framebuffer_bind(fbl->volumetric_fb); + DRW_draw_pass(psl->volumetric_world_ps); + DRW_draw_pass(psl->volumetric_objects_ps); + + /* Step 2: Scatter Light */ + DRW_framebuffer_bind(fbl->volumetric_scat_fb); + DRW_draw_pass(psl->volumetric_scatter_ps); + + /* Step 3: Integration */ + DRW_framebuffer_bind(fbl->volumetric_integ_fb); + DRW_draw_pass(psl->volumetric_integration_ps); + + /* Swap volume history buffers */ + SWAP(struct GPUFrameBuffer *, fbl->volumetric_scat_fb, fbl->volumetric_integ_fb); + SWAP(GPUTexture *, txl->volume_scatter, txl->volume_scatter_history); + SWAP(GPUTexture *, txl->volume_transmittance, txl->volume_transmittance_history); + + /* Restore */ + DRW_framebuffer_bind(fbl->main); + + DRW_stats_group_end(); + } +} + +void EEVEE_volumes_resolve(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + + if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) { + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + + e_data.color_src = txl->color; + e_data.depth_src = dtxl->depth; + + /* Step 4: Apply for opaque */ + DRW_framebuffer_bind(fbl->effect_fb); + DRW_draw_pass(psl->volumetric_resolve_ps); + + /* Swap the buffers and rebind depth to the current buffer */ + DRW_framebuffer_texture_detach(dtxl->depth); + SWAP(struct GPUFrameBuffer *, fbl->main, fbl->effect_fb); + SWAP(GPUTexture *, txl->color, txl->color_post); + DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0); + } +} + +void EEVEE_volumes_free_smoke_textures(void) +{ + /* Free Smoke Textures after rendering */ + for (LinkData *link = e_data.smoke_domains.first; link; link = link->next) { + SmokeModifierData *smd = (SmokeModifierData *)link->data; + GPU_free_smoke(smd); + } + BLI_freelistN(&e_data.smoke_domains); +} + +void EEVEE_volumes_free(void) +{ + MEM_SAFE_FREE(e_data.volumetric_common_lib); + MEM_SAFE_FREE(e_data.volumetric_common_lamps_lib); + + DRW_SHADER_FREE_SAFE(e_data.volumetric_clear_sh); + DRW_SHADER_FREE_SAFE(e_data.volumetric_scatter_sh); + DRW_SHADER_FREE_SAFE(e_data.volumetric_integration_sh); + DRW_SHADER_FREE_SAFE(e_data.volumetric_resolve_sh); +} |