Eevee: Add Velocity pass.
authorClément Foucault <foucault.clem@gmail.com>
Fri, 20 Apr 2018 16:18:33 +0000 (18:18 +0200)
committerClément Foucault <foucault.clem@gmail.com>
Fri, 20 Apr 2018 16:29:33 +0000 (18:29 +0200)
This pass create a velocity buffer which is basically a 2D motion vector
texture. This is not yet used for rendering but will be usefull for motion
blur and temporal reprojection.

source/blender/draw/CMakeLists.txt
source/blender/draw/engines/eevee/eevee_effects.c
source/blender/draw/engines/eevee/eevee_engine.c
source/blender/draw/engines/eevee/eevee_private.h
source/blender/draw/engines/eevee/shaders/effect_velocity_resolve_frag.glsl [new file with mode: 0644]

index d8143fef77124af80d2299fd1b388252191e805e..22106c55bdabc5af5832bbc492e4fb97a6d6d296 100644 (file)
@@ -174,6 +174,7 @@ data_to_c_simple(engines/eevee/shaders/effect_dof_frag.glsl SRC)
 data_to_c_simple(engines/eevee/shaders/effect_downsample_frag.glsl SRC)
 data_to_c_simple(engines/eevee/shaders/effect_downsample_cube_frag.glsl SRC)
 data_to_c_simple(engines/eevee/shaders/effect_gtao_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/effect_velocity_resolve_frag.glsl SRC)
 data_to_c_simple(engines/eevee/shaders/effect_minmaxz_frag.glsl SRC)
 data_to_c_simple(engines/eevee/shaders/effect_mist_frag.glsl SRC)
 data_to_c_simple(engines/eevee/shaders/effect_motion_blur_frag.glsl SRC)
index 719ff879e8e1f8a0ac5377b607a1d21772a26f87..14924345d3ea262ca44db4b0fbff67a772f88cef 100644 (file)
 
 #include "DRW_render.h"
 
+#include "BKE_global.h" /* for G.debug_value */
+
+#include "BLI_string_utils.h"
+
 #include "eevee_private.h"
 #include "GPU_texture.h"
 #include "GPU_extensions.h"
