Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2018-04-20 19:24:14 +0300
committerClément Foucault <foucault.clem@gmail.com>2018-04-20 19:29:33 +0300
commit73d2e6f2021e649a1bf8952c37ce870562a884e4 (patch)
tree915c066afd7d92a433720b0a415da4de177d8720 /source/blender/draw/engines
parentbe307d6032f390cd71bcbb92402c1929a085db1f (diff)
Eevee: TAA Reprojection: Initial implementation
This "improve" the viewport experience by reducing the noise from random sampling effects (SSAO, Contact Shadows, SSR) when moving the viewport or during playback. This does not do Anti Aliasing because this would conflict with the outline pass. We could enable AA jittering in "only render" mode though. There are many things to improve but this is a solid basis to build upon.
Diffstat (limited to 'source/blender/draw/engines')
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c16
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c13
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h3
-rw-r--r--source/blender/draw/engines/eevee/eevee_temporal_sampling.c119
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl25
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl104
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