diff options
6 files changed, 233 insertions, 47 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 14924345d3e..ccb61d3e328 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -251,6 +251,22 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object } /** + * Setup depth double buffer. + */ + if ((effects->enabled_effects & EFFECT_DEPTH_DOUBLE_BUFFER) != 0) { + DRW_texture_ensure_fullscreen_2D(&txl->depth_double_buffer, DRW_TEX_DEPTH_24_STENCIL_8, 0); + + GPU_framebuffer_ensure_config(&fbl->double_buffer_depth_fb, { + GPU_ATTACHMENT_TEXTURE(txl->depth_double_buffer) + }); + } + else { + /* Cleanup to release memory */ + DRW_TEXTURE_FREE_SAFE(txl->depth_double_buffer); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->double_buffer_depth_fb); + } + + /** * Setup double buffer so we can access last frame as it was before post processes. */ if ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0) { diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index be9a9fa157a..2c459f5ae3b 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -204,12 +204,18 @@ static void eevee_draw_background(void *vedata) double offset[3] = {0.0, 0.0, 0.0}; double r[3]; + bool taa_use_reprojection = (stl->effects->enabled_effects & EFFECT_TAA_REPROJECT) != 0; + if (DRW_state_is_image_render() || + taa_use_reprojection || ((stl->effects->enabled_effects & EFFECT_TAA) != 0)) { - BLI_halton_3D(primes, offset, stl->effects->taa_current_sample, r); + int samp = taa_use_reprojection + ? stl->effects->taa_reproject_sample + 1 + : stl->effects->taa_current_sample; + BLI_halton_3D(primes, offset, samp, r); EEVEE_update_noise(psl, fbl, r); - EEVEE_volumes_set_jitter(sldata, stl->effects->taa_current_sample - 1); + EEVEE_volumes_set_jitter(sldata, samp - 1); EEVEE_materials_init(sldata, stl, fbl); } /* Copy previous persmat to UBO data */ @@ -217,7 +223,8 @@ static void eevee_draw_background(void *vedata) if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) && (stl->effects->taa_current_sample > 1) && - !DRW_state_is_image_render()) + !DRW_state_is_image_render() && + !taa_use_reprojection) { DRW_viewport_matrix_override_set(stl->effects->overide_persmat, DRW_MAT_PERS); DRW_viewport_matrix_override_set(stl->effects->overide_persinv, DRW_MAT_PERSINV); diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 07624100ea7..9c4d7d65ccd 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -483,6 +483,8 @@ typedef enum EEVEE_EffectsFlag { 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 */ + EFFECT_TAA_REPROJECT = (1 << 13), /* should be mutually exclusive with EFFECT_TAA */ + EFFECT_DEPTH_DOUBLE_BUFFER = (1 << 14), /* Not really an effect but a feature */ } EEVEE_EffectsFlag; typedef struct EEVEE_EffectsInfo { @@ -506,6 +508,7 @@ typedef struct EEVEE_EffectsInfo { struct GPUTexture *ssr_hit_output; struct GPUTexture *ssr_pdf_output; /* Temporal Anti Aliasing */ + int taa_reproject_sample; int taa_current_sample; int taa_render_sample; int taa_total_sample; diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c index acc1bff6331..06f6293240d 100644 --- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c +++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c @@ -27,7 +27,10 @@ #include "DRW_render.h" +#include "ED_screen.h" + #include "BLI_rand.h" +#include "BLI_string_utils.h" #include "eevee_private.h" #include "GPU_texture.h" @@ -37,16 +40,29 @@ static struct { /* Temporal Anti Aliasing */ struct GPUShader *taa_resolve_sh; + struct GPUShader *taa_resolve_reproject_sh; /* Pixel filter table: Only blackman-harris for now. */ float inverted_cdf[FILTER_CDF_TABLE_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_temporal_aa_glsl[]; static void eevee_create_shader_temporal_sampling(void) { - e_data.taa_resolve_sh = DRW_shader_create_fullscreen(datatoc_effect_temporal_aa_glsl, NULL); + char *frag_str = BLI_string_joinN( + datatoc_common_uniforms_lib_glsl, + datatoc_common_view_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_effect_temporal_aa_glsl); + + e_data.taa_resolve_sh = DRW_shader_create_fullscreen(frag_str, NULL); + e_data.taa_resolve_reproject_sh = DRW_shader_create_fullscreen(frag_str, "#define USE_REPROJECTION\n"); + + MEM_freeN(frag_str); } static float UNUSED_FUNCTION(filter_box)(float UNUSED(x)) @@ -163,6 +179,11 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; + if (!e_data.taa_resolve_sh) { + eevee_create_shader_temporal_sampling(); + eevee_create_cdf_table_temporal_sampling(); + } + /* Reset for each "redraw". When rendering using ogl render, * we accumulate the redraw inside the drawing loop in eevee_draw_background(). * But we do NOT accumulate between "redraw" (as in full draw manager drawloop) @@ -173,6 +194,14 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data ViewLayer *view_layer = draw_ctx->view_layer; IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); + int repro_flag = 0; + if (!DRW_state_is_image_render() && + BKE_collection_engine_property_value_get_bool(props, "taa_reprojection")) + { + repro_flag = EFFECT_TAA_REPROJECT | EFFECT_VELOCITY_BUFFER | EFFECT_DEPTH_DOUBLE_BUFFER | EFFECT_DOUBLE_BUFFER | EFFECT_POST_BUFFER; + effects->taa_reproject_sample = ((effects->taa_reproject_sample + 1) % 16); + } + if ((BKE_collection_engine_property_value_get_int(props, "taa_samples") != 1 && /* FIXME the motion blur camera evaluation is tagging view_updated * thus making the TAA always reset and never stopping rendering. */ @@ -181,17 +210,17 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data { float persmat[4][4], viewmat[4][4]; - if (!e_data.taa_resolve_sh) { - eevee_create_shader_temporal_sampling(); - eevee_create_cdf_table_temporal_sampling(); - } - /* Until we support reprojection, we need to make sure * that the history buffer contains correct information. */ bool view_is_valid = stl->g_data->valid_double_buffer; view_is_valid = view_is_valid && (stl->g_data->view_updated == false); + 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); + } + effects->taa_total_sample = BKE_collection_engine_property_value_get_int(props, "taa_samples"); MAX2(effects->taa_total_sample, 0); @@ -215,6 +244,7 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data /* OGL render already jitter the camera. */ if (!DRW_state_is_image_render()) { effects->taa_current_sample += 1; + repro_flag = 0; double ht_point[2]; double ht_offset[2] = {0.0, 0.0}; @@ -238,42 +268,54 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data effects->taa_current_sample = 1; } - DRW_texture_ensure_fullscreen_2D(&txl->depth_double_buffer, DRW_TEX_DEPTH_24_STENCIL_8, 0); - - GPU_framebuffer_ensure_config(&fbl->double_buffer_depth_fb, { - GPU_ATTACHMENT_TEXTURE(txl->depth_double_buffer) - }); - - return EFFECT_TAA | EFFECT_DOUBLE_BUFFER | EFFECT_POST_BUFFER; + return repro_flag | EFFECT_TAA | EFFECT_DOUBLE_BUFFER | EFFECT_DEPTH_DOUBLE_BUFFER | EFFECT_POST_BUFFER; } effects->taa_current_sample = 1; - /* Cleanup to release memory */ - DRW_TEXTURE_FREE_SAFE(txl->depth_double_buffer); - GPU_FRAMEBUFFER_FREE_SAFE(fbl->double_buffer_depth_fb); - - return 0; + return repro_flag; } -void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; - if ((effects->enabled_effects & EFFECT_TAA) != 0) { + if ((effects->enabled_effects & (EFFECT_TAA | EFFECT_TAA_REPROJECT)) != 0) { + struct GPUShader *sh = (effects->enabled_effects & EFFECT_TAA_REPROJECT) + ? e_data.taa_resolve_reproject_sh + : e_data.taa_resolve_sh; + psl->taa_resolve = DRW_pass_create("Temporal AA Resolve", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.taa_resolve_sh, psl->taa_resolve); + DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->taa_resolve); - DRW_shgroup_uniform_texture_ref(grp, "historyBuffer", &txl->color_double_buffer); + DRW_shgroup_uniform_texture_ref(grp, "colorHistoryBuffer", &txl->color_double_buffer); DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &txl->color); - DRW_shgroup_uniform_float(grp, "alpha", &effects->taa_alpha, 1); + + if (effects->enabled_effects & EFFECT_TAA_REPROJECT) { + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + DRW_shgroup_uniform_texture_ref(grp, "velocityBuffer", &effects->velocity_tx); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + } + else { + DRW_shgroup_uniform_float(grp, "alpha", &effects->taa_alpha, 1); + } DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); } } +/* Special Swap */ +#define SWAP_BUFFER_TAA() do { \ + SWAP(struct GPUFrameBuffer *, fbl->effect_fb, fbl->double_buffer_fb); \ + SWAP(struct GPUFrameBuffer *, fbl->effect_color_fb, fbl->double_buffer_color_fb); \ + SWAP(GPUTexture *, txl->color_post, txl->color_double_buffer); \ + effects->swap_double_buffer = false; \ + effects->source_buffer = txl->color_double_buffer; \ + effects->target_buffer = fbl->main_color_fb; \ +} while (0); + void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; @@ -282,8 +324,8 @@ void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata) EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - if ((effects->enabled_effects & EFFECT_TAA) != 0) { - if (effects->taa_current_sample != 1) { + if ((effects->enabled_effects & (EFFECT_TAA | EFFECT_TAA_REPROJECT)) != 0) { + if ((effects->enabled_effects & EFFECT_TAA) != 0 && effects->taa_current_sample != 1) { if (DRW_state_is_image_render()) { /* See EEVEE_temporal_sampling_init() for more details. */ effects->taa_alpha = 1.0f / (float)(effects->taa_render_sample); @@ -300,19 +342,24 @@ void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata) GPU_framebuffer_blit(fbl->double_buffer_depth_fb, 0, fbl->main_fb, 0, GPU_DEPTH_BIT); } - /* Special Swap */ - SWAP(struct GPUFrameBuffer *, fbl->effect_fb, fbl->double_buffer_fb); - SWAP(struct GPUFrameBuffer *, fbl->effect_color_fb, fbl->double_buffer_color_fb); - SWAP(GPUTexture *, txl->color_post, txl->color_double_buffer); - effects->swap_double_buffer = false; - effects->source_buffer = txl->color_double_buffer; - effects->target_buffer = fbl->main_color_fb; + SWAP_BUFFER_TAA(); } else { - /* Save the depth buffer for the next frame. - * This saves us from doing anything special - * in the other mode engines. */ if (!DRW_state_is_image_render()) { + /* Do reprojection for noise reduction */ + /* TODO : do AA jitter if in only render view. */ + if ((effects->enabled_effects & EFFECT_TAA_REPROJECT) != 0 && + stl->g_data->valid_double_buffer) + { + GPU_framebuffer_bind(fbl->effect_color_fb); + DRW_draw_pass(psl->taa_resolve); + + SWAP_BUFFER_TAA(); + } + + /* Save the depth buffer for the next frame. + * This saves us from doing anything special + * in the other mode engines. */ GPU_framebuffer_blit(fbl->main_fb, 0, fbl->double_buffer_depth_fb, 0, GPU_DEPTH_BIT); } } @@ -330,10 +377,10 @@ void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata) } } } - } void EEVEE_temporal_sampling_free(void) { DRW_SHADER_FREE_SAFE(e_data.taa_resolve_sh); + DRW_SHADER_FREE_SAFE(e_data.taa_resolve_reproject_sh); } 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 b5e54c8747a..9f4f508d6fd 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -95,6 +95,30 @@ vec3 project_point(mat4 m, vec3 v) { return tmp.xyz / tmp.w; } +#define min3(a, b, c) min(a, min(b, c)) +#define min4(a, b, c, d) min(a, min3(b, c, d)) +#define min5(a, b, c, d, e) min(a, min4(b, c, d, e)) +#define min6(a, b, c, d, e, f) min(a, min5(b, c, d, e, f)) +#define min7(a, b, c, d, e, f, g) min(a, min6(b, c, d, e, f, g)) +#define min8(a, b, c, d, e, f, g, h) min(a, min7(b, c, d, e, f, g, h)) +#define min9(a, b, c, d, e, f, g, h, i) min(a, min8(b, c, d, e, f, g, h, i)) + +#define max3(a, b, c) max(a, max(b, c)) +#define max4(a, b, c, d) max(a, max3(b, c, d)) +#define max5(a, b, c, d, e) max(a, max4(b, c, d, e)) +#define max6(a, b, c, d, e, f) max(a, max5(b, c, d, e, f)) +#define max7(a, b, c, d, e, f, g) max(a, max6(b, c, d, e, f, g)) +#define max8(a, b, c, d, e, f, g, h) max(a, max7(b, c, d, e, f, g, h)) +#define max9(a, b, c, d, e, f, g, h, i) max(a, max8(b, c, d, e, f, g, h, i)) + +#define avg3(a, b, c) (a + b + c) * (1.0 / 3.0) +#define avg4(a, b, c, d) (a + b + c + d) * (1.0 / 4.0) +#define avg5(a, b, c, d, e) (a + b + c + d + e) * (1.0 / 5.0) +#define avg6(a, b, c, d, e, f) (a + b + c + d + e + f) * (1.0 / 6.0) +#define avg7(a, b, c, d, e, f, g) (a + b + c + d + e + f + g) * (1.0 / 7.0) +#define avg8(a, b, c, d, e, f, g, h) (a + b + c + d + e + f + g + h) * (1.0 / 8.0) +#define avg9(a, b, c, d, e, f, g, h, i) (a + b + c + d + e + f + g + h + i) * (1.0 / 9.0) + float min_v2(vec2 v) { return min(v.x, v.y); } float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); } float max_v2(vec2 v) { return max(v.x, v.y); } @@ -252,6 +276,7 @@ void make_orthonormal_basis(vec3 N, out vec3 T, out vec3 B) } /* ---- Opengl Depth conversion ---- */ + float linear_depth(bool is_persp, float z, float zf, float zn) { if (is_persp) { 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 f3df1864317..b3b94b0a391 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl @@ -1,14 +1,102 @@ -uniform sampler2D colorBuffer; -uniform sampler2D historyBuffer; -uniform float alpha; +uniform sampler2D colorHistoryBuffer; +uniform sampler2D velocityBuffer; out vec4 FragColor; +#ifdef USE_REPROJECTION + +/** + * Adapted from https://casual-effects.com/g3d/G3D10/data-files/shader/Film/Film_temporalAA.pix + * which is adapted from https://github.com/gokselgoktas/temporal-anti-aliasing/blob/master/Assets/Resources/Shaders/TemporalAntiAliasing.cginc + * which is adapted from https://github.com/playdeadgames/temporal + * Optimization by Stubbesaurus and epsilon adjustment to avoid division by zero. + * + * This can cause 3x3 blocks of color when there is a thin edge of a similar color that + * is varying in intensity. + */ +vec3 clip_to_aabb(vec3 color, vec3 minimum, vec3 maximum, vec3 average) +{ + /* note: only clips towards aabb center (but fast!) */ + vec3 center = 0.5 * (maximum + minimum); + vec3 extents = 0.5 * (maximum - minimum); + vec3 dist = color - center; + vec3 ts = abs(extents) / max(abs(dist), vec3(0.0001)); + float t = saturate(min_v3(ts)); + return center + dist * t; +} + +/** + * Vastly based on https://github.com/playdeadgames/temporal + */ +void main() +{ + ivec2 texel = ivec2(gl_FragCoord.xy); + float depth = texelFetch(depthBuffer, texel, 0).r; + vec2 motion = texelFetch(velocityBuffer, texel, 0).rg; + + /* 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; + + ivec2 texel_history = ivec2(uv_history * screen_res); + vec4 color_history = textureLod(colorHistoryBuffer, uv_history, 0.0); + + /* Color bounding box clamping. 3x3 neighborhood. */ + vec4 c02 = texelFetchOffset(colorBuffer, texel, 0, ivec2(-1, 1)); + vec4 c12 = texelFetchOffset(colorBuffer, texel, 0, ivec2( 0, 1)); + vec4 c22 = texelFetchOffset(colorBuffer, texel, 0, ivec2( 1, 1)); + vec4 c01 = texelFetchOffset(colorBuffer, texel, 0, ivec2(-1, 0)); + vec4 c11 = texelFetchOffset(colorBuffer, texel, 0, ivec2( 0, 0)); + vec4 c21 = texelFetchOffset(colorBuffer, texel, 0, ivec2( 1, 0)); + vec4 c00 = texelFetchOffset(colorBuffer, texel, 0, ivec2(-1, -1)); + vec4 c10 = texelFetchOffset(colorBuffer, texel, 0, ivec2( 0, -1)); + vec4 c20 = texelFetchOffset(colorBuffer, texel, 0, ivec2( 1, -1)); + + vec4 color = c11; + + /* AABB minmax */ + vec4 min_col = min9(c02, c12, c22, c01, c11, c21, c00, c10, c20); + vec4 max_col = max9(c02, c12, c22, c01, c11, c21, c00, c10, c20); + vec4 avg_col = avg9(c02, c12, c22, c01, c11, c21, c00, c10, c20); + + /* bias the color aabb toward the center (rounding the shape) */ + vec4 min_center = min5(c12, c01, c11, c21, c10); + vec4 max_center = max5(c12, c01, c11, c21, c10); + vec4 avg_center = avg5(c12, c01, c11, c21, c10); + min_col = (min_col + min_center) * 0.5; + max_col = (max_col + max_center) * 0.5; + avg_col = (avg_col + avg_center) * 0.5; + + /* Clip color toward the center of the neighborhood colors AABB box. */ + color_history.rgb = clip_to_aabb(color_history.rgb, min_col.rgb, max_col.rgb, avg_col.rgb); + + /* Luminance weighting. */ + /* TODO correct luminance */ + float lum0 = dot(color.rgb, vec3(0.333)); + float lum1 = dot(color_history.rgb, vec3(0.333)); + float diff = abs(lum0 - lum1) / max(lum0, max(lum1, 0.2)); + float weight = 1.0 - diff; + float alpha = mix(0.04, 0.12, weight * weight); + + color_history = mix(color_history, color, alpha); + + bool out_of_view = any(greaterThanEqual(abs(uv_history - 0.5), vec2(0.5))); + color_history = (out_of_view) ? color : color_history; + + FragColor = color_history; +} + +#else + +uniform float alpha; + void main() { - /* TODO History buffer Reprojection */ - vec4 history = texelFetch(historyBuffer, ivec2(gl_FragCoord.xy), 0).rgba; - vec4 color = texelFetch(colorBuffer, ivec2(gl_FragCoord.xy), 0).rgba; - FragColor = mix(history, color, alpha); -}
\ No newline at end of file + ivec2 texel = ivec2(gl_FragCoord.xy); + vec4 color = texelFetch(colorBuffer, texel, 0); + vec4 color_history = texelFetch(colorHistoryBuffer, texel, 0); + FragColor = mix(color_history, color, alpha); +} +#endif
\ No newline at end of file |