Eevee: Simple Camera Motion Blur.

Disabled by default. Set ENABLE_EFFECT_MOTION_BLUR to 1 to enable.
No fancy motion blur. Use depth and camera matrix to get the motion vectors. Then blur in this direction.
Only available in camera view.
Only Camera animation is supported, does not take into account the parents motion
This commit is contained in:
Clément Foucault 2017-05-04 17:36:40 +02:00
parent a3d8ef059c
commit 5601a62179
7 changed files with 312 additions and 26 deletions

View File

@ -82,6 +82,7 @@ set(SRC
engines/eevee/eevee_engine.c
engines/eevee/eevee_lights.c
engines/eevee/eevee_probes.c
engines/eevee/eevee_effects.c
engines/external/external_engine.c
DRW_engine.h
@ -112,6 +113,7 @@ data_to_c_simple(engines/eevee/shaders/default_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/default_world_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lit_surface_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lit_surface_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/effect_motion_blur_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/probe_filter_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/probe_sh_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/probe_geom.glsl SRC)

View File

@ -0,0 +1,204 @@
/*
* Copyright 2016, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): Blender Institute
*
*/
/* Gather all screen space effects technique such as Bloom, Motion Blur, DoF, SSAO, SSR, ...
*/
/** \file eevee_effects.c
* \ingroup draw_engine
*/
#include "DRW_render.h"
#include "DNA_anim_types.h"
#include "DNA_view3d_types.h"
#include "BKE_object.h"
#include "BKE_animsys.h"
#include "eevee_private.h"
#include "GPU_texture.h"
typedef struct EEVEE_ProbeData {
short probe_id, shadow_id;
} EEVEE_ProbeData;
/* TODO Option */
#define PROBE_SIZE 512
static struct {
struct GPUShader *motion_blur_sh;
struct GPUShader *tonemap_sh;
} e_data = {NULL}; /* Engine data */
extern char datatoc_effect_motion_blur_frag_glsl[];
extern char datatoc_tonemap_frag_glsl[];
void EEVEE_effects_init(EEVEE_Data *vedata)
{
EEVEE_StorageList *stl = vedata->stl;
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_TextureList *txl = vedata->txl;
/* Ping Pong buffer */
DRWFboTexture tex = {&txl->color_post, DRW_BUF_RGBA_16, DRW_TEX_FILTER};
const float *viewport_size = DRW_viewport_size_get();
DRW_framebuffer_init(&fbl->effect_fb,
(int)viewport_size[0], (int)viewport_size[1],
&tex, 1);
if (!e_data.motion_blur_sh) {
e_data.motion_blur_sh = DRW_shader_create_fullscreen(datatoc_effect_motion_blur_frag_glsl, NULL);
}
if (!e_data.tonemap_sh) {
e_data.tonemap_sh = DRW_shader_create_fullscreen(datatoc_tonemap_frag_glsl, NULL);
}
if (!stl->effects) {
stl->effects = MEM_callocN(sizeof(EEVEE_EffectsInfo), "EEVEE_EffectsInfo");
}
{
/* Update Motion Blur Matrices */
EEVEE_EffectsInfo *effects = stl->effects;
#if ENABLE_EFFECT_MOTION_BLUR
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
View3D *v3d = draw_ctx->v3d;
RegionView3D *rv3d = draw_ctx->rv3d;
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
float ctime = BKE_scene_frame_get(scene);
float past_obmat[4][4], future_obmat[4][4], winmat[4][4];
DRW_viewport_matrix_get(winmat, DRW_MAT_WIN);
/* HACK */
Object cam_cpy;
memcpy(&cam_cpy, v3d->camera, sizeof(cam_cpy));
/* Past matrix */
/* FIXME : This is a temporal solution that does not take care of parent animations */
/* Recalc Anim manualy */
BKE_animsys_evaluate_animdata(scene, &cam_cpy.id, cam_cpy.adt, ctime - 1.0, ADT_RECALC_ANIM);
BKE_object_where_is_calc_time(scene, &cam_cpy, ctime - 1.0);
normalize_m4_m4(past_obmat, cam_cpy.obmat);
invert_m4(past_obmat);
mul_m4_m4m4(effects->past_world_to_ndc, winmat, past_obmat);
#if 0 /* for future high quality blur */
/* Future matrix */
/* Recalc Anim manualy */
BKE_animsys_evaluate_animdata(scene, &cam_cpy.id, cam_cpy.adt, ctime + 1.0, ADT_RECALC_ANIM);
BKE_object_where_is_calc_time(scene, &cam_cpy, ctime + 1.0);
normalize_m4_m4(past_obmat, cam_cpy.obmat);
invert_m4(past_obmat);
mul_m4_m4m4(effects->past_world_to_ndc, winmat, past_obmat);
#else
UNUSED_VARS(future_obmat);
#endif
/* Current matrix */
DRW_viewport_matrix_get(effects->current_ndc_to_world, DRW_MAT_PERSINV);
effects->blur_amount = 0.5f;
effects->final_color = txl->color_post;
effects->enabled_effects |= EFFECT_MOTION_BLUR;
}
else {
#endif /* ENABLE_EFFECT_MOTION_BLUR */
effects->blur_amount = 0.0f;
effects->final_color = txl->color;
effects->enabled_effects &= ~EFFECT_MOTION_BLUR;
#if ENABLE_EFFECT_MOTION_BLUR
}
#endif
}
}
void EEVEE_effects_cache_init(EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_TextureList *txl = vedata->txl;
EEVEE_EffectsInfo *effects = stl->effects;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
struct Batch *quad = DRW_cache_fullscreen_quad_get();
{
psl->motion_blur = DRW_pass_create("Motion Blur", DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(e_data.motion_blur_sh, psl->motion_blur);
DRW_shgroup_uniform_float(grp, "blurAmount", &effects->blur_amount, 1);
DRW_shgroup_uniform_mat4(grp, "currInvViewProjMatrix", (float *)effects->current_ndc_to_world);
DRW_shgroup_uniform_mat4(grp, "pastViewProjMatrix", (float *)effects->past_world_to_ndc);
DRW_shgroup_uniform_buffer(grp, "colorBuffer", &txl->color, 0);
DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth, 1);
DRW_shgroup_call_add(grp, quad, NULL);
}
{
/* Final pass : Map HDR color to LDR color.
* Write result to the default color buffer */
psl->tonemap = DRW_pass_create("Tone Mapping", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND);
DRWShadingGroup *grp = DRW_shgroup_create(e_data.tonemap_sh, psl->tonemap);
DRW_shgroup_uniform_buffer(grp, "hdrColorBuf", &effects->final_color, 0);
DRW_shgroup_call_add(grp, quad, NULL);
}
}
void EEVEE_draw_effects(EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = stl->effects;
/* Default framebuffer and texture */
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) {
/* Motion Blur */
DRW_framebuffer_bind(fbl->effect_fb);
DRW_draw_pass(psl->motion_blur);
}
/* Restore default framebuffer */
DRW_framebuffer_texture_detach(dtxl->depth);
DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
DRW_framebuffer_bind(dfbl->default_fb);
/* Tonemapping */
DRW_draw_pass(psl->tonemap);
}
void EEVEE_effects_free(void)
{
DRW_SHADER_FREE_SAFE(e_data.tonemap_sh);
DRW_SHADER_FREE_SAFE(e_data.motion_blur_sh);
}

