diff options
4 files changed, 71 insertions, 11 deletions
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl index 2dea2fc4883..9797a5e3301 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl @@ -5,7 +5,7 @@ uniform sampler2D searchTex; uniform sampler2D blendTex; uniform sampler2D colorTex; uniform float mixFactor; -uniform float taaSampleCountInv; +uniform float taaAccumulatedWeight; in vec2 uvs; in vec2 pixcoord; @@ -39,6 +39,12 @@ void main() if (mixFactor < 1.0) { fragColor += texture(colorTex, uvs) * (1.0 - mixFactor); } - fragColor *= taaSampleCountInv; + fragColor /= taaAccumulatedWeight; + fragColor = exp2(fragColor) - 0.5; + + /* Avoid float precision issue. */ + if (fragColor.a > 0.999) { + fragColor.a = 1.0; + } #endif } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl index b877c2c3f76..d021e4696f7 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl @@ -1,11 +1,22 @@ uniform sampler2D colorBuffer; - -in vec4 uvcoordsvar; +uniform float samplesWeights[9]; out vec4 fragColor; void main() { - fragColor = texture(colorBuffer, uvcoordsvar.st); + vec2 texel_size = 1.0 / vec2(textureSize(colorBuffer, 0)); + vec2 uv = gl_FragCoord.xy * texel_size; + + fragColor = vec4(0.0); + int i = 0; + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++, i++) { + /* Use log2 space to avoid highlights creating too much aliasing. */ + vec4 color = log2(texture(colorBuffer, uv + vec2(x, y) * texel_size) + 0.5); + + fragColor += color * samplesWeights[i]; + } + } } diff --git a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c index feb48b2623d..83aa7f6e344 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c +++ b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c @@ -264,6 +264,37 @@ void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata) } } +static float filter_blackman_harris(float x, const float width) +{ + if (x > width * 0.5f) { + return 0.0f; + } + x = 2.0f * M_PI * clamp_f((x / width + 0.5f), 0.0f, 1.0f); + return 0.35875f - 0.48829f * cosf(x) + 0.14128f * cosf(2.0f * x) - 0.01168f * cosf(3.0f * x); +} + +/* Compute weights for the 3x3 neighborhood using a 1.5px filter. */ +static void workbench_antialiasing_weights_get(const float offset[2], + float r_weights[9], + float *r_weight_sum) +{ + /* NOTE: If filter width is bigger than 2.0f, then we need to sample more neighborhood. */ + const float filter_width = 2.0f; + *r_weight_sum = 0.0f; + int i = 0; + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++, i++) { + float sample_co[2] = {x, y}; + add_v2_v2(sample_co, offset); + float r = len_v2(sample_co); + /* fclem: is radial distance ok here? */ + float weight = filter_blackman_harris(r, filter_width); + *r_weight_sum += weight; + r_weights[i] = weight; + } + } +} + void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata) { WORKBENCH_TextureList *txl = vedata->txl; @@ -278,10 +309,12 @@ void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata) { DRW_PASS_CREATE(psl->aa_accum_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL); + DRW_PASS_INSTANCE_CREATE(psl->aa_accum_replace_ps, psl->aa_accum_ps, DRW_STATE_WRITE_COLOR); GPUShader *shader = workbench_shader_antialiasing_accumulation_get(); grp = DRW_shgroup_create(shader, psl->aa_accum_ps); - DRW_shgroup_uniform_texture(grp, "colorBuffer", dtxl->color); + DRW_shgroup_uniform_texture_ex(grp, "colorBuffer", dtxl->color, GPU_SAMPLER_DEFAULT); + DRW_shgroup_uniform_float(grp, "samplesWeights", wpd->taa_weights, 9); DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } @@ -325,7 +358,7 @@ void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata) DRW_shgroup_uniform_texture(grp, "colorTex", txl->history_buffer_tx); DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics); DRW_shgroup_uniform_float(grp, "mixFactor", &wpd->smaa_mix_factor, 1); - DRW_shgroup_uniform_float(grp, "taaSampleCountInv", &wpd->taa_sample_inv, 1); + DRW_shgroup_uniform_float(grp, "taaAccumulatedWeight", &wpd->taa_weight_accum, 1); DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } @@ -369,6 +402,8 @@ bool workbench_antialiasing_setup(WORKBENCH_Data *vedata) break; } + workbench_antialiasing_weights_get(transform_offset, wpd->taa_weights, &wpd->taa_weights_sum); + /* construct new matrices from transform delta */ float winmat[4][4], viewmat[4][4], persmat[4][4]; DRW_view_winmat_get(default_view, winmat, false); @@ -419,8 +454,11 @@ void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata) const bool last_sample = wpd->taa_sample + 1 == wpd->taa_sample_len; const bool taa_finished = wpd->taa_sample >= wpd->taa_sample_len; if (wpd->taa_sample == 0) { + wpd->taa_weight_accum = wpd->taa_weights_sum; wpd->valid_history = true; - GPU_texture_copy(txl->history_buffer_tx, dtxl->color); + + GPU_framebuffer_bind(fbl->antialiasing_fb); + DRW_draw_pass(psl->aa_accum_replace_ps); /* In playback mode, we are sure the next redraw will not use the same viewmatrix. * In this case no need to save the depth buffer. */ if (!wpd->is_playback) { @@ -435,6 +473,7 @@ void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata) /* Accumulate result to the TAA buffer. */ GPU_framebuffer_bind(fbl->antialiasing_fb); DRW_draw_pass(psl->aa_accum_ps); + wpd->taa_weight_accum += wpd->taa_weights_sum; } /* Copy back the saved depth buffer for correct overlays. */ GPU_texture_copy(dtxl->depth, txl->depth_buffer_tx); @@ -446,7 +485,6 @@ void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata) if (!DRW_state_is_image_render() || last_sample) { /* After a certain point SMAA is no longer necessary. */ wpd->smaa_mix_factor = 1.0f - clamp_f(wpd->taa_sample / 4.0f, 0.0f, 1.0f); - wpd->taa_sample_inv = 1.0f / min_ii(wpd->taa_sample + 1, wpd->taa_sample_len); if (wpd->smaa_mix_factor > 0.0f) { GPU_framebuffer_bind(fbl->smaa_edge_fb); diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 522aae7f542..6247436feea 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -164,6 +164,7 @@ typedef struct WORKBENCH_PassList { struct DRWPass *volume_ps; struct DRWPass *aa_accum_ps; + struct DRWPass *aa_accum_replace_ps; struct DRWPass *aa_edge_ps; struct DRWPass *aa_weight_ps; struct DRWPass *aa_resolve_ps; @@ -286,8 +287,12 @@ typedef struct WORKBENCH_PrivateData { int taa_sample_len_previous; /** Current TAA sample index in [0..taa_sample_len[ range. */ int taa_sample; - /** Inverse of taa_sample to divide the accumulation buffer. */ - float taa_sample_inv; + /** Weight accumulated. */ + float taa_weight_accum; + /** Samples weight for this iteration. */ + float taa_weights[9]; + /** Sum of taa_weights. */ + float taa_weights_sum; /** If the view has been updated and TAA needs to be reset. */ bool view_updated; /** True if the history buffer contains relevant data and false if it could contain garbage. */ |