@@ -46,6 +50,9 @@ static struct {
        struct GPUShader *downsample_sh;
        struct GPUShader *downsample_cube_sh;
 
+       /* Velocity Resolve */
+       struct GPUShader *velocity_resolve_sh;
+
        /* Theses are just references, not actually allocated */
        struct GPUTexture *depth_src;
        struct GPUTexture *color_src;
@@ -54,6 +61,10 @@ static struct {
        float cube_texel_size;
 } e_data = {NULL}; /* Engine data */
 
+extern char datatoc_common_uniforms_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_bsdf_common_lib_glsl[];
+extern char datatoc_effect_velocity_resolve_frag_glsl[];
 extern char datatoc_effect_minmaxz_frag_glsl[];
 extern char datatoc_effect_downsample_frag_glsl[];
 extern char datatoc_effect_downsample_cube_frag_glsl[];
@@ -62,6 +73,16 @@ extern char datatoc_lightprobe_geom_glsl[];
 
 static void eevee_create_shader_downsample(void)
 {
+       char *frag_str = BLI_string_joinN(
+           datatoc_common_uniforms_lib_glsl,
+           datatoc_common_view_lib_glsl,
+           datatoc_bsdf_common_lib_glsl,
+           datatoc_effect_velocity_resolve_frag_glsl);
+
+       e_data.velocity_resolve_sh = DRW_shader_create_fullscreen(frag_str, NULL);
+
+       MEM_freeN(frag_str);
+
        e_data.downsample_sh = DRW_shader_create_fullscreen(datatoc_effect_downsample_frag_glsl, NULL);
        e_data.downsample_cube_sh = DRW_shader_create(
                datatoc_lightprobe_vert_glsl,
@@ -110,6 +131,8 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object
        ViewLayer *view_layer = draw_ctx->view_layer;
 
        const float *viewport_size = DRW_viewport_size_get();
+       int size_fs[2] = {(int)viewport_size[0], (int)viewport_size[1]};
+
        /* Shaders */
        if (!e_data.downsample_sh) {
                eevee_create_shader_downsample();
@@ -122,6 +145,7 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object
        effects = stl->effects;
 
        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_bloom_init(sldata, vedata);
        effects->enabled_effects |= EEVEE_depth_of_field_init(sldata, vedata, camera);
@@ -163,9 +187,9 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object
        /**
         * MinMax Pyramid
         */
-       int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
-       size[0] = max_ii(size[0] / 2, 1);
-       size[1] = max_ii(size[1] / 2, 1);
+       int size[2];
+       size[0] = max_ii(size_fs[0] / 2, 1);
+       size[1] = max_ii(size_fs[1] / 2, 1);
 
        if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
                /* Intel gpu seems to have problem rendering to only depth format */
@@ -197,8 +221,6 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object
         * Normal buffer for deferred passes.
         */
        if ((effects->enabled_effects & EFFECT_NORMAL_BUFFER) != 0)     {
-               int size_fs[2] = {(int)viewport_size[0], (int)viewport_size[1]};
-
                effects->ssr_normal_input = DRW_texture_pool_query_2D(size_fs[0], size_fs[1], DRW_TEX_RG_16,
                                                                      &draw_engine_eevee_type);
 
@@ -208,6 +230,26 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object
                effects->ssr_normal_input = NULL;
        }
 
+       /**
+        * Motion vector buffer for correct TAA / motion blur.
+        */
+       if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) {
+               /* TODO use RG16_UNORM */
+               effects->velocity_tx = DRW_texture_pool_query_2D(size_fs[0], size_fs[1], DRW_TEX_RG_32,
+                                                                &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_resolve_fb, {
+                       GPU_ATTACHMENT_NONE,
+                       GPU_ATTACHMENT_TEXTURE(effects->velocity_tx)
+               });
+       }
+       else {
+               effects->velocity_tx = NULL;
+       }
+
        /**
         * Setup double buffer so we can access last frame as it was before post processes.
         */
@@ -235,6 +277,8 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
 {
        EEVEE_PassList *psl = vedata->psl;
        EEVEE_TextureList *txl = vedata->txl;
+       EEVEE_StorageList *stl = vedata->stl;
+       EEVEE_EffectsInfo *effects = stl->effects;
        int downsample_write = DRW_STATE_WRITE_DEPTH;
 
        /* Intel gpu seems to have problem rendering to only depth format.
@@ -291,6 +335,17 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
                DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
                DRW_shgroup_call_add(grp, quad, NULL);
        }
+
+       if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) {
+               /* This pass compute camera motions to the non moving objects. */
+               psl->velocity_resolve = DRW_pass_create("Velocity Resolve", DRW_STATE_WRITE_COLOR);
+               DRWShadingGroup *grp = DRW_shgroup_create(e_data.velocity_resolve_sh, 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_mat4(grp, "currPersinv", effects->velocity_curr_persinv);
+               DRW_shgroup_uniform_mat4(grp, "pastPersmat", effects->velocity_past_persmat);
+               DRW_shgroup_call_add(grp, quad, NULL);
+       }
 }
 
 #if 0 /* Not required for now */
@@ -401,11 +456,21 @@ void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, GPUTexture *texture_src, i
 
 void EEVEE_draw_effects(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
 {
+       EEVEE_PassList *psl = vedata->psl;
        EEVEE_TextureList *txl = vedata->txl;
        EEVEE_FramebufferList *fbl = vedata->fbl;
        EEVEE_StorageList *stl = vedata->stl;
        EEVEE_EffectsInfo *effects = stl->effects;
 
+       /* First resolve the velocity. */
+       if ((effects->enabled_effects & EFFECT_VELOCITY_BUFFER) != 0) {
+               DRW_viewport_matrix_get(effects->velocity_curr_persinv, DRW_MAT_PERSINV);
+
+               GPU_framebuffer_bind(fbl->velocity_resolve_fb);
+               DRW_draw_pass(psl->velocity_resolve);
+       }
+       DRW_viewport_matrix_get(effects->velocity_past_persmat, DRW_MAT_PERS);
+
        /* only once per frame after the first post process */
        effects->swap_double_buffer = ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0);
 
@@ -448,6 +513,8 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
 
 void EEVEE_effects_free(void)
 {
+       DRW_SHADER_FREE_SAFE(e_data.velocity_resolve_sh);
+
        DRW_SHADER_FREE_SAFE(e_data.downsample_sh);
        DRW_SHADER_FREE_SAFE(e_data.downsample_cube_sh);
 
index 276f23c7cf79f601d9fe1d2b8af8cccd87f6ff86..3dd7d98842beead55b79e7b127a7f4b80b078a1f 100644 (file)
@@ -333,6 +333,9 @@ static void eevee_draw_background(void *vedata)
                case 8:
                        if (effects->sss_data) DRW_transform_to_display(effects->sss_data);
                        break;
+               case 9:
+                       if (effects->velocity_tx) DRW_transform_to_display(effects->velocity_tx);
+                       break;
                default:
                        break;
        }
index f0ba458dcc88bf235649a7ba56070c00bedec1c5..07624100ea741fbb4eb74c475228beeffcf712a0 100644 (file)
@@ -184,6 +184,7 @@ typedef struct EEVEE_PassList {
        struct DRWPass *sss_accum_ps;
        struct DRWPass *color_downsample_ps;
        struct DRWPass *color_downsample_cube_ps;
+       struct DRWPass *velocity_resolve;
        struct DRWPass *taa_resolve;
 
        /* HiZ */
@@ -235,6 +236,7 @@ typedef struct EEVEE_FramebufferList {
        struct GPUFrameBuffer *refract_fb;
        struct GPUFrameBuffer *mist_accum_fb;
        struct GPUFrameBuffer *ao_accum_fb;
+       struct GPUFrameBuffer *velocity_resolve_fb;
 
        struct GPUFrameBuffer *update_noise_fb;
 
@@ -480,6 +482,7 @@ typedef enum EEVEE_EffectsFlag {
        EFFECT_POST_BUFFER         = (1 << 9), /* Not really an effect but a feature */
        EFFECT_NORMAL_BUFFER       = (1 << 10), /* Not really an effect but a feature */
        EFFECT_SSS                 = (1 << 11),
+       EFFECT_VELOCITY_BUFFER     = (1 << 12), /* Not really an effect but a feature */
 } EEVEE_EffectsFlag;
 
 typedef struct EEVEE_EffectsInfo {
@@ -522,6 +525,10 @@ typedef struct EEVEE_EffectsInfo {
        float current_ndc_to_world[4][4];
        float past_world_to_ndc[4][4];
        int motion_blur_samples;
+       /* Velocity Pass */
+       float velocity_curr_persinv[4][4];
+       float velocity_past_persmat[4][4];
+       struct GPUTexture *velocity_tx; /* Texture from pool */
        /* Depth Of Field */
        float dof_near_far[2];
        float dof_params[3];
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
new file mode 100644 (file)
index 0000000..9c11827
--- /dev/null
@@ -0,0 +1,19 @@
+
+uniform mat4 currPersinv;
+uniform mat4 pastPersmat;
+
+out vec2 outData;
+
+void main()
+{
+       /* Extract pixel motion vector from camera movement. */
+       ivec2 texel = ivec2(gl_FragCoord.xy);
+       vec2 uv = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0).xy);
+
+       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;
+
+       outData = uv - uv_history;
+}