View File

@ -69,7 +69,6 @@ extern char datatoc_bsdf_direct_lib_glsl[];
extern char datatoc_bsdf_sampling_lib_glsl[];
extern char datatoc_lit_surface_frag_glsl[];
extern char datatoc_lit_surface_vert_glsl[];
extern char datatoc_tonemap_frag_glsl[];
extern char datatoc_shadow_frag_glsl[];
extern char datatoc_shadow_geom_glsl[];
extern char datatoc_shadow_vert_glsl[];
@ -284,9 +283,6 @@ static void EEVEE_engine_init(void *ved)
e_data.probe_spherical_harmonic_sh = DRW_shader_create_fullscreen(datatoc_probe_sh_frag_glsl, NULL);
}
if (!e_data.tonemap) {
e_data.tonemap = DRW_shader_create_fullscreen(datatoc_tonemap_frag_glsl, NULL);
}
if (!e_data.ltc_mat) {
e_data.ltc_mat = DRW_texture_create_2D(64, 64, DRW_TEX_RGBA_16, DRW_TEX_FILTER, ltc_mat_ggx);
@ -315,6 +311,8 @@ static void EEVEE_engine_init(void *ved)
EEVEE_probes_init(vedata);
EEVEE_effects_init(vedata);
// EEVEE_lights_update(stl);
}
@ -492,19 +490,10 @@ static void EEVEE_cache_init(void *vedata)
psl->material_pass = DRW_pass_create("Material Shader Pass", state);
}
{
/* Final pass : Map HDR color to LDR color.
* Write result to the default color buffer */
psl->tonemap = DRW_pass_create("Tone Mapping", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND);
DRWShadingGroup *grp = DRW_shgroup_create(e_data.tonemap, psl->tonemap);
DRW_shgroup_uniform_buffer(grp, "hdrColorBuf", &txl->color, 0);
struct Batch *geom = DRW_cache_fullscreen_quad_get();
DRW_shgroup_call_add(grp, geom, NULL);
}
EEVEE_lights_cache_init(stl);
EEVEE_effects_cache_init(vedata);
}
static void EEVEE_cache_populate(void *vedata, Object *ob)
@ -584,8 +573,8 @@ static void EEVEE_cache_populate(void *vedata, Object *ob)
/* TODO, support for all geometry types (non mesh geometry) */
DRW_shgroup_call_add(stl->g_data->default_lit_grp, geom, ob->obmat);
// DRW_shgroup_call_add(stl->g_data->shadow_shgrp, geom, ob->obmat);
eevee_cascade_shadow_shgroup(psl, stl, geom, ob->obmat);
eevee_cube_shadow_shgroup(psl, stl, geom, ob->obmat);
// eevee_cascade_shadow_shgroup(psl, stl, geom, ob->obmat);
// eevee_cube_shadow_shgroup(psl, stl, geom, ob->obmat);
}
// GPUMaterial *gpumat = GPU_material_from_nodetree(struct bNodeTree *ntree, ListBase *gpumaterials, void *engine_type, int options)
@ -638,7 +627,6 @@ static void EEVEE_draw_scene(void *vedata)
EEVEE_FramebufferList *fbl = ((EEVEE_Data *)vedata)->fbl;
/* Default framebuffer and texture */
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
/* Refresh Probes */
@ -663,23 +651,19 @@ static void EEVEE_draw_scene(void *vedata)
DRW_draw_pass(psl->default_pass);
DRW_draw_pass(psl->material_pass);
/* Restore default framebuffer */
DRW_framebuffer_texture_detach(dtxl->depth);
DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0);
DRW_framebuffer_bind(dfbl->default_fb);
DRW_draw_pass(psl->tonemap);
EEVEE_draw_effects(vedata);
}
static void EEVEE_engine_free(void)
{
EEVEE_effects_free();
MEM_SAFE_FREE(e_data.frag_shader_lib);
DRW_SHADER_FREE_SAFE(e_data.default_lit);
DRW_SHADER_FREE_SAFE(e_data.shadow_sh);
DRW_SHADER_FREE_SAFE(e_data.default_world);
DRW_SHADER_FREE_SAFE(e_data.probe_filter_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_spherical_harmonic_sh);
DRW_SHADER_FREE_SAFE(e_data.tonemap);
DRW_TEXTURE_FREE_SAFE(e_data.ltc_mat);
DRW_TEXTURE_FREE_SAFE(e_data.brdf_lut);
DRW_TEXTURE_FREE_SAFE(e_data.hammersley);

View File

@ -43,11 +43,14 @@ typedef struct EEVEE_PassList {
struct DRWPass *probe_prefilter;
struct DRWPass *probe_sh_compute;
/* Effects */
struct DRWPass *motion_blur;
struct DRWPass *tonemap;
struct DRWPass *depth_pass;
struct DRWPass *depth_pass_cull;
struct DRWPass *default_pass;
struct DRWPass *material_pass;
struct DRWPass *tonemap;
} EEVEE_PassList;
typedef struct EEVEE_FramebufferList {
@ -59,6 +62,8 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *probe_fb;
struct GPUFrameBuffer *probe_filter_fb;
struct GPUFrameBuffer *probe_sh_fb;
/* Effects */
struct GPUFrameBuffer *effect_fb; /* HDR */
struct GPUFrameBuffer *main; /* HDR */
} EEVEE_FramebufferList;
@ -75,6 +80,7 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *probe_sh; /* R16_G16_B16 */
struct GPUTexture *color; /* R16_G16_B16 */
struct GPUTexture *color_post; /* R16_G16_B16 */
} EEVEE_TextureList;
typedef struct EEVEE_StorageList {
@ -89,6 +95,9 @@ typedef struct EEVEE_StorageList {
struct EEVEE_ProbesInfo *probes;
struct GPUUniformBuffer *probe_ubo;
/* Effects */
struct EEVEE_EffectsInfo *effects;
struct EEVEE_PrivateData *g_data;
} EEVEE_StorageList;
@ -157,6 +166,24 @@ typedef struct EEVEE_ProbesInfo {
struct GPUTexture *backgroundtex;
} EEVEE_ProbesInfo;
/* ************ EFFECTS DATA ************* */
typedef struct EEVEE_EffectsInfo {
float current_ndc_to_world[4][4];
float past_world_to_ndc[4][4];
float tmp_mat[4][4];
float blur_amount;
int enabled_effects;
/* not alloced, just a pointer to a texture in EEVEE_TextureList.
* Point to the final color buffer to transform to display color space. */
struct GPUTexture *final_color;
} EEVEE_EffectsInfo;
enum {
EFFECT_MOTION_BLUR = (1 << 0),
};
/* *********************************** */
typedef struct EEVEE_Data {
@ -198,6 +225,12 @@ void EEVEE_probes_cache_finish(EEVEE_Data *vedata);
void EEVEE_probes_update(EEVEE_Data *vedata);
void EEVEE_refresh_probe(EEVEE_Data *vedata);
/* eevee_effects.c */
void EEVEE_effects_init(EEVEE_Data *vedata);
void EEVEE_effects_cache_init(EEVEE_Data *vedata);
void EEVEE_draw_effects(EEVEE_Data *vedata);
void EEVEE_effects_free(void);
/* Shadow Matrix */
static const float texcomat[4][4] = { /* From NDC to TexCo */
{0.5, 0.0, 0.0, 0.0},

View File

@ -0,0 +1,59 @@
uniform sampler2D colorBuffer;
uniform sampler2D depthBuffer;
uniform float blurAmount;
/* current frame */
uniform mat4 currInvViewProjMatrix;
/* past frame frame */
uniform mat4 pastViewProjMatrix;
in vec4 uvcoordsvar;
out vec4 FragColor;
#define MAX_SAMPLE 16
float wang_hash_noise(uint s)
{
uint seed = (uint(gl_FragCoord.x) * 1664525u + uint(gl_FragCoord.y)) + s;
seed = (seed ^ 61u) ^ (seed >> 16u);
seed *= 9u;
seed = seed ^ (seed >> 4u);
seed *= 0x27d4eb2du;
seed = seed ^ (seed >> 15u);
float value = float(seed);
value *= 1.0 / 4294967296.0;
return fract(value);
}
void main()
{
vec3 ndc_pos;
ndc_pos.xy = uvcoordsvar.xy;
ndc_pos.z = texture(depthBuffer, uvcoordsvar.xy).x;
float noise = 2.0 * wang_hash_noise(0u) / MAX_SAMPLE;
/* Normalize Device Coordinates are [-1, +1]. */
ndc_pos = ndc_pos * 2.0 - 1.0;
vec4 p = currInvViewProjMatrix * vec4(ndc_pos, 1.0);
vec3 world_pos = p.xyz / p.w; /* Perspective divide */
/* 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 */
vec2 motion = (ndc_pos.xy - old_ndc.xy) * blurAmount;
const float inc = 2.0 / MAX_SAMPLE;
for (float i = -1.0 + noise; i < 1.0; i += inc) {
FragColor += texture(colorBuffer, uvcoordsvar.xy + motion * i) / MAX_SAMPLE;
}
}

View File

@ -296,6 +296,7 @@ void DRW_pass_foreach_shgroup(DRWPass *pass, void (*callback)(void *userData, DR
/* Viewport */
typedef enum {
DRW_MAT_PERS,
DRW_MAT_PERSINV,
DRW_MAT_VIEW,
DRW_MAT_VIEWINV,
DRW_MAT_WIN,

View File

@ -1800,6 +1800,9 @@ void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type)
case DRW_MAT_PERS:
copy_m4_m4(mat, rv3d->persmat);
break;
case DRW_MAT_PERSINV:
copy_m4_m4(mat, rv3d->persinv);
break;
case DRW_MAT_VIEW:
copy_m4_m4(mat, rv3d->viewmat);
break;