diff options
author | Julian Eisel <julian@blender.org> | 2020-07-01 18:25:04 +0300 |
---|---|---|
committer | Julian Eisel <julian@blender.org> | 2020-07-01 18:25:04 +0300 |
commit | 889c4ca9c26d770af02cedef972d65eb173bdb5e (patch) | |
tree | 6f46156146db1b3f09d92c6eaa1f44ba8a584ed4 /source/blender/draw/engines/eevee | |
parent | 87df15190210eb84ef52e5dccc2932918f912da5 (diff) | |
parent | 0829cebeb024095c268f190c34daa8ae9a5a224c (diff) |
Merge branch 'asset-uuid--archived' into asset-engine--archivedasset-engine--archived
Diffstat (limited to 'source/blender/draw/engines/eevee')
24 files changed, 1493 insertions, 290 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index a19af77124f..a4aa0e10198 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -24,11 +24,153 @@ #include "DRW_render.h" +#include "BLI_ghash.h" #include "BLI_memblock.h" +#include "BKE_duplilist.h" + +#include "DEG_depsgraph_query.h" + +#include "GPU_vertex_buffer.h" + #include "eevee_lightcache.h" #include "eevee_private.h" +/* Motion Blur data. */ + +static void eevee_motion_blur_mesh_data_free(void *val) +{ + EEVEE_GeometryMotionData *geom_mb = (EEVEE_GeometryMotionData *)val; + switch (geom_mb->type) { + case EEVEE_HAIR_GEOM_MOTION_DATA: + for (int i = 0; i < ARRAY_SIZE(geom_mb->vbo); i++) { + GPU_VERTBUF_DISCARD_SAFE(geom_mb->hair_pos[i]); + DRW_TEXTURE_FREE_SAFE(geom_mb->hair_pos_tx[i]); + } + break; + + case EEVEE_MESH_GEOM_MOTION_DATA: + for (int i = 0; i < ARRAY_SIZE(geom_mb->vbo); i++) { + GPU_VERTBUF_DISCARD_SAFE(geom_mb->vbo[i]); + } + break; + } + MEM_freeN(val); +} + +static uint eevee_object_key_hash(const void *key) +{ + EEVEE_ObjectKey *ob_key = (EEVEE_ObjectKey *)key; + uint hash = BLI_ghashutil_ptrhash(ob_key->ob); + hash = BLI_ghashutil_combine_hash(hash, BLI_ghashutil_ptrhash(ob_key->parent)); + for (int i = 0; i < 16; i++) { + if (ob_key->id[i] != 0) { + hash = BLI_ghashutil_combine_hash(hash, BLI_ghashutil_inthash(ob_key->id[i])); + } + else { + break; + } + } + return hash; +} + +/* Return false if equal. */ +static bool eevee_object_key_cmp(const void *a, const void *b) +{ + EEVEE_ObjectKey *key_a = (EEVEE_ObjectKey *)a; + EEVEE_ObjectKey *key_b = (EEVEE_ObjectKey *)b; + + if (key_a->ob != key_b->ob) { + return true; + } + if (key_a->parent != key_b->parent) { + return true; + } + if (memcmp(key_a->id, key_b->id, sizeof(key_a->id)) != 0) { + return true; + } + return false; +} + +void EEVEE_motion_blur_data_init(EEVEE_MotionBlurData *mb) +{ + if (mb->object == NULL) { + mb->object = BLI_ghash_new(eevee_object_key_hash, eevee_object_key_cmp, "EEVEE Object Motion"); + } + if (mb->geom == NULL) { + mb->geom = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "EEVEE Mesh Motion"); + } +} + +void EEVEE_motion_blur_data_free(EEVEE_MotionBlurData *mb) +{ + if (mb->object) { + BLI_ghash_free(mb->object, MEM_freeN, MEM_freeN); + mb->object = NULL; + } + if (mb->geom) { + BLI_ghash_free(mb->geom, NULL, eevee_motion_blur_mesh_data_free); + mb->geom = NULL; + } +} + +EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb, + Object *ob, + bool hair) +{ + if (mb->object == NULL) { + return NULL; + } + + EEVEE_ObjectKey key, *key_p; + /* Small hack to avoid another comparisson. */ + key.ob = (Object *)((char *)ob + hair); + DupliObject *dup = DRW_object_get_dupli(ob); + if (dup) { + key.parent = DRW_object_get_dupli_parent(ob); + memcpy(key.id, dup->persistent_id, sizeof(key.id)); + } + else { + key.parent = key.ob; + memset(key.id, 0, sizeof(key.id)); + } + + EEVEE_ObjectMotionData *ob_step = BLI_ghash_lookup(mb->object, &key); + if (ob_step == NULL) { + key_p = MEM_mallocN(sizeof(*key_p), __func__); + memcpy(key_p, &key, sizeof(*key_p)); + + ob_step = MEM_callocN(sizeof(EEVEE_ObjectMotionData), __func__); + + BLI_ghash_insert(mb->object, key_p, ob_step); + } + return ob_step; +} + +EEVEE_GeometryMotionData *EEVEE_motion_blur_geometry_data_get(EEVEE_MotionBlurData *mb, + Object *ob, + bool hair) +{ + if (mb->geom == NULL) { + return NULL; + } + + /* Use original data as key to ensure matching accross update. */ + Object *ob_orig = DEG_get_original_object(ob); + + void *key = (char *)ob_orig->data + hair; + EEVEE_GeometryMotionData *geom_step = BLI_ghash_lookup(mb->geom, key); + if (geom_step == NULL) { + geom_step = MEM_callocN(sizeof(EEVEE_GeometryMotionData), __func__); + geom_step->type = (hair) ? EEVEE_HAIR_GEOM_MOTION_DATA : EEVEE_MESH_GEOM_MOTION_DATA; + BLI_ghash_insert(mb->geom, key, geom_step); + } + + return geom_step; +} + +/* View Layer data. */ + void EEVEE_view_layer_data_free(void *storage) { EEVEE_ViewLayerData *sldata = (EEVEE_ViewLayerData *)storage; @@ -105,6 +247,8 @@ static void eevee_object_data_init(DrawData *dd) { EEVEE_ObjectEngineData *eevee_data = (EEVEE_ObjectEngineData *)dd; eevee_data->shadow_caster_id = -1; + eevee_data->need_update = false; + eevee_data->geom_update = false; } EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob) diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index ab846fe0f11..8c48ae65d9b 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -153,7 +153,7 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, effects->enabled_effects = 0; effects->enabled_effects |= (G.debug_value == 9) ? EFFECT_VELOCITY_BUFFER : 0; - effects->enabled_effects |= EEVEE_motion_blur_init(sldata, vedata, camera); + 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, camera); effects->enabled_effects |= EEVEE_temporal_sampling_init(sldata, vedata); @@ -225,10 +225,13 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, */ if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) { effects->velocity_tx = DRW_texture_pool_query_2d( - size_fs[0], size_fs[1], GPU_RG16, &draw_engine_eevee_type); + size_fs[0], size_fs[1], GPU_RGBA16, &draw_engine_eevee_type); - /* TODO output objects velocity during the mainpass. */ - // GPU_framebuffer_texture_attach(fbl->main_fb, effects->velocity_tx, 1, 0); + GPU_framebuffer_ensure_config(&fbl->velocity_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(effects->velocity_tx), + }); GPU_framebuffer_ensure_config( &fbl->velocity_resolve_fb, @@ -328,14 +331,18 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) { + EEVEE_MotionBlurData *mb_data = &effects->motion_blur; + /* This pass compute camera motions to the non moving objects. */ DRW_PASS_CREATE(psl->velocity_resolve, DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_create(EEVEE_shaders_velocity_resolve_sh_get(), psl->velocity_resolve); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); - DRW_shgroup_uniform_mat4(grp, "currPersinv", effects->velocity_curr_persinv); - DRW_shgroup_uniform_mat4(grp, "pastPersmat", effects->velocity_past_persmat); + + DRW_shgroup_uniform_mat4(grp, "prevViewProjMatrix", mb_data->camera[MB_PREV].persmat); + DRW_shgroup_uniform_mat4(grp, "currViewProjMatrixInv", mb_data->camera[MB_CURR].persinv); + DRW_shgroup_uniform_mat4(grp, "nextViewProjMatrix", mb_data->camera[MB_NEXT].persmat); DRW_shgroup_call(grp, quad, NULL); } } @@ -501,17 +508,19 @@ static void EEVEE_velocity_resolve(EEVEE_Data *vedata) EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - struct DRWView *view = effects->taa_view; if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) { DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); e_data.depth_src = dtxl->depth; - DRW_view_persmat_get(view, effects->velocity_curr_persinv, true); GPU_framebuffer_bind(fbl->velocity_resolve_fb); DRW_draw_pass(psl->velocity_resolve); + + if (psl->velocity_object) { + GPU_framebuffer_bind(fbl->velocity_fb); + DRW_draw_pass(psl->velocity_object); + } } - DRW_view_persmat_get(view, effects->velocity_past_persmat, false); } void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) @@ -529,6 +538,7 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) effects->target_buffer = fbl->effect_color_fb; /* next target to render to */ /* Post process stack (order matters) */ + EEVEE_velocity_resolve(vedata); EEVEE_motion_blur_draw(vedata); EEVEE_depth_of_field_draw(vedata); @@ -537,7 +547,6 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) * Velocity resolve use a hack to exclude lookdev * spheres from creating shimmering re-projection vectors. */ EEVEE_lookdev_draw(vedata); - EEVEE_velocity_resolve(vedata); EEVEE_temporal_sampling_draw(vedata); EEVEE_bloom_draw(vedata); diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index b698574f9d7..bac96ab1079 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -166,7 +166,9 @@ static void eevee_cache_finish(void *vedata) EEVEE_materials_cache_finish(sldata, vedata); EEVEE_lights_cache_finish(sldata, vedata); EEVEE_lightprobes_cache_finish(sldata, vedata); + EEVEE_renderpasses_cache_finish(sldata, vedata); + EEVEE_subsurface_draw_init(sldata, vedata); EEVEE_effects_draw_init(sldata, vedata); EEVEE_volumes_draw_init(sldata, vedata); @@ -213,6 +215,10 @@ static void eevee_draw_scene(void *vedata) loop_len = MAX2(1, scene->eevee.taa_samples); } + if (stl->effects->bypass_drawing) { + loop_len = 0; + } + while (loop_len--) { float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; float clear_depth = 1.0f; @@ -351,11 +357,18 @@ static void eevee_draw_scene(void *vedata) EEVEE_renderpasses_draw(sldata, vedata); } + if (stl->effects->bypass_drawing) { + /* Restore the depth from sample 1. */ + GPU_framebuffer_blit(fbl->double_buffer_depth_fb, 0, dfbl->default_fb, 0, GPU_DEPTH_BIT); + } + EEVEE_renderpasses_draw_debug(vedata); EEVEE_volumes_free_smoke_textures(); stl->g_data->view_updated = false; + + DRW_view_set_active(NULL); } static void eevee_view_update(void *vedata) @@ -370,7 +383,7 @@ static void eevee_id_object_update(void *UNUSED(vedata), Object *object) { EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(object); if (ped != NULL && ped->dd.recalc != 0) { - ped->need_update = (ped->dd.recalc & (ID_RECALC_TRANSFORM)) != 0; + ped->need_update = (ped->dd.recalc & ID_RECALC_TRANSFORM) != 0; ped->dd.recalc = 0; } EEVEE_LightEngineData *led = EEVEE_light_data_get(object); @@ -381,6 +394,7 @@ static void eevee_id_object_update(void *UNUSED(vedata), Object *object) EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(object); if (oedata != NULL && oedata->dd.recalc != 0) { oedata->need_update = true; + oedata->geom_update = (oedata->dd.recalc & (ID_RECALC_GEOMETRY)) != 0; oedata->dd.recalc = 0; } } @@ -390,6 +404,11 @@ static void eevee_id_world_update(void *vedata, World *wo) EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; LightCache *lcache = stl->g_data->light_cache; + if (lcache == NULL || lcache == stl->lookdev_lightcache) { + /* Avoid Lookdev viewport clearing the update flag (see T67741). */ + return; + } + EEVEE_WorldEngineData *wedata = EEVEE_world_data_ensure(wo); if (wedata != NULL && wedata->dd.recalc != 0) { @@ -400,7 +419,7 @@ static void eevee_id_world_update(void *vedata, World *wo) } } -static void eevee_id_update(void *vedata, ID *id) +void eevee_id_update(void *vedata, ID *id) { /* Handle updates based on ID type. */ switch (GS(id->name)) { @@ -416,23 +435,129 @@ static void eevee_id_update(void *vedata, ID *id) } } +static void eevee_render_reset_passes(EEVEE_Data *vedata) +{ + /* Reset passlist. This is safe as they are stored into managed memory chunks. */ + memset(vedata->psl, 0, sizeof(*vedata->psl)); +} + static void eevee_render_to_image(void *vedata, RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect) { + EEVEE_Data *ved = (EEVEE_Data *)vedata; const DRWContextState *draw_ctx = DRW_context_state_get(); + Depsgraph *depsgraph = draw_ctx->depsgraph; + Scene *scene = DEG_get_evaluated_scene(depsgraph); + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + const bool do_motion_blur = (scene->eevee.flag & SCE_EEVEE_MOTION_BLUR_ENABLED) != 0; + const bool do_motion_blur_fx = do_motion_blur && (scene->eevee.motion_blur_max > 0); - if (!EEVEE_render_init(vedata, engine, draw_ctx->depsgraph)) { + if (!EEVEE_render_init(vedata, engine, depsgraph)) { return; } + EEVEE_PrivateData *g_data = ved->stl->g_data; + + int steps = max_ii(1, scene->eevee.motion_blur_steps); + int time_steps_tot = (do_motion_blur) ? steps : 1; + g_data->render_tot_samples = divide_ceil_u(scene->eevee.taa_render_samples, time_steps_tot); + /* Centered on frame for now. */ + float time = CFRA - scene->eevee.motion_blur_shutter / 2.0f; + float time_step = scene->eevee.motion_blur_shutter / time_steps_tot; + for (int i = 0; i < time_steps_tot && !RE_engine_test_break(engine); i++) { + float time_prev = time; + float time_curr = time + time_step * 0.5f; + float time_next = time + time_step; + time += time_step; + + /* Previous motion step. */ + if (do_motion_blur_fx) { + if (i > 0) { + /* The previous step of this iteration N is exactly the next step of iteration N - 1. + * So we just swap the resources to avoid too much re-evaluation. */ + EEVEE_motion_blur_swap_data(vedata); + } + else { + EEVEE_motion_blur_step_set(ved, MB_PREV); + RE_engine_frame_set(engine, floorf(time_prev), fractf(time_prev)); + + EEVEE_render_view_sync(vedata, engine, depsgraph); + EEVEE_render_cache_init(sldata, vedata); + + DRW_render_object_iter(vedata, engine, depsgraph, EEVEE_render_cache); + + EEVEE_motion_blur_cache_finish(vedata); + EEVEE_materials_cache_finish(sldata, vedata); + eevee_render_reset_passes(vedata); + } + } + + /* Next motion step. */ + if (do_motion_blur_fx) { + EEVEE_motion_blur_step_set(ved, MB_NEXT); + RE_engine_frame_set(engine, floorf(time_next), fractf(time_next)); - DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, EEVEE_render_cache); + EEVEE_render_view_sync(vedata, engine, depsgraph); + EEVEE_render_cache_init(sldata, vedata); - /* Actually do the rendering. */ - EEVEE_render_draw(vedata, engine, render_layer, rect); + DRW_render_object_iter(vedata, engine, depsgraph, EEVEE_render_cache); + + EEVEE_motion_blur_cache_finish(vedata); + EEVEE_materials_cache_finish(sldata, vedata); + eevee_render_reset_passes(vedata); + } + + /* Current motion step. */ + { + if (do_motion_blur) { + EEVEE_motion_blur_step_set(ved, MB_CURR); + RE_engine_frame_set(engine, floorf(time_curr), fractf(time_curr)); + } + + EEVEE_render_view_sync(vedata, engine, depsgraph); + EEVEE_render_cache_init(sldata, vedata); + + DRW_render_object_iter(vedata, engine, depsgraph, EEVEE_render_cache); + + EEVEE_motion_blur_cache_finish(vedata); + EEVEE_volumes_cache_finish(sldata, vedata); + EEVEE_materials_cache_finish(sldata, vedata); + EEVEE_lights_cache_finish(sldata, vedata); + EEVEE_lightprobes_cache_finish(sldata, vedata); + EEVEE_renderpasses_cache_finish(sldata, vedata); + + EEVEE_subsurface_draw_init(sldata, vedata); + EEVEE_effects_draw_init(sldata, vedata); + EEVEE_volumes_draw_init(sldata, vedata); + } + + /* Actual drawing. */ + { + EEVEE_renderpasses_output_init(sldata, vedata, g_data->render_tot_samples * time_steps_tot); + + EEVEE_temporal_sampling_create_view(vedata); + EEVEE_render_draw(vedata, engine, render_layer, rect); + + if (i < time_steps_tot - 1) { + /* Don't reset after the last loop. Since EEVEE_render_read_result + * might need some DRWPasses. */ + DRW_cache_restart(); + } + } + } EEVEE_volumes_free_smoke_textures(); + EEVEE_motion_blur_data_free(&ved->stl->effects->motion_blur); + + if (RE_engine_test_break(engine)) { + return; + } + + EEVEE_render_read_result(vedata, engine, render_layer, rect); + + /* Restore original viewport size. */ + DRW_render_viewport_size_set((int[2]){g_data->size_orig[0], g_data->size_orig[1]}); } static void eevee_engine_free(void) diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 4cdd166f09c..78d50a02fc7 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -849,6 +849,7 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb /* Disable volumetrics when baking. */ stl->effects->enabled_effects &= ~EFFECT_VOLUMETRIC; + EEVEE_subsurface_draw_init(sldata, vedata); EEVEE_effects_draw_init(sldata, vedata); EEVEE_volumes_draw_init(sldata, vedata); diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 83b2a9bb6d4..71c8294d123 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -957,8 +957,8 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us /* Slight modification: we handle refraction as normal * shading and don't do SSRefraction. */ - DRW_draw_pass(psl->depth_ps); - DRW_draw_pass(psl->depth_refract_ps); + DRW_draw_pass(psl->depth_clip_ps); + DRW_draw_pass(psl->depth_refract_clip_ps); DRW_draw_pass(psl->probe_background); EEVEE_create_minmax_buffer(vedata, tmp_planar_depth, layer); diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index cfc70baaf01..8537ad0e532 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -801,6 +801,8 @@ static void eevee_hair_cache_populate(EEVEE_Data *vedata, *matcache.shadow_grp_p = DRW_shgroup_hair_create_sub(ob, psys, md, matcache.shadow_grp); *cast_shadow = true; } + + EEVEE_motion_blur_hair_cache_populate(sldata, vedata, ob, psys, md); } #define ADD_SHGROUP_CALL(shgrp, ob, geom, oedata) \ @@ -851,8 +853,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, */ bool use_volume_material = (matcache[0].shading_gpumat && GPU_material_has_volume_output(matcache[0].shading_gpumat)); - - if ((ob->dt >= OB_SOLID) || DRW_state_is_image_render()) { + if ((ob->dt >= OB_SOLID) || DRW_state_is_scene_render()) { if (use_sculpt_pbvh) { struct DRWShadingGroup **shgrps_array = BLI_array_alloca(shgrps_array, materials_len); @@ -901,6 +902,9 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, } } } + + /* Motion Blur Vectors. */ + EEVEE_motion_blur_cache_populate(sldata, vedata, ob); } /* Volumetrics */ @@ -946,17 +950,15 @@ void EEVEE_object_hair_cache_populate(EEVEE_Data *vedata, eevee_hair_cache_populate(vedata, sldata, ob, NULL, NULL, HAIR_MATERIAL_NR, cast_shadow); } -void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_PrivateData *pd = vedata->stl->g_data; EEVEE_EffectsInfo *effects = vedata->stl->effects; BLI_ghash_free(pd->material_hash, NULL, NULL); + pd->material_hash = NULL; SET_FLAG_FROM_TEST(effects->enabled_effects, effects->sss_surface_count > 0, EFFECT_SSS); - - /* TODO(fclem) this is not really clean. Init should not be done in cache finish. */ - EEVEE_subsurface_draw_init(sldata, vedata); } void EEVEE_materials_free(void) @@ -1015,7 +1017,7 @@ void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, /* Should be enough precision for many samples. */ const eGPUTextureFormat texture_format = (tot_samples > 128) ? GPU_RGBA32F : GPU_RGBA16F; - const bool do_clear = DRW_state_is_image_render() || (effects->taa_current_sample == 1); + const bool do_clear = (effects->taa_current_sample == 1); /* Create FrameBuffer. */ GPU_framebuffer_ensure_config(&fbl->material_accum_fb, {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_LEAVE}); diff --git a/source/blender/draw/engines/eevee/eevee_mist.c b/source/blender/draw/engines/eevee/eevee_mist.c index 7b942784ee9..1cedd334d67 100644 --- a/source/blender/draw/engines/eevee/eevee_mist.c +++ b/source/blender/draw/engines/eevee/eevee_mist.c @@ -75,7 +75,7 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->mist_accum)}); /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + if (effects->taa_current_sample == 1) { GPU_framebuffer_bind(fbl->mist_accum_fb); GPU_framebuffer_clear_color(fbl->mist_accum_fb, clear); } diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c index a6e6b30a6b1..586ee780f1d 100644 --- a/source/blender/draw/engines/eevee/eevee_motion_blur.c +++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c @@ -24,12 +24,19 @@ #include "DRW_render.h" +#include "BLI_rand.h" +#include "BLI_string_utils.h" + #include "BKE_animsys.h" #include "BKE_camera.h" #include "BKE_object.h" +#include "BKE_screen.h" #include "DNA_anim_types.h" #include "DNA_camera_types.h" +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_particle_types.h" #include "DNA_screen_types.h" #include "ED_screen.h" @@ -37,172 +44,517 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" +#include "GPU_batch.h" #include "GPU_texture.h" #include "eevee_private.h" static struct { /* Motion Blur */ struct GPUShader *motion_blur_sh; + struct GPUShader *motion_blur_object_sh; + struct GPUShader *motion_blur_hair_sh; + struct GPUShader *velocity_tiles_sh; + struct GPUShader *velocity_tiles_expand_sh; } e_data = {NULL}; /* Engine data */ +extern char datatoc_effect_velocity_tile_frag_glsl[]; extern char datatoc_effect_motion_blur_frag_glsl[]; +extern char datatoc_object_motion_frag_glsl[]; +extern char datatoc_object_motion_vert_glsl[]; +extern char datatoc_common_hair_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; -static void eevee_motion_blur_camera_get_matrix_at_time(Scene *scene, - ARegion *region, - RegionView3D *rv3d, - View3D *v3d, - Object *camera, - float time, - float r_mat[4][4]) -{ - float obmat[4][4]; +#define EEVEE_VELOCITY_TILE_SIZE 32 - /* HACK */ - Object cam_cpy = *camera; - Camera camdata_cpy = *(Camera *)(camera->data); - cam_cpy.data = &camdata_cpy; +static void eevee_create_shader_motion_blur(void) +{ + e_data.motion_blur_sh = DRW_shader_create_fullscreen( + datatoc_effect_motion_blur_frag_glsl, + "#define EEVEE_VELOCITY_TILE_SIZE " STRINGIFY(EEVEE_VELOCITY_TILE_SIZE) "\n"); + e_data.motion_blur_object_sh = DRW_shader_create_with_lib(datatoc_object_motion_vert_glsl, + NULL, + datatoc_object_motion_frag_glsl, + datatoc_common_view_lib_glsl, + NULL); + e_data.velocity_tiles_sh = DRW_shader_create_fullscreen( + datatoc_effect_velocity_tile_frag_glsl, + "#define TILE_GATHER\n" + "#define EEVEE_VELOCITY_TILE_SIZE " STRINGIFY(EEVEE_VELOCITY_TILE_SIZE) "\n"); + e_data.velocity_tiles_expand_sh = DRW_shader_create_fullscreen( + datatoc_effect_velocity_tile_frag_glsl, + "#define TILE_EXPANSION\n" + "#define EEVEE_VELOCITY_TILE_SIZE " STRINGIFY(EEVEE_VELOCITY_TILE_SIZE) "\n"); + + char *vert = BLI_string_joinN(datatoc_common_hair_lib_glsl, datatoc_object_motion_vert_glsl); + e_data.motion_blur_hair_sh = DRW_shader_create_with_lib( + vert, NULL, datatoc_object_motion_frag_glsl, datatoc_common_view_lib_glsl, "#define HAIR\n"); + MEM_freeN(vert); +} - /* Reset original pointers, so direct evaluation does not attempt to flush - * animation back to the original object: otherwise viewport with motion - * blur enabled will always loose non-keyed changes. */ - cam_cpy.id.orig_id = NULL; - camdata_cpy.id.orig_id = NULL; +int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_EffectsInfo *effects = stl->effects; const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; - /* Past matrix */ - /* FIXME : This is a temporal solution that does not take care of parent animations */ - /* Recalc Anim manually */ - BKE_animsys_evaluate_animdata(&camdata_cpy.id, camdata_cpy.adt, time, ADT_RECALC_ALL, false); - BKE_object_where_is_calc_time(draw_ctx->depsgraph, scene, &cam_cpy, time); + /* Viewport not supported for now. */ + if (!DRW_state_is_scene_render()) { + return 0; + } + + effects->motion_blur_max = max_ii(0, scene->eevee.motion_blur_max); + + if ((effects->motion_blur_max > 0) && (scene->eevee.flag & SCE_EEVEE_MOTION_BLUR_ENABLED)) { + if (!e_data.motion_blur_sh) { + eevee_create_shader_motion_blur(); + } - /* Compute winmat */ - CameraParams params; - BKE_camera_params_init(¶ms); + if (DRW_state_is_scene_render()) { + int mb_step = effects->motion_blur_step; + DRW_view_viewmat_get(NULL, effects->motion_blur.camera[mb_step].viewmat, false); + DRW_view_persmat_get(NULL, effects->motion_blur.camera[mb_step].persmat, false); + DRW_view_persmat_get(NULL, effects->motion_blur.camera[mb_step].persinv, true); + } - if (v3d != NULL) { - BKE_camera_params_from_view3d(¶ms, draw_ctx->depsgraph, v3d, rv3d); - BKE_camera_params_compute_viewplane(¶ms, region->winx, region->winy, 1.0f, 1.0f); + const float *fs_size = DRW_viewport_size_get(); + int tx_size[2] = {1 + ((int)fs_size[0] / EEVEE_VELOCITY_TILE_SIZE), + 1 + ((int)fs_size[1] / EEVEE_VELOCITY_TILE_SIZE)}; + + effects->velocity_tiles_x_tx = DRW_texture_pool_query_2d( + tx_size[0], fs_size[1], GPU_RGBA16, &draw_engine_eevee_type); + GPU_framebuffer_ensure_config(&fbl->velocity_tiles_fb[0], + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->velocity_tiles_x_tx), + }); + + effects->velocity_tiles_tx = DRW_texture_pool_query_2d( + tx_size[0], tx_size[1], GPU_RGBA16, &draw_engine_eevee_type); + GPU_framebuffer_ensure_config(&fbl->velocity_tiles_fb[1], + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->velocity_tiles_tx), + }); + + return EFFECT_MOTION_BLUR | EFFECT_POST_BUFFER | EFFECT_VELOCITY_BUFFER; } - else { - BKE_camera_params_from_object(¶ms, &cam_cpy); - BKE_camera_params_compute_viewplane( - ¶ms, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp); + return 0; +} + +void EEVEE_motion_blur_step_set(EEVEE_Data *vedata, int step) +{ + BLI_assert(step < 3); + vedata->stl->effects->motion_blur_step = step; +} + +static void eevee_motion_blur_sync_camera(EEVEE_Data *vedata) +{ + EEVEE_EffectsInfo *effects = vedata->stl->effects; + if (DRW_state_is_scene_render()) { + int mb_step = effects->motion_blur_step; + DRW_view_viewmat_get(NULL, effects->motion_blur.camera[mb_step].viewmat, false); + DRW_view_persmat_get(NULL, effects->motion_blur.camera[mb_step].persmat, false); + DRW_view_persmat_get(NULL, effects->motion_blur.camera[mb_step].persinv, true); } - BKE_camera_params_compute_matrix(¶ms); + effects->motion_blur_near_far[0] = fabsf(DRW_view_near_distance_get(NULL)); + effects->motion_blur_near_far[1] = fabsf(DRW_view_far_distance_get(NULL)); +} + +void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + EEVEE_MotionBlurData *mb_data = &effects->motion_blur; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + + if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) { + const float *fs_size = DRW_viewport_size_get(); + int tx_size[2] = {GPU_texture_width(effects->velocity_tiles_tx), + GPU_texture_height(effects->velocity_tiles_tx)}; + + eevee_motion_blur_sync_camera(vedata); + + DRWShadingGroup *grp; + { + DRW_PASS_CREATE(psl->velocity_tiles_x, DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->velocity_tiles, DRW_STATE_WRITE_COLOR); + + /* Create max velocity tiles in 2 passes. One for X and one for Y */ + GPUShader *sh = e_data.velocity_tiles_sh; + grp = DRW_shgroup_create(sh, psl->velocity_tiles_x); + DRW_shgroup_uniform_texture(grp, "velocityBuffer", effects->velocity_tx); + DRW_shgroup_uniform_ivec2_copy(grp, "velocityBufferSize", (int[2]){fs_size[0], fs_size[1]}); + DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); + DRW_shgroup_uniform_vec2(grp, "viewportSizeInv", DRW_viewport_invert_size_get(), 1); + DRW_shgroup_uniform_ivec2_copy(grp, "gatherStep", (int[2]){1, 0}); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + grp = DRW_shgroup_create(sh, psl->velocity_tiles); + DRW_shgroup_uniform_texture(grp, "velocityBuffer", effects->velocity_tiles_x_tx); + DRW_shgroup_uniform_ivec2_copy(grp, "velocityBufferSize", (int[2]){tx_size[0], fs_size[1]}); + DRW_shgroup_uniform_ivec2_copy(grp, "gatherStep", (int[2]){0, 1}); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + /* Expand max tiles by keeping the max tile in each tile neighborhood. */ + DRW_PASS_CREATE(psl->velocity_tiles_expand[0], DRW_STATE_WRITE_COLOR); + DRW_PASS_CREATE(psl->velocity_tiles_expand[1], DRW_STATE_WRITE_COLOR); + for (int i = 0; i < 2; i++) { + GPUTexture *tile_tx = (i == 0) ? effects->velocity_tiles_tx : effects->velocity_tiles_x_tx; + GPUShader *sh_expand = e_data.velocity_tiles_expand_sh; + grp = DRW_shgroup_create(sh_expand, psl->velocity_tiles_expand[i]); + DRW_shgroup_uniform_ivec2_copy(grp, "velocityBufferSize", tx_size); + DRW_shgroup_uniform_texture(grp, "velocityBuffer", tile_tx); + DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); + DRW_shgroup_uniform_vec2(grp, "viewportSizeInv", DRW_viewport_invert_size_get(), 1); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + } + { + DRW_PASS_CREATE(psl->motion_blur, DRW_STATE_WRITE_COLOR); + eGPUSamplerState state = 0; + int expand_steps = 1 + (max_ii(0, effects->motion_blur_max - 1) / EEVEE_VELOCITY_TILE_SIZE); + GPUTexture *tile_tx = (expand_steps & 1) ? effects->velocity_tiles_x_tx : + effects->velocity_tiles_tx; + + grp = DRW_shgroup_create(e_data.motion_blur_sh, psl->motion_blur); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_texture_ref_ex(grp, "colorBuffer", &effects->source_buffer, state); + DRW_shgroup_uniform_texture_ref_ex(grp, "depthBuffer", &dtxl->depth, state); + DRW_shgroup_uniform_texture_ref_ex(grp, "velocityBuffer", &effects->velocity_tx, state); + DRW_shgroup_uniform_texture(grp, "tileMaxBuffer", tile_tx); + DRW_shgroup_uniform_float_copy(grp, "depthScale", scene->eevee.motion_blur_depth_scale); + DRW_shgroup_uniform_vec2(grp, "nearFar", effects->motion_blur_near_far, 1); + DRW_shgroup_uniform_bool_copy(grp, "isPerspective", DRW_view_is_persp_get(NULL)); + DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); + DRW_shgroup_uniform_vec2(grp, "viewportSizeInv", DRW_viewport_invert_size_get(), 1); + DRW_shgroup_uniform_ivec2_copy(grp, "tileBufferSize", tx_size); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + { + DRW_PASS_CREATE(psl->velocity_object, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); + + grp = DRW_shgroup_create(e_data.motion_blur_object_sh, psl->velocity_object); + DRW_shgroup_uniform_mat4(grp, "prevViewProjMatrix", mb_data->camera[MB_PREV].persmat); + DRW_shgroup_uniform_mat4(grp, "currViewProjMatrix", mb_data->camera[MB_CURR].persmat); + DRW_shgroup_uniform_mat4(grp, "nextViewProjMatrix", mb_data->camera[MB_NEXT].persmat); + + DRW_PASS_CREATE(psl->velocity_hair, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); + + mb_data->hair_grp = grp = DRW_shgroup_create(e_data.motion_blur_hair_sh, psl->velocity_hair); + DRW_shgroup_uniform_mat4(grp, "prevViewProjMatrix", mb_data->camera[MB_PREV].persmat); + DRW_shgroup_uniform_mat4(grp, "currViewProjMatrix", mb_data->camera[MB_CURR].persmat); + DRW_shgroup_uniform_mat4(grp, "nextViewProjMatrix", mb_data->camera[MB_NEXT].persmat); + + DRW_pass_link(psl->velocity_object, psl->velocity_hair); + } - /* 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); + EEVEE_motion_blur_data_init(mb_data); + } + else { + psl->motion_blur = NULL; + psl->velocity_object = NULL; + psl->velocity_hair = NULL; + } } -static void eevee_create_shader_motion_blur(void) +void EEVEE_motion_blur_hair_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata), + EEVEE_Data *vedata, + Object *ob, + ParticleSystem *psys, + ModifierData *md) { - e_data.motion_blur_sh = DRW_shader_create_fullscreen(datatoc_effect_motion_blur_frag_glsl, NULL); + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + DRWShadingGroup *grp = NULL; + + if (!DRW_state_is_scene_render() || psl->velocity_hair == NULL) { + return; + } + + /* For now we assume hair objects are always moving. */ + EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get( + &effects->motion_blur, ob, true); + + if (mb_data) { + int mb_step = effects->motion_blur_step; + /* Store transform */ + DRW_hair_duplimat_get(ob, psys, md, mb_data->obmat[mb_step]); + + EEVEE_GeometryMotionData *mb_geom = EEVEE_motion_blur_geometry_data_get( + &effects->motion_blur, ob, true); + + if (mb_step == MB_CURR) { + /* Fill missing matrices if the object was hidden in previous or next frame. */ + if (is_zero_m4(mb_data->obmat[MB_PREV])) { + copy_m4_m4(mb_data->obmat[MB_PREV], mb_data->obmat[MB_CURR]); + } + if (is_zero_m4(mb_data->obmat[MB_NEXT])) { + copy_m4_m4(mb_data->obmat[MB_NEXT], mb_data->obmat[MB_CURR]); + } + + grp = DRW_shgroup_hair_create_sub(ob, psys, md, effects->motion_blur.hair_grp); + DRW_shgroup_uniform_mat4(grp, "prevModelMatrix", mb_data->obmat[MB_PREV]); + DRW_shgroup_uniform_mat4(grp, "currModelMatrix", mb_data->obmat[MB_CURR]); + DRW_shgroup_uniform_mat4(grp, "nextModelMatrix", mb_data->obmat[MB_NEXT]); + DRW_shgroup_uniform_texture(grp, "prvBuffer", mb_geom->hair_pos_tx[MB_PREV]); + DRW_shgroup_uniform_texture(grp, "nxtBuffer", mb_geom->hair_pos_tx[MB_NEXT]); + DRW_shgroup_uniform_bool(grp, "useDeform", &mb_geom->use_deform, 1); + } + else { + /* Store vertex position buffer. */ + mb_geom->hair_pos[mb_step] = DRW_hair_pos_buffer_get(ob, psys, md); + mb_geom->use_deform = true; + } + } } -int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, Object *camera) +void EEVEE_motion_blur_cache_populate(EEVEE_ViewLayerData *UNUSED(sldata), + EEVEE_Data *vedata, + Object *ob) { + EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; + DRWShadingGroup *grp = NULL; - const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); - Scene *scene = draw_ctx->scene; + if (!DRW_state_is_scene_render() || psl->velocity_object == NULL) { + return; + } - View3D *v3d = draw_ctx->v3d; - RegionView3D *rv3d = draw_ctx->rv3d; - ARegion *region = draw_ctx->region; + const bool is_dupli = (ob->base_flag & BASE_FROM_DUPLI) != 0; + /* For now we assume dupli objects are moving. */ + const bool object_moves = is_dupli || BKE_object_moves_in_time(ob, true); + const bool is_deform = BKE_object_is_deform_modified(DRW_context_state_get()->scene, ob); - if (scene_eval->eevee.flag & SCE_EEVEE_MOTION_BLUR_ENABLED) { - /* Update Motion Blur Matrices */ - if (camera && (camera->type == OB_CAMERA) && (camera->data != NULL)) { - float persmat[4][4]; - float ctime = DEG_get_ctime(draw_ctx->depsgraph); - float delta = scene_eval->eevee.motion_blur_shutter; - Object *ob_camera_eval = DEG_get_evaluated_object(draw_ctx->depsgraph, camera); + if (!(object_moves || is_deform)) { + return; + } - /* Viewport Matrix */ - /* Note: This does not have TAA jitter applied. */ - DRW_view_persmat_get(NULL, persmat, false); + EEVEE_ObjectMotionData *mb_data = EEVEE_motion_blur_object_data_get( + &effects->motion_blur, ob, false); - bool view_is_valid = (stl->g_data->view_updated == false); + if (mb_data) { + int mb_step = effects->motion_blur_step; + /* Store transform */ + copy_m4_m4(mb_data->obmat[mb_step], ob->obmat); + + EEVEE_GeometryMotionData *mb_geom = EEVEE_motion_blur_geometry_data_get( + &effects->motion_blur, ob, false); + + if (mb_step == MB_CURR) { + GPUBatch *batch = DRW_cache_object_surface_get(ob); + if (batch == NULL) { + return; + } - if (draw_ctx->evil_C != NULL) { - struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); - view_is_valid = view_is_valid && (ED_screen_animation_no_scrub(wm) == NULL); + /* Fill missing matrices if the object was hidden in previous or next frame. */ + if (is_zero_m4(mb_data->obmat[MB_PREV])) { + copy_m4_m4(mb_data->obmat[MB_PREV], mb_data->obmat[MB_CURR]); + } + if (is_zero_m4(mb_data->obmat[MB_NEXT])) { + copy_m4_m4(mb_data->obmat[MB_NEXT], mb_data->obmat[MB_CURR]); } - /* The view is jittered by the oglrenderer. So avoid testing in this case. */ - if (!DRW_state_is_image_render()) { - view_is_valid = view_is_valid && compare_m4m4(persmat, effects->prev_drw_persmat, FLT_MIN); - /* WATCH: assume TAA init code runs last. */ - if (scene_eval->eevee.taa_samples == 1) { - /* Only if TAA is disabled. If not, TAA will update prev_drw_persmat itself. */ - copy_m4_m4(effects->prev_drw_persmat, persmat); + grp = DRW_shgroup_create(e_data.motion_blur_object_sh, psl->velocity_object); + DRW_shgroup_uniform_mat4(grp, "prevModelMatrix", mb_data->obmat[MB_PREV]); + DRW_shgroup_uniform_mat4(grp, "currModelMatrix", mb_data->obmat[MB_CURR]); + DRW_shgroup_uniform_mat4(grp, "nextModelMatrix", mb_data->obmat[MB_NEXT]); + DRW_shgroup_uniform_bool(grp, "useDeform", &mb_geom->use_deform, 1); + + DRW_shgroup_call(grp, batch, ob); + + if (mb_geom->use_deform) { + EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob); + if (!oedata->geom_update) { + /* FIXME(fclem) There can be false positive where the actual mesh is not updated. + * This avoids a crash but removes the motion blur from some object. + * Maybe an issue with depsgraph tagging. */ + mb_geom->use_deform = false; + oedata->geom_update = false; + + GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_PREV]); + GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_NEXT]); } + /* Keep to modify later (after init). */ + mb_geom->batch = batch; } + } + else if (is_deform) { + /* Store vertex position buffer. */ + mb_geom->vbo[mb_step] = DRW_cache_object_pos_vertbuf_get(ob); + mb_geom->use_deform = (mb_geom->vbo[mb_step] != NULL); + } + else { + mb_geom->vbo[mb_step] = NULL; + mb_geom->use_deform = false; + } + } +} + +void EEVEE_motion_blur_cache_finish(EEVEE_Data *vedata) +{ + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; + GHashIterator ghi; - effects->motion_blur_mat_cached = view_is_valid && !DRW_state_is_image_render(); + if ((effects->enabled_effects & EFFECT_MOTION_BLUR) == 0) { + return; + } - /* Current matrix */ - if (effects->motion_blur_mat_cached == false) { - eevee_motion_blur_camera_get_matrix_at_time( - scene, region, rv3d, v3d, ob_camera_eval, ctime, effects->current_world_to_ndc); - } + int mb_step = effects->motion_blur_step; + + if (mb_step != MB_CURR) { + /* Push instances attributes to the GPU. */ + DRW_render_instance_buffer_finish(); + + /* Need to be called after DRW_render_instance_buffer_finish() */ + /* Also we weed to have a correct fbo bound for DRW_hair_update */ + GPU_framebuffer_bind(vedata->fbl->main_fb); + DRW_hair_update(); - /* Only continue if camera is not being keyed */ - if (DRW_state_is_image_render() || - compare_m4m4(persmat, effects->current_world_to_ndc, 0.0001f)) { - /* Past matrix */ - if (effects->motion_blur_mat_cached == false) { - eevee_motion_blur_camera_get_matrix_at_time( - scene, region, rv3d, v3d, ob_camera_eval, 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, region, rv3d, v3d, ob_camera_eval, ctime + delta, effects->future_world_to_ndc); -#endif - invert_m4_m4(effects->current_ndc_to_world, effects->current_world_to_ndc); + DRW_cache_restart(); + } + + for (BLI_ghashIterator_init(&ghi, effects->motion_blur.geom); + BLI_ghashIterator_done(&ghi) == false; + BLI_ghashIterator_step(&ghi)) { + EEVEE_GeometryMotionData *mb_geom = BLI_ghashIterator_getValue(&ghi); + + if (!mb_geom->use_deform) { + continue; + } + + switch (mb_geom->type) { + case EEVEE_HAIR_GEOM_MOTION_DATA: + if (mb_step == MB_CURR) { + /* TODO(fclem) Check if vertex count mismatch. */ + mb_geom->use_deform = true; } + else { + mb_geom->hair_pos[mb_step] = GPU_vertbuf_duplicate(mb_geom->hair_pos[mb_step]); - effects->motion_blur_mat_cached = true; - effects->motion_blur_samples = scene_eval->eevee.motion_blur_samples; + /* Create vbo immediately to bind to texture buffer. */ + GPU_vertbuf_use(mb_geom->hair_pos[mb_step]); - if (!e_data.motion_blur_sh) { - eevee_create_shader_motion_blur(); + mb_geom->hair_pos_tx[mb_step] = GPU_texture_create_from_vertbuf( + mb_geom->hair_pos[mb_step]); + } + break; + + case EEVEE_MESH_GEOM_MOTION_DATA: + if (mb_step == MB_CURR) { + /* Modify batch to have data from adjacent frames. */ + GPUBatch *batch = mb_geom->batch; + for (int i = 0; i < MB_CURR; i++) { + GPUVertBuf *vbo = mb_geom->vbo[i]; + if (vbo && batch) { + if (vbo->vertex_len != batch->verts[0]->vertex_len) { + /* Vertex count mismatch, disable deform motion blur. */ + mb_geom->use_deform = false; + } + + if (mb_geom->use_deform == false) { + GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_PREV]); + GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_NEXT]); + break; + } + else { + /* Modify the batch to include the previous & next position. */ + if (i == MB_PREV) { + GPU_batch_vertbuf_add_ex(batch, vbo, true); + mb_geom->vbo[i] = NULL; + } + else { + /* This VBO can be reuse by next time step. Don't pass ownership. */ + GPU_batch_vertbuf_add_ex(batch, vbo, false); + } + } + } + } + } + else { + GPUVertBuf *vbo = mb_geom->vbo[mb_step]; + /* If this assert fails, it means that different EEVEE_GeometryMotionDatas + * has been used for each motion blur step. */ + BLI_assert(vbo); + if (vbo) { + /* Use the vbo to perform the copy on the GPU. */ + GPU_vertbuf_use(vbo); + /* Perform a copy to avoid loosing it after RE_engine_frame_set(). */ + mb_geom->vbo[mb_step] = vbo = GPU_vertbuf_duplicate(vbo); + /* Find and replace "pos" attrib name. */ + int attrib_id = GPU_vertformat_attr_id_get(&vbo->format, "pos"); + GPU_vertformat_attr_rename( + &vbo->format, attrib_id, (mb_step == MB_PREV) ? "prv" : "nxt"); + } } + break; - return EFFECT_MOTION_BLUR | EFFECT_POST_BUFFER; - } + default: + BLI_assert(0); + break; } } - - return 0; } -void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +void EEVEE_motion_blur_swap_data(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 GPUBatch *quad = DRW_cache_fullscreen_quad_get(); + GHashIterator ghi; - if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) { - DRW_PASS_CREATE(psl->motion_blur, DRW_STATE_WRITE_COLOR); + BLI_assert((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0); - 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", effects->current_ndc_to_world); - DRW_shgroup_uniform_mat4(grp, "pastViewProjMatrix", effects->past_world_to_ndc); - DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_call(grp, quad, NULL); + /* Camera Data. */ + effects->motion_blur.camera[MB_PREV] = effects->motion_blur.camera[MB_CURR]; + + /* Object Data. */ + for (BLI_ghashIterator_init(&ghi, effects->motion_blur.object); + BLI_ghashIterator_done(&ghi) == false; + BLI_ghashIterator_step(&ghi)) { + EEVEE_ObjectMotionData *mb_data = BLI_ghashIterator_getValue(&ghi); + + copy_m4_m4(mb_data->obmat[MB_PREV], mb_data->obmat[MB_NEXT]); + } + + /* Deformation Data. */ + for (BLI_ghashIterator_init(&ghi, effects->motion_blur.geom); + BLI_ghashIterator_done(&ghi) == false; + BLI_ghashIterator_step(&ghi)) { + EEVEE_GeometryMotionData *mb_geom = BLI_ghashIterator_getValue(&ghi); + + switch (mb_geom->type) { + case EEVEE_HAIR_GEOM_MOTION_DATA: + GPU_VERTBUF_DISCARD_SAFE(mb_geom->hair_pos[MB_PREV]); + DRW_TEXTURE_FREE_SAFE(mb_geom->hair_pos_tx[MB_PREV]); + mb_geom->hair_pos[MB_PREV] = mb_geom->hair_pos[MB_NEXT]; + mb_geom->hair_pos_tx[MB_PREV] = mb_geom->hair_pos_tx[MB_NEXT]; + break; + + case EEVEE_MESH_GEOM_MOTION_DATA: + GPU_VERTBUF_DISCARD_SAFE(mb_geom->vbo[MB_PREV]); + mb_geom->vbo[MB_PREV] = mb_geom->vbo[MB_NEXT]; + + if (mb_geom->vbo[MB_NEXT]) { + GPUVertBuf *vbo = mb_geom->vbo[MB_NEXT]; + int attrib_id = GPU_vertformat_attr_id_get(&vbo->format, "nxt"); + GPU_vertformat_attr_rename(&vbo->format, attrib_id, "prv"); + } + break; + + default: + BLI_assert(0); + break; + } } } @@ -216,6 +568,30 @@ void EEVEE_motion_blur_draw(EEVEE_Data *vedata) /* Motion Blur */ if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) { + /* Create velocity max tiles in 2 passes. One for each dimension. */ + GPU_framebuffer_bind(fbl->velocity_tiles_fb[0]); + DRW_draw_pass(psl->velocity_tiles_x); + + GPU_framebuffer_bind(fbl->velocity_tiles_fb[1]); + DRW_draw_pass(psl->velocity_tiles); + + /* Expand the tiles by reading the neighborhood. Do as many passes as required. */ + int buf = 0; + for (int i = effects->motion_blur_max; i > 0; i -= EEVEE_VELOCITY_TILE_SIZE) { + GPU_framebuffer_bind(fbl->velocity_tiles_fb[buf]); + + /* Change viewport to avoid invoking more pixel shaders than necessary since in one of the + * buffer the texture is way bigger in height. This avoid creating another texture and + * reduce VRAM usage. */ + int w = GPU_texture_width(effects->velocity_tiles_tx); + int h = GPU_texture_height(effects->velocity_tiles_tx); + GPU_framebuffer_viewport_set(fbl->velocity_tiles_fb[buf], 0, 0, w, h); + + DRW_draw_pass(psl->velocity_tiles_expand[buf]); + + buf = buf ? 0 : 1; + } + GPU_framebuffer_bind(effects->target_buffer); DRW_draw_pass(psl->motion_blur); SWAP_BUFFERS(); @@ -225,4 +601,8 @@ void EEVEE_motion_blur_draw(EEVEE_Data *vedata) void EEVEE_motion_blur_free(void) { DRW_SHADER_FREE_SAFE(e_data.motion_blur_sh); + DRW_SHADER_FREE_SAFE(e_data.motion_blur_object_sh); + DRW_SHADER_FREE_SAFE(e_data.motion_blur_hair_sh); + DRW_SHADER_FREE_SAFE(e_data.velocity_tiles_sh); + DRW_SHADER_FREE_SAFE(e_data.velocity_tiles_expand_sh); } diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c index f5ebbe08dd1..a075210967c 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -155,7 +155,7 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->ao_accum)}); /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + if (effects->taa_current_sample == 1) { GPU_framebuffer_bind(fbl->ao_accum_fb); GPU_framebuffer_clear_color(fbl->ao_accum_fb, clear); } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 40008c5c364..5005c5a8ba9 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -29,6 +29,8 @@ #include "DNA_lightprobe_types.h" +#include "BKE_camera.h" + struct EEVEE_ShadowCasterBuffer; struct GPUFrameBuffer; struct Object; @@ -256,7 +258,12 @@ typedef struct EEVEE_PassList { struct DRWPass *sss_translucency_ps; struct DRWPass *color_downsample_ps; struct DRWPass *color_downsample_cube_ps; + struct DRWPass *velocity_object; + struct DRWPass *velocity_hair; struct DRWPass *velocity_resolve; + struct DRWPass *velocity_tiles_x; + struct DRWPass *velocity_tiles; + struct DRWPass *velocity_tiles_expand[2]; struct DRWPass *taa_resolve; struct DRWPass *alpha_checker; @@ -327,6 +334,8 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *renderpass_fb; struct GPUFrameBuffer *ao_accum_fb; struct GPUFrameBuffer *velocity_resolve_fb; + struct GPUFrameBuffer *velocity_fb; + struct GPUFrameBuffer *velocity_tiles_fb[2]; struct GPUFrameBuffer *update_noise_fb; @@ -556,6 +565,58 @@ enum { PROBE_UPDATE_ALL = 0xFFFFFF, }; +/* ************** MOTION BLUR ************ */ + +#define MB_PREV 0 +#define MB_NEXT 1 +#define MB_CURR 2 + +typedef struct EEVEE_MotionBlurData { + struct GHash *object; + struct GHash *geom; + struct { + float viewmat[4][4]; + float persmat[4][4]; + float persinv[4][4]; + } camera[3]; + DRWShadingGroup *hair_grp; +} EEVEE_MotionBlurData; + +typedef struct EEVEE_ObjectKey { + /** Object or source object for duplis */ + struct Object *ob; + /** Parent object for duplis */ + struct Object *parent; + /** Dupli objects recursive unique identifier */ + int id[16]; /* 2*MAX_DUPLI_RECUR */ +} EEVEE_ObjectKey; + +typedef struct EEVEE_ObjectMotionData { + float obmat[3][4][4]; +} EEVEE_ObjectMotionData; + +typedef enum eEEVEEMotionData { + EEVEE_MESH_GEOM_MOTION_DATA = 0, + EEVEE_HAIR_GEOM_MOTION_DATA, +} eEEVEEMotionData; + +typedef struct EEVEE_GeometryMotionData { + eEEVEEMotionData type; + int use_deform; /* To disable deform mb if vertcount mismatch. */ + union { + struct { + /* Mesh */ + struct GPUBatch *batch; /* Batch for time = t. */ + struct GPUVertBuf *vbo[2]; /* Vbo for time = t +/- step. */ + }; + struct { + /* Hair */ + struct GPUVertBuf *hair_pos[2]; /* Position buffer for time = t +/- step. */ + struct GPUTexture *hair_pos_tx[2]; /* Buffer Texture of the corresponding VBO. */ + }; + }; +} EEVEE_GeometryMotionData; + /* ************ EFFECTS DATA ************* */ typedef enum EEVEE_EffectsFlag { @@ -607,9 +668,10 @@ typedef struct EEVEE_EffectsInfo { int taa_render_sample; int taa_total_sample; float taa_alpha; + bool bypass_drawing; bool prev_drw_support; bool prev_is_navigating; - float prev_drw_persmat[4][4]; + float prev_drw_persmat[4][4]; /* Used for checking view validity and reprojection. */ struct DRWView *taa_view; /* Ambient Occlusion */ int ao_depth_layer; @@ -617,15 +679,24 @@ typedef struct EEVEE_EffectsInfo { struct GPUTexture *gtao_horizons; /* Textures from pool */ struct GPUTexture *gtao_horizons_debug; /* Motion Blur */ - float current_world_to_ndc[4][4]; float current_ndc_to_world[4][4]; + float current_world_to_ndc[4][4]; + float current_world_to_view[4][4]; float past_world_to_ndc[4][4]; - int motion_blur_samples; - bool motion_blur_mat_cached; + float past_world_to_view[4][4]; + CameraParams past_cam_params; + CameraParams current_cam_params; + char motion_blur_step; /* Which step we are evaluating. */ + int motion_blur_max; /* Maximum distance in pixels a motion blured pixel can cover. */ + float motion_blur_near_far[2]; /* Camera near/far clip distances (positive). */ + bool cam_params_init; + /* TODO(fclem) Only used in render mode for now. + * This is because we are missing a per scene persistent place to hold this. */ + struct EEVEE_MotionBlurData motion_blur; /* Velocity Pass */ - float velocity_curr_persinv[4][4]; - float velocity_past_persmat[4][4]; struct GPUTexture *velocity_tx; /* Texture from pool */ + struct GPUTexture *velocity_tiles_x_tx; + struct GPUTexture *velocity_tiles_tx; /* Depth Of Field */ float dof_near_far[2]; float dof_params[2]; @@ -805,6 +876,7 @@ typedef struct EEVEE_ObjectEngineData { bool ob_vis, ob_vis_dirty; bool need_update; + bool geom_update; uint shadow_caster_id; } EEVEE_ObjectEngineData; @@ -880,15 +952,25 @@ typedef struct EEVEE_PrivateData { struct DRWView *world_views[6]; /** For rendering planar reflections. */ struct DRWView *planar_views[MAX_PLANAR]; + + int render_tot_samples; } EEVEE_PrivateData; /* Transient data */ /* eevee_data.c */ +void EEVEE_motion_blur_data_init(EEVEE_MotionBlurData *mb); +void EEVEE_motion_blur_data_free(EEVEE_MotionBlurData *mb); void EEVEE_view_layer_data_free(void *sldata); EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void); EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure_ex(struct ViewLayer *view_layer); EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void); EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob); EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob); +EEVEE_ObjectMotionData *EEVEE_motion_blur_object_data_get(EEVEE_MotionBlurData *mb, + Object *ob, + bool hair); +EEVEE_GeometryMotionData *EEVEE_motion_blur_geometry_data_get(EEVEE_MotionBlurData *mb, + Object *ob, + bool hair); EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob); EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_ensure(Object *ob); EEVEE_LightEngineData *EEVEE_light_data_get(Object *ob); @@ -896,6 +978,8 @@ EEVEE_LightEngineData *EEVEE_light_data_ensure(Object *ob); EEVEE_WorldEngineData *EEVEE_world_data_get(World *wo); EEVEE_WorldEngineData *EEVEE_world_data_ensure(World *wo); +void eevee_id_update(void *vedata, ID *id); + /* eevee_materials.c */ struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, @@ -1112,8 +1196,17 @@ void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data void EEVEE_subsurface_free(void); /* eevee_motion_blur.c */ -int EEVEE_motion_blur_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera); +int EEVEE_motion_blur_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_motion_blur_step_set(EEVEE_Data *vedata, int step); void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_motion_blur_cache_populate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *ob); +void EEVEE_motion_blur_hair_cache_populate(EEVEE_ViewLayerData *sldata, + EEVEE_Data *vedata, + Object *ob, + struct ParticleSystem *psys, + struct ModifierData *md); +void EEVEE_motion_blur_swap_data(EEVEE_Data *vedata); +void EEVEE_motion_blur_cache_finish(EEVEE_Data *vedata); void EEVEE_motion_blur_draw(EEVEE_Data *vedata); void EEVEE_motion_blur_free(void); @@ -1127,6 +1220,7 @@ void EEVEE_renderpasses_init(EEVEE_Data *vedata); void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples); +void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, bool post_effect); @@ -1140,6 +1234,7 @@ bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata); /* eevee_temporal_sampling.c */ void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata); +void EEVEE_temporal_sampling_create_view(EEVEE_Data *vedata); int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_temporal_sampling_offset_calc(const double ht_point[2], const float filter_size, @@ -1183,6 +1278,10 @@ void EEVEE_effects_free(void); bool EEVEE_render_init(EEVEE_Data *vedata, struct RenderEngine *engine, struct Depsgraph *depsgraph); +void EEVEE_render_view_sync(EEVEE_Data *vedata, + struct RenderEngine *engine, + struct Depsgraph *depsgraph); +void EEVEE_render_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_render_cache(void *vedata, struct Object *ob, struct RenderEngine *engine, @@ -1191,6 +1290,10 @@ void EEVEE_render_draw(EEVEE_Data *vedata, struct RenderEngine *engine, struct RenderLayer *render_layer, const struct rcti *rect); +void EEVEE_render_read_result(EEVEE_Data *vedata, + struct RenderEngine *engine, + struct RenderLayer *rl, + const rcti *rect); void EEVEE_render_update_passes(struct RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer); diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 89a5ad2198a..f903fa905e8 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -131,6 +131,29 @@ bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * &sldata->common_data); } + EEVEE_render_view_sync(vedata, engine, depsgraph); + + /* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */ + struct Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re)); + + DRWView *view = (DRWView *)DRW_view_default_get(); + DRW_view_camtexco_set(view, camtexcofac); + + /* `EEVEE_renderpasses_init` will set the active render passes used by `EEVEE_effects_init`. + * `EEVEE_effects_init` needs to go second for TAA. */ + EEVEE_renderpasses_init(vedata); + EEVEE_effects_init(sldata, vedata, ob_camera_eval, false); + EEVEE_materials_init(sldata, vedata, stl, fbl); + EEVEE_shadows_init(sldata); + EEVEE_lightprobes_init(sldata, vedata); + + return true; +} + +void EEVEE_render_view_sync(EEVEE_Data *vedata, RenderEngine *engine, struct Depsgraph *depsgraph) +{ + EEVEE_PrivateData *g_data = vedata->stl->g_data; + /* Set the pers & view matrix. */ float winmat[4][4], viewmat[4][4], viewinv[4][4]; /* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */ @@ -143,19 +166,13 @@ bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * invert_m4_m4(viewmat, viewinv); DRWView *view = DRW_view_create(viewmat, winmat, NULL, NULL, NULL); - DRW_view_camtexco_set(view, camtexcofac); + DRW_view_reset(); DRW_view_default_set(view); DRW_view_set_active(view); +} - /* `EEVEE_renderpasses_init` will set the active render passes used by `EEVEE_effects_init`. - * `EEVEE_effects_init` needs to go second for TAA. */ - EEVEE_renderpasses_init(vedata); - EEVEE_effects_init(sldata, vedata, ob_camera_eval, false); - EEVEE_materials_init(sldata, vedata, stl, fbl); - EEVEE_shadows_init(sldata); - EEVEE_lightprobes_init(sldata, vedata); - - /* INIT CACHE */ +void EEVEE_render_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ EEVEE_bloom_cache_init(sldata, vedata); EEVEE_depth_of_field_cache_init(sldata, vedata); EEVEE_effects_cache_init(sldata, vedata); @@ -168,8 +185,6 @@ bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * EEVEE_subsurface_cache_init(sldata, vedata); EEVEE_temporal_sampling_cache_init(sldata, vedata); EEVEE_volumes_cache_init(sldata, vedata); - - return true; } /* Used by light cache. in this case engine is NULL. */ @@ -182,6 +197,8 @@ void EEVEE_render_cache(void *vedata, EEVEE_LightProbesInfo *pinfo = sldata->probes; bool cast_shadow = false; + eevee_id_update(vedata, &ob->id); + if (pinfo->vis_data.collection) { /* Used for rendering probe with visibility groups. */ bool ob_vis = BKE_collection_has_object_recursive(pinfo->vis_data.collection, ob); @@ -478,27 +495,12 @@ static void eevee_render_draw_background(EEVEE_Data *vedata) void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl, const rcti *rect) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); const char *viewname = RE_GetActiveRenderView(engine->re); EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); - EEVEE_PrivateData *g_data = stl->g_data; - - /* FINISH CACHE */ - EEVEE_volumes_cache_finish(sldata, vedata); - EEVEE_materials_cache_finish(sldata, vedata); - EEVEE_lights_cache_finish(sldata, vedata); - EEVEE_lightprobes_cache_finish(sldata, vedata); - - EEVEE_effects_draw_init(sldata, vedata); - EEVEE_volumes_draw_init(sldata, vedata); - - /* Sort transparents before the loop. */ - DRW_pass_sort_shgroup_z(psl->transparent_pass); /* Push instances attributes to the GPU. */ DRW_render_instance_buffer_finish(); @@ -508,20 +510,17 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl GPU_framebuffer_bind(fbl->main_fb); DRW_hair_update(); - uint tot_sample = scene_eval->eevee.taa_render_samples; + /* Sort transparents before the loop. */ + DRW_pass_sort_shgroup_z(psl->transparent_pass); + + uint tot_sample = stl->g_data->render_tot_samples; uint render_samples = 0; /* SSR needs one iteration to start properly. */ - if (stl->effects->enabled_effects & EFFECT_SSR) { + if ((stl->effects->enabled_effects & EFFECT_SSR) && !stl->effects->ssr_was_valid_double_buffer) { tot_sample += 1; } - EEVEE_renderpasses_output_init(sldata, vedata, tot_sample); - - if (RE_engine_test_break(engine)) { - return; - } - while (render_samples < tot_sample && !RE_engine_test_break(engine)) { float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; float clear_depth = 1.0f; @@ -617,6 +616,15 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl RE_engine_update_progress(engine, (float)(render_samples++) / (float)tot_sample); } +} + +void EEVEE_render_read_result(EEVEE_Data *vedata, + RenderEngine *engine, + RenderLayer *rl, + const rcti *rect) +{ + const char *viewname = RE_GetActiveRenderView(engine->re); + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); eevee_render_result_combined(rl, viewname, rect, vedata, sldata); eevee_render_result_mist(rl, viewname, rect, vedata, sldata); @@ -631,9 +639,6 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl eevee_render_result_bloom(rl, viewname, rect, vedata, sldata); eevee_render_result_volume_scatter(rl, viewname, rect, vedata, sldata); eevee_render_result_volume_transmittance(rl, viewname, rect, vedata, sldata); - - /* Restore original viewport size. */ - DRW_render_viewport_size_set((int[2]){g_data->size_orig[0], g_data->size_orig[1]}); } void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer) diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c index 9a47ca19e7b..be771d7cf42 100644 --- a/source/blender/draw/engines/eevee/eevee_renderpasses.c +++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c @@ -136,24 +136,13 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, { EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; - EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; EEVEE_PrivateData *g_data = stl->g_data; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); const bool needs_post_processing = (g_data->render_passes & EEVEE_RENDERPASSES_WITH_POST_PROCESSING) > 0; if (needs_post_processing) { - if (e_data.postprocess_sh == NULL) { - char *frag_str = BLI_string_joinN(datatoc_common_view_lib_glsl, - datatoc_common_uniforms_lib_glsl, - datatoc_bsdf_common_lib_glsl, - datatoc_renderpass_postprocess_frag_glsl); - e_data.postprocess_sh = DRW_shader_create_fullscreen(frag_str, NULL); - MEM_freeN(frag_str); - } - /* Create FrameBuffer. */ /* Should be enough to store the data needs for a single pass. @@ -188,29 +177,51 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, EEVEE_volumes_output_init(sldata, vedata, tot_samples); } - /* Create Pass. */ - DRW_PASS_CREATE(psl->renderpass_pass, DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.postprocess_sh, psl->renderpass_pass); /* We set a default texture as not all post processes uses the inputBuffer. */ g_data->renderpass_input = txl->color; g_data->renderpass_col_input = txl->color; g_data->renderpass_light_input = txl->color; + } + else { + /* Free unneeded memory */ + DRW_TEXTURE_FREE_SAFE(txl->renderpass); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->renderpass_fb); + } +} + +void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_PrivateData *g_data = vedata->stl->g_data; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + + const bool needs_post_processing = (g_data->render_passes & + EEVEE_RENDERPASSES_WITH_POST_PROCESSING) > 0; + if (needs_post_processing) { + if (e_data.postprocess_sh == NULL) { + char *frag_str = BLI_string_joinN(datatoc_common_view_lib_glsl, + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_renderpass_postprocess_frag_glsl); + e_data.postprocess_sh = DRW_shader_create_fullscreen(frag_str, NULL); + MEM_freeN(frag_str); + } + + DRW_PASS_CREATE(psl->renderpass_pass, DRW_STATE_WRITE_COLOR); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.postprocess_sh, psl->renderpass_pass); DRW_shgroup_uniform_texture_ref(grp, "inputBuffer", &g_data->renderpass_input); DRW_shgroup_uniform_texture_ref(grp, "inputColorBuffer", &g_data->renderpass_col_input); DRW_shgroup_uniform_texture_ref( grp, "inputSecondLightBuffer", &g_data->renderpass_light_input); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); + DRW_shgroup_uniform_block_ref(grp, "common_block", &sldata->common_ubo); + DRW_shgroup_uniform_block_ref(grp, "renderpass_block", &sldata->renderpass_ubo.combined); DRW_shgroup_uniform_int(grp, "currentSample", &g_data->renderpass_current_sample, 1); DRW_shgroup_uniform_int(grp, "renderpassType", &g_data->renderpass_type, 1); DRW_shgroup_uniform_int(grp, "postProcessType", &g_data->renderpass_postprocess, 1); DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } else { - /* Free unneeded memory */ - DRW_TEXTURE_FREE_SAFE(txl->renderpass); - GPU_FRAMEBUFFER_FREE_SAFE(fbl->renderpass_fb); psl->renderpass_pass = NULL; } } diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index cece67334c5..32d758dba4b 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -358,7 +358,7 @@ void EEVEE_reflection_output_init(EEVEE_ViewLayerData *UNUSED(sldata), {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->ssr_accum)}); /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + if (effects->taa_current_sample == 1) { GPU_framebuffer_bind(fbl->ssr_accum_fb); GPU_framebuffer_clear_color(fbl->ssr_accum_fb, clear); } diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c index 84c50a22ae6..d0e430e115f 100644 --- a/source/blender/draw/engines/eevee/eevee_shadows.c +++ b/source/blender/draw/engines/eevee/eevee_shadows.c @@ -412,7 +412,7 @@ void EEVEE_shadow_output_init(EEVEE_ViewLayerData *sldata, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->shadow_accum)}); /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + if (effects->taa_current_sample == 1) { GPU_framebuffer_bind(fbl->shadow_accum_fb); GPU_framebuffer_clear_color(fbl->shadow_accum_fb, clear); } diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index 7674148f76a..ef4588f4aca 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -75,18 +75,8 @@ static void eevee_create_shader_subsurface(void) MEM_freeN(frag_str); } -void EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +void EEVEE_subsurface_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *UNUSED(vedata)) { - EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_EffectsInfo *effects = stl->effects; - - const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); - - effects->sss_sample_count = 1 + scene_eval->eevee.sss_samples * 2; - effects->sss_surface_count = 0; - common_data->sss_jitter_threshold = scene_eval->eevee.sss_jitter_threshold; } void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) @@ -197,22 +187,31 @@ void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *UNUSED(sldata), * already higher than one. This is noticeable when loading a file that has the diffuse light * pass in look dev mode active. `texture_created` will make sure that newly created textures * are cleared. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1 || texture_created) { + if (effects->taa_current_sample == 1 || texture_created) { float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; GPU_framebuffer_bind(fbl->sss_accum_fb); GPU_framebuffer_clear_color(fbl->sss_accum_fb, clear); } } -void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; + EEVEE_EffectsInfo *effects = vedata->stl->effects; EEVEE_PassList *psl = vedata->psl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); + /* Shaders */ if (!e_data.sss_sh[0]) { eevee_create_shader_subsurface(); } + effects->sss_sample_count = 1 + scene_eval->eevee.sss_samples * 2; + effects->sss_surface_count = 0; + common_data->sss_jitter_threshold = scene_eval->eevee.sss_jitter_threshold; + /** Screen Space SubSurface Scattering overview * TODO */ diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c index d57048f2c4e..714481c39f1 100644 --- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c +++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c @@ -186,6 +186,18 @@ void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata) vedata->stl->effects->taa_current_sample = 1; } +void EEVEE_temporal_sampling_create_view(EEVEE_Data *vedata) +{ + EEVEE_EffectsInfo *effects = vedata->stl->effects; + /* Create a sub view to disable clipping planes (if any). */ + const DRWView *default_view = DRW_view_default_get(); + float viewmat[4][4], winmat[4][4]; + DRW_view_viewmat_get(default_view, viewmat, false); + DRW_view_winmat_get(default_view, winmat, false); + effects->taa_view = DRW_view_create_sub(default_view, viewmat, winmat); + DRW_view_clip_planes_set(effects->taa_view, NULL, 0); +} + int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_StorageList *stl = vedata->stl; @@ -201,15 +213,9 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data * we accumulate the redraw inside the drawing loop in eevee_draw_scene(). **/ effects->taa_render_sample = 1; - effects->taa_view = NULL; + effects->bypass_drawing = false; - /* Create a sub view to disable clipping planes (if any). */ - const DRWView *default_view = DRW_view_default_get(); - float viewmat[4][4], winmat[4][4]; - DRW_view_viewmat_get(default_view, viewmat, false); - DRW_view_winmat_get(default_view, winmat, false); - effects->taa_view = DRW_view_create_sub(default_view, viewmat, winmat); - DRW_view_clip_planes_set(effects->taa_view, NULL, 0); + EEVEE_temporal_sampling_create_view(vedata); const DRWContextState *draw_ctx = DRW_context_state_get(); const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); @@ -241,7 +247,6 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data DRW_view_persmat_get(NULL, persmat, false); 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()) && @@ -251,7 +256,7 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data if (((effects->taa_total_sample == 0) || (effects->taa_current_sample < effects->taa_total_sample)) || - DRW_state_is_image_render()) { + (!view_is_valid) || DRW_state_is_image_render()) { if (view_is_valid) { /* Viewport rendering updates the matrices in `eevee_draw_scene` */ if (!DRW_state_is_image_render()) { @@ -264,7 +269,7 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data } } else { - effects->taa_current_sample = 1; + effects->bypass_drawing = true; } return repro_flag | EFFECT_TAA | EFFECT_DOUBLE_BUFFER | EFFECT_DEPTH_DOUBLE_BUFFER | @@ -283,7 +288,7 @@ void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; - if ((effects->enabled_effects & (EFFECT_TAA | EFFECT_TAA_REPROJECT)) != 0) { + if (effects->enabled_effects & EFFECT_TAA) { struct GPUShader *sh = EEVEE_shaders_taa_resolve_sh_get(effects->enabled_effects); DRW_PASS_CREATE(psl->taa_resolve, DRW_STATE_WRITE_COLOR); @@ -295,8 +300,9 @@ void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); if (effects->enabled_effects & EFFECT_TAA_REPROJECT) { - // DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - DRW_shgroup_uniform_texture_ref(grp, "velocityBuffer", &effects->velocity_tx); + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_mat4(grp, "prevViewProjectionMatrix", effects->prev_drw_persmat); } else { DRW_shgroup_uniform_float(grp, "alpha", &effects->taa_alpha, 1); @@ -359,10 +365,13 @@ void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata) effects->taa_current_sample += 1; } else { - if ((effects->taa_total_sample == 0) || - (effects->taa_current_sample < effects->taa_total_sample)) { + if (!DRW_state_is_playback() && + ((effects->taa_total_sample == 0) || + (effects->taa_current_sample < effects->taa_total_sample))) { DRW_viewport_request_redraw(); } } + + DRW_view_persmat_get(NULL, effects->prev_drw_persmat, false); } } diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 90860e94270..17f53113939 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -894,7 +894,7 @@ void EEVEE_volumes_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, GPU_ATTACHMENT_TEXTURE(txl->volume_transmittance_accum)}); /* Clear texture. */ - if (DRW_state_is_image_render() || effects->taa_current_sample == 1) { + if (effects->taa_current_sample == 1) { GPU_framebuffer_bind(fbl->volumetric_accum_fb); GPU_framebuffer_clear_color(fbl->volumetric_accum_fb, clear); } diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index 402d306df45..393ecaf1fc5 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -877,6 +877,14 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac) { Closure cl; cl.holdout = mix(cl1.holdout, cl2.holdout, fac); + + if (FLAG_TEST(cl1.flag, CLOSURE_HOLDOUT_FLAG)) { + fac = 1.0; + } + else if (FLAG_TEST(cl2.flag, CLOSURE_HOLDOUT_FLAG)) { + fac = 0.0; + } + cl.transmittance = mix(cl1.transmittance, cl2.transmittance, fac); cl.radiance = mix(cl1.radiance, cl2.radiance, fac); cl.flag = cl1.flag | cl2.flag; @@ -958,7 +966,7 @@ void main() { Closure cl = nodetree_exec(); - float holdout = 1.0 - saturate(cl.holdout); + float holdout = saturate(1.0 - cl.holdout); float transmit = saturate(avg(cl.transmittance)); float alpha = 1.0 - transmit; @@ -972,8 +980,9 @@ void main() * Since we do that using the blending pipeline we need to account for material transmittance. */ vol_scatter -= vol_scatter * cl.transmittance; - outRadiance = vec4(cl.radiance * vol_transmit + vol_scatter, alpha * holdout); - outTransmittance = vec4(cl.transmittance, transmit * holdout); + cl.radiance = cl.radiance * holdout * vol_transmit + vol_scatter; + outRadiance = vec4(cl.radiance, alpha * holdout); + outTransmittance = vec4(cl.transmittance, transmit) * holdout; # else outRadiance = vec4(cl.radiance, holdout); ssrNormals = cl.ssr_normal; diff --git a/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl index b7935235d06..fbf507a2e40 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_motion_blur_frag.glsl @@ -1,64 +1,235 @@ +/* + * Based on: + * A Fast and Stable Feature-Aware Motion Blur Filter + * by Jean-Philippe Guertin, Morgan McGuire, Derek Nowrouzezahrai + * + * With modification from the presentation: + * Next Generation Post Processing in Call of Duty Advanced Warfare + * by Jorge Jimenez + */ uniform sampler2D colorBuffer; uniform sampler2D depthBuffer; +uniform sampler2D velocityBuffer; +uniform sampler2D tileMaxBuffer; -/* current frame */ -uniform mat4 currInvViewProjMatrix; +#define KERNEL 8 -/* past frame frame */ -uniform mat4 pastViewProjMatrix; +/* TODO(fclem) deduplicate this code. */ +uniform sampler2DArray utilTex; +#define LUT_SIZE 64 +#define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) + +uniform float depthScale; +uniform ivec2 tileBufferSize; +uniform vec2 viewportSize; +uniform vec2 viewportSizeInv; +uniform bool isPerspective; +uniform vec2 nearFar; /* Near & far view depths values */ + +#define linear_depth(z) \ + ((isPerspective) ? (nearFar.x * nearFar.y) / (z * (nearFar.x - nearFar.y) + nearFar.y) : \ + z * (nearFar.y - nearFar.x) + nearFar.x) /* Only true for camera view! */ in vec4 uvcoordsvar; -out vec4 FragColor; +out vec4 fragColor; -#define MAX_SAMPLE 64 +#define saturate(a) clamp(a, 0.0, 1.0) -uniform int samples; +vec2 spread_compare(float center_motion_length, float sample_motion_length, float offset_length) +{ + return saturate(vec2(center_motion_length, sample_motion_length) - offset_length + 1.0); +} -float wang_hash_noise(uint s) +vec2 depth_compare(float center_depth, float sample_depth) { - uint seed = (uint(gl_FragCoord.x) * 1664525u + uint(gl_FragCoord.y)) + s; + return saturate(0.5 + vec2(depthScale, -depthScale) * (sample_depth - center_depth)); +} - seed = (seed ^ 61u) ^ (seed >> 16u); - seed *= 9u; - seed = seed ^ (seed >> 4u); - seed *= 0x27d4eb2du; - seed = seed ^ (seed >> 15u); +/* Kill contribution if not going the same direction. */ +float dir_compare(vec2 offset, vec2 sample_motion, float sample_motion_length) +{ + if (sample_motion_length < 0.5) { + return 1.0; + } + return (dot(offset, sample_motion) > 0.0) ? 1.0 : 0.0; +} - float value = float(seed); - value *= 1.0 / 4294967296.0; - return fract(value); +/* Return background (x) and foreground (y) weights. */ +vec2 sample_weights(float center_depth, + float sample_depth, + float center_motion_length, + float sample_motion_length, + float offset_length) +{ + /* Clasify foreground/background. */ + vec2 depth_weight = depth_compare(center_depth, sample_depth); + /* Weight if sample is overlapping or under the center pixel. */ + vec2 spread_weight = spread_compare(center_motion_length, sample_motion_length, offset_length); + return depth_weight * spread_weight; } -void main() +vec4 decode_velocity(vec4 velocity) { - vec3 ndc_pos; - ndc_pos.xy = uvcoordsvar.xy; - ndc_pos.z = texture(depthBuffer, uvcoordsvar.xy).x; + velocity = velocity * 2.0 - 1.0; + /* Needed to match cycles. Can't find why... (fclem) */ + velocity *= 0.5; + /* Transpose to pixelspace. */ + velocity *= viewportSize.xyxy; + return velocity; +} - float inv_samples = 1.0 / float(samples); - float noise = 2.0 * wang_hash_noise(0u) * inv_samples; +vec4 sample_velocity(vec2 uv) +{ + vec4 data = texture(velocityBuffer, uv); + return decode_velocity(data); +} - /* Normalize Device Coordinates are [-1, +1]. */ - ndc_pos = ndc_pos * 2.0 - 1.0; +vec2 sample_velocity(vec2 uv, const bool next) +{ + vec4 data = sample_velocity(uv); + data.xy = (next ? data.zw : data.xy); + return data.xy; +} - vec4 p = currInvViewProjMatrix * vec4(ndc_pos, 1.0); - vec3 world_pos = p.xyz / p.w; /* Perspective divide */ +void gather_sample(vec2 screen_uv, + float center_depth, + float center_motion_len, + vec2 offset, + float offset_len, + const bool next, + inout vec4 accum, + inout vec4 accum_bg, + inout vec3 w_accum) +{ + vec2 sample_uv = screen_uv - offset * viewportSizeInv; + vec2 sample_motion = sample_velocity(sample_uv, next); + float sample_motion_len = length(sample_motion); + float sample_depth = linear_depth(texture(depthBuffer, sample_uv).r); + vec4 col = textureLod(colorBuffer, sample_uv, 0.0); + + vec3 weights; + weights.xy = sample_weights( + center_depth, sample_depth, center_motion_len, sample_motion_len, offset_len); + weights.z = dir_compare(offset, sample_motion, sample_motion_len); + weights.xy *= weights.z; + + accum += col * weights.y; + accum_bg += col * weights.x; + w_accum += weights; +} - /* Now find where was this pixel position - * inside the past camera viewport */ - vec4 old_ndc = pastViewProjMatrix * vec4(world_pos, 1.0); - old_ndc.xyz /= old_ndc.w; /* Perspective divide */ +void gather_blur(vec2 screen_uv, + vec2 center_motion, + float center_depth, + vec2 max_motion, + float ofs, + const bool next, + inout vec4 accum, + inout vec4 accum_bg, + inout vec3 w_accum) +{ + float center_motion_len = length(center_motion); + float max_motion_len = length(max_motion); + + /* Tile boundaries randomization can fetch a tile where there is less motion than this pixel. + * Fix this by overriding the max_motion. */ + if (max_motion_len < center_motion_len) { + max_motion_len = center_motion_len; + max_motion = center_motion; + } - vec2 motion = (ndc_pos.xy - old_ndc.xy) * 0.25; /* 0.25 fit cycles ref */ + if (max_motion_len < 0.5) { + return; + } - float inc = 2.0 * inv_samples; - float i = -1.0 + noise; + int i; + float t, inc = 1.0 / float(KERNEL); + for (i = 0, t = ofs * inc; i < KERNEL; i++, t += inc) { + gather_sample(screen_uv, + center_depth, + center_motion_len, + max_motion * t, + max_motion_len * t, + next, + accum, + accum_bg, + w_accum); + } - FragColor = vec4(0.0); - for (int j = 0; j < samples && j < MAX_SAMPLE; j++) { - FragColor += textureLod(colorBuffer, uvcoordsvar.xy + motion * i, 0.0) * inv_samples; - i += inc; + if (center_motion_len < 0.5) { + return; } + + for (i = 0, t = ofs * inc; i < KERNEL; i++, t += inc) { + /* Also sample in center motion direction. + * Allow to recover motion where there is conflicting + * motion between foreground and background. */ + gather_sample(screen_uv, + center_depth, + center_motion_len, + center_motion * t, + center_motion_len * t, + next, + accum, + accum_bg, + w_accum); + } +} + +void main() +{ + vec2 uv = uvcoordsvar.xy; + + /* Data of the center pixel of the gather (target). */ + float center_depth = linear_depth(texture(depthBuffer, uv).r); + vec4 center_motion = sample_velocity(uv); + vec4 center_color = textureLod(colorBuffer, uv, 0.0); + + vec2 rand = texelfetch_noise_tex(gl_FragCoord.xy).xy; + + /* Randomize tile boundary to avoid ugly discontinuities. Randomize 1/4th of the tile. + * Note this randomize only in one direction but in practice it's enough. */ + rand.x = rand.x * 2.0 - 1.0; + ivec2 tile = ivec2(gl_FragCoord.xy + rand.x * float(EEVEE_VELOCITY_TILE_SIZE) * 0.25) / + EEVEE_VELOCITY_TILE_SIZE; + tile = clamp(tile, ivec2(0), tileBufferSize - 1); + vec4 max_motion = decode_velocity(texelFetch(tileMaxBuffer, tile, 0)); + + /* First (center) sample: time = T */ + /* x: Background, y: Foreground, z: dir. */ + vec3 w_accum = vec3(0.0, 0.0, 1.0); + vec4 accum_bg = vec4(0.0); + vec4 accum = vec4(0.0); + /* First linear gather. time = [T - delta, T] */ + gather_blur( + uv, center_motion.xy, center_depth, max_motion.xy, rand.y, false, accum, accum_bg, w_accum); + /* Second linear gather. time = [T, T + delta] */ + gather_blur( + uv, center_motion.zw, center_depth, max_motion.zw, rand.y, true, accum, accum_bg, w_accum); + +#if 1 + /* Avoid division by 0.0. */ + float w = 1.0 / (50.0 * float(KERNEL) * 4.0); + accum_bg += center_color * w; + w_accum.x += w; + /* Note: In Jimenez's presentation, they used center sample. + * We use background color as it contains more informations for foreground + * elements that have not enough weights. + * Yield beter blur in complex motion. */ + center_color = accum_bg / w_accum.x; +#endif + /* Merge background. */ + accum += accum_bg; + w_accum.y += w_accum.x; + /* Balance accumulation for failled samples. + * We replace the missing foreground by the background. */ + float blend_fac = saturate(1.0 - w_accum.y / w_accum.z); + fragColor = (accum / w_accum.z) + center_color * blend_fac; + +#if 0 /* For debugging. */ + fragColor.rgb = fragColor.ggg; + fragColor.rg += max_motion.xy; +#endif } diff --git a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl index 428318e3c68..b44645174bd 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl @@ -1,6 +1,6 @@ uniform sampler2D colorHistoryBuffer; -uniform sampler2D velocityBuffer; +uniform mat4 prevViewProjectionMatrix; out vec4 FragColor; @@ -38,16 +38,19 @@ vec3 clip_to_aabb(vec3 color, vec3 minimum, vec3 maximum, vec3 average) */ void main() { + vec2 screen_res = vec2(textureSize(colorBuffer, 0).xy); + vec2 uv = gl_FragCoord.xy / screen_res; ivec2 texel = ivec2(gl_FragCoord.xy); - vec2 motion = texelFetch(velocityBuffer, texel, 0).rg; - - /* Decode from unsigned normalized 16bit texture. */ - motion = motion * 2.0 - 1.0; /* Compute pixel position in previous frame. */ - vec2 screen_res = vec2(textureSize(colorBuffer, 0).xy); - vec2 uv = gl_FragCoord.xy / screen_res; - vec2 uv_history = uv - motion; + float depth = textureLod(depthBuffer, uv, 0.0).r; + vec3 pos = get_world_space_from_depth(uv, depth); + vec2 uv_history = project_point(prevViewProjectionMatrix, pos).xy * 0.5 + 0.5; + + /* HACK: Reject lookdev spheres from TAA reprojection. */ + if (depth == 0.0) { + uv_history = uv; + } ivec2 texel_history = ivec2(uv_history * screen_res); vec4 color_history = textureLod(colorHistoryBuffer, uv_history, 0.0); diff --git a/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl index 7d701bce5cb..d927fd78d30 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl @@ -1,8 +1,9 @@ -uniform mat4 currPersinv; -uniform mat4 pastPersmat; +uniform mat4 prevViewProjMatrix; +uniform mat4 currViewProjMatrixInv; +uniform mat4 nextViewProjMatrix; -out vec2 outData; +out vec4 outData; void main() { @@ -12,13 +13,12 @@ void main() float depth = texelFetch(depthBuffer, texel, 0).r; - vec3 world_position = project_point(currPersinv, vec3(uv, depth) * 2.0 - 1.0); - vec2 uv_history = project_point(pastPersmat, world_position).xy * 0.5 + 0.5; + vec3 world_position = project_point(currViewProjMatrixInv, vec3(uv, depth) * 2.0 - 1.0); + vec2 uv_prev = project_point(prevViewProjMatrix, world_position).xy * 0.5 + 0.5; + vec2 uv_next = project_point(nextViewProjMatrix, world_position).xy * 0.5 + 0.5; - outData = uv - uv_history; - - /* HACK: Reject lookdev spheres from TAA reprojection. */ - outData = (depth > 0.0) ? outData : vec2(0.0); + outData.xy = uv_prev - uv; + outData.zw = uv_next - uv; /* Encode to unsigned normalized 16bit texture. */ outData = outData * 0.5 + 0.5; diff --git a/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl new file mode 100644 index 00000000000..0eb598521af --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl @@ -0,0 +1,151 @@ +/** + * Shaders that down-sample velocity buffer, + * + * Based on: + * A Fast and Stable Feature-Aware Motion Blur Filter + * by Jean-Philippe Guertin, Morgan McGuire, Derek Nowrouzezahrai + * + * Adapted from G3D Innovation Engine implementation. + */ + +uniform sampler2D velocityBuffer; +uniform vec2 viewportSize; +uniform vec2 viewportSizeInv; +uniform ivec2 velocityBufferSize; + +out vec4 tileMaxVelocity; + +vec4 sample_velocity(ivec2 texel) +{ + texel = clamp(texel, ivec2(0), velocityBufferSize - 1); + vec4 data = texelFetch(velocityBuffer, texel, 0); + /* Decode data. */ + return (data * 2.0 - 1.0) * viewportSize.xyxy; +} + +vec4 encode_velocity(vec4 velocity) +{ + return velocity * viewportSizeInv.xyxy * 0.5 + 0.5; +} + +#ifdef TILE_GATHER + +uniform ivec2 gatherStep; + +void main() +{ + vec4 max_motion = vec4(0.0); + float max_motion_len_sqr_prev = 0.0; + float max_motion_len_sqr_next = 0.0; + ivec2 texel = ivec2(gl_FragCoord.xy); + texel = texel * gatherStep.yx + texel * EEVEE_VELOCITY_TILE_SIZE * gatherStep; + + for (int i = 0; i < EEVEE_VELOCITY_TILE_SIZE; ++i) { + vec4 motion = sample_velocity(texel + i * gatherStep); + float motion_len_sqr_prev = dot(motion.xy, motion.xy); + float motion_len_sqr_next = dot(motion.zw, motion.zw); + + if (motion_len_sqr_prev > max_motion_len_sqr_prev) { + max_motion_len_sqr_prev = motion_len_sqr_prev; + max_motion.xy = motion.xy; + } + if (motion_len_sqr_next > max_motion_len_sqr_next) { + max_motion_len_sqr_next = motion_len_sqr_next; + max_motion.zw = motion.zw; + } + } + + tileMaxVelocity = encode_velocity(max_motion); +} + +#else /* TILE_EXPANSION */ + +bool neighbor_affect_this_tile(ivec2 offset, vec2 velocity) +{ + /* Manhattan distance to the tiles, which is used for + * differentiating corners versus middle blocks */ + float displacement = float(abs(offset.x) + abs(offset.y)); + /** + * Relative sign on each axis of the offset compared + * to the velocity for that tile. In order for a tile + * to affect the center tile, it must have a + * neighborhood velocity in which x and y both have + * identical or both have opposite signs relative to + * offset. If the offset coordinate is zero then + * velocity is irrelevant. + **/ + vec2 point = sign(offset * velocity); + + float dist = (point.x + point.y); + /** + * Here's an example of the logic for this code. + * In this diagram, the upper-left tile has offset = (-1, -1). + * V1 is velocity = (1, -2). point in this case = (-1, 1), and therefore dist = 0, + * so the upper-left tile does not affect the center. + * + * Now, look at another case. V2 = (-1, -2). point = (1, 1), so dist = 2 and the tile + * does affect the center. + * + * V2(-1,-2) V1(1, -2) + * \ / + * \ / + * \/___ ____ ____ + * (-1, -1)| | | | + * |____|____|____| + * | | | | + * |____|____|____| + * | | | | + * |____|____|____| + **/ + return (abs(dist) == displacement); +} + +/** + * Only gather neighborhood velocity into tiles that could be affected by it. + * In the general case, only six of the eight neighbors contribute: + * + * This tile can't possibly be affected by the center one + * | + * v + * ____ ____ ____ + * | | ///|/// | + * |____|////|//__| + * | |////|/ | + * |___/|////|____| + * | //|////| | <--- This tile can't possibly be affected by the center one + * |_///|///_|____| + **/ +void main() +{ + vec4 max_motion = vec4(0.0); + float max_motion_len_sqr_prev = -1.0; + float max_motion_len_sqr_next = -1.0; + + ivec2 tile = ivec2(gl_FragCoord.xy); + ivec2 offset = ivec2(0); + for (offset.y = -1; offset.y <= 1; ++offset.y) { + for (offset.x = -1; offset.x <= 1; ++offset.x) { + vec4 motion = sample_velocity(tile + offset); + float motion_len_sqr_prev = dot(motion.xy, motion.xy); + float motion_len_sqr_next = dot(motion.zw, motion.zw); + + if (motion_len_sqr_prev > max_motion_len_sqr_prev) { + if (neighbor_affect_this_tile(offset, motion.xy)) { + max_motion_len_sqr_prev = motion_len_sqr_prev; + max_motion.xy = motion.xy; + } + } + + if (motion_len_sqr_next > max_motion_len_sqr_next) { + if (neighbor_affect_this_tile(offset, motion.zw)) { + max_motion_len_sqr_next = motion_len_sqr_next; + max_motion.zw = motion.zw; + } + } + } + } + + tileMaxVelocity = encode_velocity(max_motion); +} + +#endif
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/object_motion_frag.glsl b/source/blender/draw/engines/eevee/shaders/object_motion_frag.glsl new file mode 100644 index 00000000000..66b098ef6c5 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/object_motion_frag.glsl @@ -0,0 +1,27 @@ + +uniform mat4 prevViewProjMatrix; +uniform mat4 currViewProjMatrix; +uniform mat4 nextViewProjMatrix; + +in vec3 prevWorldPos; +in vec3 currWorldPos; +in vec3 nextWorldPos; + +out vec4 outData; + +void main() +{ + vec4 prev_wpos = prevViewProjMatrix * vec4(prevWorldPos, 1.0); + vec4 curr_wpos = currViewProjMatrix * vec4(currWorldPos, 1.0); + vec4 next_wpos = nextViewProjMatrix * vec4(nextWorldPos, 1.0); + + vec2 prev_uv = (prev_wpos.xy / prev_wpos.w); + vec2 curr_uv = (curr_wpos.xy / curr_wpos.w); + vec2 next_uv = (next_wpos.xy / next_wpos.w); + + outData.xy = prev_uv - curr_uv; + outData.zw = next_uv - curr_uv; + + /* Encode to unsigned normalized 16bit texture. */ + outData = outData * 0.5 + 0.5; +} diff --git a/source/blender/draw/engines/eevee/shaders/object_motion_vert.glsl b/source/blender/draw/engines/eevee/shaders/object_motion_vert.glsl new file mode 100644 index 00000000000..95cd69ba310 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/object_motion_vert.glsl @@ -0,0 +1,54 @@ + +uniform mat4 currModelMatrix; +uniform mat4 prevModelMatrix; +uniform mat4 nextModelMatrix; +uniform bool useDeform; + +#ifdef HAIR +uniform samplerBuffer prvBuffer; /* RGBA32F */ +uniform samplerBuffer nxtBuffer; /* RGBA32F */ +#else +in vec3 pos; +in vec3 prv; /* Previous frame position. */ +in vec3 nxt; /* Next frame position. */ +#endif + +out vec3 currWorldPos; +out vec3 prevWorldPos; +out vec3 nextWorldPos; + +void main() +{ +#ifdef HAIR + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + float time, thick_time, thickness; + vec3 tan, binor; + vec3 wpos; + + hair_get_pos_tan_binor_time(is_persp, + ModelMatrixInverse, + ViewMatrixInverse[3].xyz, + ViewMatrixInverse[2].xyz, + wpos, + tan, + binor, + time, + thickness, + thick_time); + + int id = hair_get_base_id(); + vec3 pos = texelFetch(hairPointBuffer, id).point_position; + vec3 prv = texelFetch(prvBuffer, id).point_position; + vec3 nxt = texelFetch(nxtBuffer, id).point_position; +#endif + prevWorldPos = (prevModelMatrix * vec4(useDeform ? prv : pos, 1.0)).xyz; + currWorldPos = (currModelMatrix * vec4(pos, 1.0)).xyz; + nextWorldPos = (nextModelMatrix * vec4(useDeform ? nxt : pos, 1.0)).xyz; + /* Use jittered projmatrix to be able to match exact sample depth (depth equal test). + * Note that currModelMatrix needs to also be equal to ModelMatrix for the samples to match. */ +#ifndef HAIR + gl_Position = ViewProjectionMatrix * vec4(currWorldPos, 1.0); +#else + gl_Position = ViewProjectionMatrix * vec4(wpos, 1.0); +#endif +} |