From 0aa2a662b91a33c6457408a02f92cfdb82bcaaee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Sun, 7 May 2017 14:27:43 +0200 Subject: [PATCH] Eevee: Add Bloom post process. Based on Kino/Bloom v2 - Bloom filter for Unity MIT license. --- source/blender/draw/CMakeLists.txt | 1 + .../draw/engines/eevee/eevee_effects.c | 264 +++++++++++++++++- .../draw/engines/eevee/eevee_private.h | 39 ++- .../eevee/shaders/effect_bloom_frag.glsl | 207 ++++++++++++++ source/blender/draw/intern/draw_manager.c | 1 - 5 files changed, 492 insertions(+), 20 deletions(-) create mode 100644 source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 64371d74960..0b229ecee8d 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -114,6 +114,7 @@ data_to_c_simple(engines/eevee/shaders/default_world_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/background_vert.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_bloom_frag.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) diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index dfae27b9cec..2279f0a6b44 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -43,13 +43,22 @@ typedef struct EEVEE_ProbeData { /* TODO Option */ #define ENABLE_EFFECT_MOTION_BLUR 1 +#define ENABLE_EFFECT_BLOOM 1 static struct { struct GPUShader *motion_blur_sh; + + /* Bloom */ + struct GPUShader *bloom_blit_sh[2]; + struct GPUShader *bloom_downsample_sh[2]; + struct GPUShader *bloom_upsample_sh[2]; + struct GPUShader *bloom_resolve_sh[2]; + struct GPUShader *tonemap_sh; } e_data = {NULL}; /* Engine data */ extern char datatoc_effect_motion_blur_frag_glsl[]; +extern char datatoc_effect_bloom_frag_glsl[]; extern char datatoc_tonemap_frag_glsl[]; void EEVEE_effects_init(EEVEE_Data *vedata) @@ -70,18 +79,37 @@ void EEVEE_effects_init(EEVEE_Data *vedata) e_data.motion_blur_sh = DRW_shader_create_fullscreen(datatoc_effect_motion_blur_frag_glsl, NULL); } + if (!e_data.bloom_blit_sh[0]) { + e_data.bloom_blit_sh[0] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_BLIT\n"); + e_data.bloom_blit_sh[1] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_BLIT\n" + "#define HIGH_QUALITY\n"); + + e_data.bloom_downsample_sh[0] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_DOWNSAMPLE\n"); + e_data.bloom_downsample_sh[1] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_DOWNSAMPLE\n" + "#define HIGH_QUALITY\n"); + + e_data.bloom_upsample_sh[0] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_UPSAMPLE\n"); + e_data.bloom_upsample_sh[1] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_UPSAMPLE\n" + "#define HIGH_QUALITY\n"); + + e_data.bloom_resolve_sh[0] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_RESOLVE\n"); + e_data.bloom_resolve_sh[1] = DRW_shader_create_fullscreen(datatoc_effect_bloom_frag_glsl, "#define STEP_RESOLVE\n" + "#define HIGH_QUALITY\n"); + } + 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"); + stl->effects->enabled_effects = 0; } +#if ENABLE_EFFECT_MOTION_BLUR { /* 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; @@ -124,18 +152,101 @@ void EEVEE_effects_init(EEVEE_Data *vedata) 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 } +#endif /* ENABLE_EFFECT_MOTION_BLUR */ + + { + /* Bloom */ + EEVEE_EffectsInfo *effects = stl->effects; + int blitsize[2], texsize[2]; + + /* Blit Buffer */ + effects->source_texel_size[0] = 1.0f / viewport_size[0]; + effects->source_texel_size[1] = 1.0f / viewport_size[1]; + + blitsize[0] = (int)viewport_size[0]; + blitsize[1] = (int)viewport_size[1]; + + effects->blit_texel_size[0] = 1.0f / (float)blitsize[0]; + effects->blit_texel_size[1] = 1.0f / (float)blitsize[1]; + + DRWFboTexture tex_blit = {&txl->bloom_blit, DRW_BUF_RGBA_16, DRW_TEX_FILTER}; + DRW_framebuffer_init(&fbl->bloom_blit_fb, + (int)blitsize[0], (int)blitsize[1], + &tex_blit, 1); + + /* Parameters */ + /* TODO UI Options */ + float threshold = 0.8f; + float knee = 0.5f; + float intensity = 0.8f; + float radius = 8.5f; + + /* determine the iteration count */ + const float minDim = (float)MIN2(blitsize[0], blitsize[1]); + const float maxIter = (radius - 8.0f) + log(minDim) / log(2); + const int maxIterInt = effects->bloom_iteration_ct = (int)maxIter; + + CLAMP(effects->bloom_iteration_ct, 1, MAX_BLOOM_STEP); + + effects->bloom_sample_scale = 0.5f + maxIter - (float)maxIterInt; + effects->bloom_curve_threshold[0] = threshold - knee; + effects->bloom_curve_threshold[1] = knee * 2.0f; + effects->bloom_curve_threshold[2] = 0.25f / knee; + effects->bloom_curve_threshold[3] = threshold; + effects->bloom_intensity = intensity; + + /* Downsample buffers */ + copy_v2_v2_int(texsize, blitsize); + for (int i = 0; i < effects->bloom_iteration_ct; ++i) { + texsize[0] /= 2; texsize[1] /= 2; + texsize[0] = MAX2(texsize[0], 2); + texsize[1] = MAX2(texsize[1], 2); + + effects->downsamp_texel_size[i][0] = 1.0f / (float)texsize[0]; + effects->downsamp_texel_size[i][1] = 1.0f / (float)texsize[1]; + + DRWFboTexture tex_bloom = {&txl->bloom_downsample[i], DRW_BUF_RGBA_16, DRW_TEX_FILTER}; + DRW_framebuffer_init(&fbl->bloom_down_fb[i], + (int)texsize[0], (int)texsize[1], + &tex_bloom, 1); + } + + /* Upsample buffers */ + copy_v2_v2_int(texsize, blitsize); + for (int i = 0; i < effects->bloom_iteration_ct - 1; ++i) { + texsize[0] /= 2; texsize[1] /= 2; + texsize[0] = MAX2(texsize[0], 2); + texsize[1] = MAX2(texsize[1], 2); + + DRWFboTexture tex_bloom = {&txl->bloom_upsample[i], DRW_BUF_RGBA_16, DRW_TEX_FILTER}; + DRW_framebuffer_init(&fbl->bloom_accum_fb[i], + (int)texsize[0], (int)texsize[1], + &tex_bloom, 1); + } + + effects->enabled_effects |= EFFECT_BLOOM; + } +} + +static DRWShadingGroup *eevee_create_bloom_pass(const char *name, EEVEE_EffectsInfo *effects, struct GPUShader *sh, DRWPass **pass, bool upsample) +{ + struct Batch *quad = DRW_cache_fullscreen_quad_get(); + + *pass = DRW_pass_create(name, DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, *pass); + DRW_shgroup_call_add(grp, quad, NULL); + DRW_shgroup_uniform_buffer(grp, "sourceBuffer", &effects->unf_source_buffer, 0); + DRW_shgroup_uniform_vec2(grp, "sourceBufferTexelSize", effects->unf_source_texel_size, 1); + if (upsample) { + DRW_shgroup_uniform_buffer(grp, "baseBuffer", &effects->unf_base_buffer, 1); + DRW_shgroup_uniform_float(grp, "sampleScale", &effects->bloom_sample_scale, 1); + } + + return grp; } void EEVEE_effects_cache_init(EEVEE_Data *vedata) @@ -160,20 +271,81 @@ void EEVEE_effects_cache_init(EEVEE_Data *vedata) DRW_shgroup_call_add(grp, quad, NULL); } + { + /** Bloom algorithm + * + * Overview : + * - Downsample the color buffer doing a small blur during each step. + * - Accumulate bloom color using previously downsampled color buffers + * and do an upsample blur for each new accumulated layer. + * - Finally add accumulation buffer onto the source color buffer. + * + * [1/1] is original copy resolution (can be half or quater res for performance) + * + * [DOWNSAMPLE CHAIN] [UPSAMPLE CHAIN] + * + * Source Color ── [Blit] ──> Bright Color Extract [1/1] Final Color + * | Λ + * [Downsample First] Source Color ─> + [Resolve] + * v | + * Color Downsampled [1/2] ────────────> + Accumulation Buffer [1/2] + * | Λ + * ─── ─── + * Repeat Repeat + * ─── ─── + * v | + * Color Downsampled [1/N-1] ──────────> + Accumulation Buffer [1/N-1] + * | Λ + * [Downsample] [Upsample] + * v | + * Color Downsampled [1/N] ─────────────────────────┘ + **/ + DRWShadingGroup *grp; + const bool use_highres = true; + const bool use_antiflicker = true; + eevee_create_bloom_pass("Bloom Downsample First", effects, e_data.bloom_downsample_sh[use_antiflicker], &psl->bloom_downsample_first, false); + eevee_create_bloom_pass("Bloom Downsample", effects, e_data.bloom_downsample_sh[0], &psl->bloom_downsample, false); + eevee_create_bloom_pass("Bloom Upsample", effects, e_data.bloom_upsample_sh[use_highres], &psl->bloom_upsample, true); + grp = eevee_create_bloom_pass("Bloom Blit", effects, e_data.bloom_blit_sh[use_antiflicker], &psl->bloom_blit, false); + DRW_shgroup_uniform_vec4(grp, "curveThreshold", effects->bloom_curve_threshold, 1); + grp = eevee_create_bloom_pass("Bloom Resolve", effects, e_data.bloom_resolve_sh[use_highres], &psl->bloom_resolve, true); + DRW_shgroup_uniform_float(grp, "bloomIntensity", &effects->bloom_intensity, 1); + } + { /* 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_uniform_buffer(grp, "hdrColorBuf", &effects->source_buffer, 0); DRW_shgroup_call_add(grp, quad, NULL); } } +/* Ping pong between 2 buffers */ +static void eevee_effect_framebuffer_bind(EEVEE_Data *vedata) +{ + EEVEE_TextureList *txl = vedata->txl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_EffectsInfo *effects = vedata->stl->effects; + + DRW_framebuffer_bind(effects->target_buffer); + + if (effects->source_buffer == txl->color) { + effects->source_buffer = txl->color_post; + effects->target_buffer = fbl->main; + } + else { + effects->source_buffer = txl->color; + effects->target_buffer = fbl->effect_fb; + } +} + void EEVEE_draw_effects(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; @@ -182,18 +354,75 @@ void EEVEE_draw_effects(EEVEE_Data *vedata) DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + /* Init pointers */ + effects->source_buffer = txl->color; /* latest updated texture */ + effects->target_buffer = fbl->effect_fb; /* next target to render to */ + + /* Motion Blur */ if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) { - /* Motion Blur */ - DRW_framebuffer_bind(fbl->effect_fb); + eevee_effect_framebuffer_bind(vedata); DRW_draw_pass(psl->motion_blur); } + /* Bloom */ + if ((effects->enabled_effects & EFFECT_BLOOM) != 0) { + struct GPUTexture *last; + + /* Extract bright pixels */ + copy_v2_v2(effects->unf_source_texel_size, effects->source_texel_size); + effects->unf_source_buffer = effects->source_buffer; + + DRW_framebuffer_bind(fbl->bloom_blit_fb); + DRW_draw_pass(psl->bloom_blit); + + /* Downsample */ + copy_v2_v2(effects->unf_source_texel_size, effects->blit_texel_size); + effects->unf_source_buffer = txl->bloom_blit; + + DRW_framebuffer_bind(fbl->bloom_down_fb[0]); + DRW_draw_pass(psl->bloom_downsample_first); + + last = txl->bloom_downsample[0]; + + for (int i = 1; i < effects->bloom_iteration_ct; ++i) { + copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[i-1]); + effects->unf_source_buffer = last; + + DRW_framebuffer_bind(fbl->bloom_down_fb[i]); + DRW_draw_pass(psl->bloom_downsample); + + /* Used in next loop */ + last = txl->bloom_downsample[i]; + } + + /* Upsample and accumulate */ + for (int i = effects->bloom_iteration_ct - 2; i >= 0; --i) { + copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[i]); + effects->unf_source_buffer = txl->bloom_downsample[i]; + effects->unf_base_buffer = last; + + DRW_framebuffer_bind(fbl->bloom_accum_fb[i]); + DRW_draw_pass(psl->bloom_upsample); + + last = txl->bloom_upsample[i]; + } + + /* Resolve */ + copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[0]); + effects->unf_source_buffer = last; + effects->unf_base_buffer = effects->source_buffer; + + eevee_effect_framebuffer_bind(vedata); + DRW_draw_pass(psl->bloom_resolve); + } + /* 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 */ + /* TODO : use OCIO */ DRW_draw_pass(psl->tonemap); } @@ -201,4 +430,13 @@ void EEVEE_effects_free(void) { DRW_SHADER_FREE_SAFE(e_data.tonemap_sh); DRW_SHADER_FREE_SAFE(e_data.motion_blur_sh); + + DRW_SHADER_FREE_SAFE(e_data.bloom_blit_sh[0]); + DRW_SHADER_FREE_SAFE(e_data.bloom_downsample_sh[0]); + DRW_SHADER_FREE_SAFE(e_data.bloom_upsample_sh[0]); + DRW_SHADER_FREE_SAFE(e_data.bloom_resolve_sh[0]); + DRW_SHADER_FREE_SAFE(e_data.bloom_blit_sh[1]); + DRW_SHADER_FREE_SAFE(e_data.bloom_downsample_sh[1]); + DRW_SHADER_FREE_SAFE(e_data.bloom_upsample_sh[1]); + DRW_SHADER_FREE_SAFE(e_data.bloom_resolve_sh[1]); } \ No newline at end of file diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 4d25dab7343..517926554f9 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -31,6 +31,7 @@ struct Object; #define MAX_SHADOW_MAP 64 #define MAX_SHADOW_CASCADE 8 #define MAX_CASCADE_NUM 4 +#define MAX_BLOOM_STEP 16 typedef struct EEVEE_PassList { /* Shadows */ @@ -45,6 +46,11 @@ typedef struct EEVEE_PassList { /* Effects */ struct DRWPass *motion_blur; + struct DRWPass *bloom_blit; + struct DRWPass *bloom_downsample_first; + struct DRWPass *bloom_downsample; + struct DRWPass *bloom_upsample; + struct DRWPass *bloom_resolve; struct DRWPass *tonemap; struct DRWPass *depth_pass; @@ -65,6 +71,9 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *probe_sh_fb; /* Effects */ struct GPUFrameBuffer *effect_fb; /* HDR */ + struct GPUFrameBuffer *bloom_blit_fb; /* HDR */ + struct GPUFrameBuffer *bloom_down_fb[MAX_BLOOM_STEP]; /* HDR */ + struct GPUFrameBuffer *bloom_accum_fb[MAX_BLOOM_STEP-1]; /* HDR */ struct GPUFrameBuffer *main; /* HDR */ } EEVEE_FramebufferList; @@ -79,9 +88,13 @@ typedef struct EEVEE_TextureList { struct GPUTexture *probe_depth_rt; struct GPUTexture *probe_pool; /* R11_G11_B10 */ struct GPUTexture *probe_sh; /* R16_G16_B16 */ + /* Effects */ + struct GPUTexture *color_post; /* R16_G16_B16 */ + struct GPUTexture *bloom_blit; /* R16_G16_B16 */ + struct GPUTexture *bloom_downsample[MAX_BLOOM_STEP]; /* R16_G16_B16 */ + struct GPUTexture *bloom_upsample[MAX_BLOOM_STEP-1]; /* R16_G16_B16 */ struct GPUTexture *color; /* R16_G16_B16 */ - struct GPUTexture *color_post; /* R16_G16_B16 */ } EEVEE_TextureList; typedef struct EEVEE_StorageList { @@ -169,20 +182,34 @@ typedef struct EEVEE_ProbesInfo { /* ************ EFFECTS DATA ************* */ typedef struct EEVEE_EffectsInfo { + int enabled_effects; + + /* Motion Blur */ 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; + /* Bloom */ + int bloom_iteration_ct; + float source_texel_size[2]; + float blit_texel_size[2]; + float downsamp_texel_size[MAX_BLOOM_STEP][2]; + float bloom_intensity; + float bloom_sample_scale; + float bloom_curve_threshold[4]; + float unf_source_texel_size[2]; + struct GPUTexture *unf_source_buffer; /* pointer copy */ + struct GPUTexture *unf_base_buffer; /* pointer copy */ - /* 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; + /* Not alloced, just a copy of a *GPUtexture in EEVEE_TextureList. */ + struct GPUTexture *source_buffer; /* latest updated texture */ + struct GPUFrameBuffer *target_buffer; /* next target to render to */ } EEVEE_EffectsInfo; enum { - EFFECT_MOTION_BLUR = (1 << 0), + EFFECT_MOTION_BLUR = (1 << 0), + EFFECT_BLOOM = (1 << 1), }; /* *********************************** */ diff --git a/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl new file mode 100644 index 00000000000..52b1cc406d2 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl @@ -0,0 +1,207 @@ +/* Original implementation by Keijiro Takahashi + * Blender integration by Clément Foucault + * + * Original License : + * + * Kino/Bloom v2 - Bloom filter for Unity + * + * Copyright (C) 2015, 2016 Keijiro Takahashi + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + **/ + +uniform sampler2D sourceBuffer; /* Buffer to filter */ +uniform vec2 sourceBufferTexelSize; + +/* Step Blit */ +uniform vec4 curveThreshold; + +/* Step Upsample */ +uniform sampler2D baseBuffer; /* Previous accumulation buffer */ +uniform vec2 baseBufferTexelSize; +uniform float sampleScale; + +/* Step Resolve */ +uniform float bloomIntensity; + +in vec4 uvcoordsvar; + +out vec4 FragColor; + +/* -------------- Utils ------------- */ + +float brightness(vec3 c) +{ + return max(max(c.r, c.g), c.b); +} + +/* 3-tap median filter */ +vec3 median(vec3 a, vec3 b, vec3 c) +{ + return a + b + c - min(min(a, b), c) - max(max(a, b), c); +} + +/* ------------- Filters ------------ */ + +vec3 downsample_filter_high(sampler2D tex, vec2 uv, vec2 texelSize) +{ + /* Downsample with a 4x4 box filter + anti-flicker filter */ + vec4 d = texelSize.xyxy * vec4(-1, -1, +1, +1); + + vec3 s1 = texture(tex, uv + d.xy).rgb; + vec3 s2 = texture(tex, uv + d.zy).rgb; + vec3 s3 = texture(tex, uv + d.xw).rgb; + vec3 s4 = texture(tex, uv + d.zw).rgb; + + /* Karis's luma weighted average (using brightness instead of luma) */ + float s1w = 1.0 / (brightness(s1) + 1.0); + float s2w = 1.0 / (brightness(s2) + 1.0); + float s3w = 1.0 / (brightness(s3) + 1.0); + float s4w = 1.0 / (brightness(s4) + 1.0); + float one_div_wsum = 1.0 / (s1w + s2w + s3w + s4w); + + return (s1 * s1w + s2 * s2w + s3 * s3w + s4 * s4w) * one_div_wsum; +} + +vec3 downsample_filter(sampler2D tex, vec2 uv, vec2 texelSize) +{ + /* Downsample with a 4x4 box filter */ + vec4 d = texelSize.xyxy * vec4(-1, -1, +1, +1); + + vec3 s; + s = texture(tex, uv + d.xy).rgb; + s += texture(tex, uv + d.zy).rgb; + s += texture(tex, uv + d.xw).rgb; + s += texture(tex, uv + d.zw).rgb; + + return s * (1.0 / 4); +} + +vec3 upsample_filter_high(sampler2D tex, vec2 uv, vec2 texelSize) +{ + /* 9-tap bilinear upsampler (tent filter) */ + vec4 d = texelSize.xyxy * vec4(1, 1, -1, 0) * sampleScale; + + vec3 s; + s = texture(tex, uv - d.xy).rgb; + s += texture(tex, uv - d.wy).rgb * 2; + s += texture(tex, uv - d.zy).rgb; + + s += texture(tex, uv + d.zw).rgb * 2; + s += texture(tex, uv ).rgb * 4; + s += texture(tex, uv + d.xw).rgb * 2; + + s += texture(tex, uv + d.zy).rgb; + s += texture(tex, uv + d.wy).rgb * 2; + s += texture(tex, uv + d.xy).rgb; + + return s * (1.0 / 16.0); +} + +vec3 upsample_filter(sampler2D tex, vec2 uv, vec2 texelSize) +{ + /* 4-tap bilinear upsampler */ + vec4 d = texelSize.xyxy * vec4(-1, -1, +1, +1) * (sampleScale * 0.5); + + vec3 s; + s = texture(tex, uv + d.xy).rgb; + s += texture(tex, uv + d.zy).rgb; + s += texture(tex, uv + d.xw).rgb; + s += texture(tex, uv + d.zw).rgb; + + return s * (1.0 / 4.0); +} + +/* ----------- Steps ----------- */ + +vec4 step_blit(void) +{ + vec2 uv = uvcoordsvar.xy + sourceBufferTexelSize.xy * 0.5; + +#ifdef HIGH_QUALITY /* Anti flicker */ + vec3 d = sourceBufferTexelSize.xyx * vec3(1, 1, 0); + vec3 s0 = texture(sourceBuffer, uvcoordsvar.xy).rgb; + vec3 s1 = texture(sourceBuffer, uvcoordsvar.xy - d.xz).rgb; + vec3 s2 = texture(sourceBuffer, uvcoordsvar.xy + d.xz).rgb; + vec3 s3 = texture(sourceBuffer, uvcoordsvar.xy - d.zy).rgb; + vec3 s4 = texture(sourceBuffer, uvcoordsvar.xy + d.zy).rgb; + vec3 m = median(median(s0.rgb, s1, s2), s3, s4); +#else + vec3 s0 = texture(sourceBuffer, uvcoordsvar.xy).rgb; + vec3 m = s0.rgb; +#endif + + /* Pixel brightness */ + float br = brightness(m); + + /* Under-threshold part: quadratic curve */ + float rq = clamp(br - curveThreshold.x, 0, curveThreshold.y); + rq = curveThreshold.z * rq * rq; + + /* Combine and apply the brightness response curve. */ + m *= max(rq, br - curveThreshold.w) / max(br, 1e-5); + + return vec4(m, 1.0); +} + +vec4 step_downsample(void) +{ +#ifdef HIGH_QUALITY /* Anti flicker */ + vec3 sample = downsample_filter_high(sourceBuffer, uvcoordsvar.xy, sourceBufferTexelSize); +#else + vec3 sample = downsample_filter(sourceBuffer, uvcoordsvar.xy, sourceBufferTexelSize); +#endif + return vec4(sample, 1.0); +} + +vec4 step_upsample(void) +{ +#ifdef HIGH_QUALITY + vec3 blur = upsample_filter_high(sourceBuffer, uvcoordsvar.xy, sourceBufferTexelSize); +#else + vec3 blur = upsample_filter(sourceBuffer, uvcoordsvar.xy, sourceBufferTexelSize); +#endif + vec3 base = texture(baseBuffer, uvcoordsvar.xy).rgb; + return vec4(base + blur, 1.0); +} + +vec4 step_resolve(void) +{ +#ifdef HIGH_QUALITY + vec3 blur = upsample_filter_high(sourceBuffer, uvcoordsvar.xy, sourceBufferTexelSize); +#else + vec3 blur = upsample_filter(sourceBuffer, uvcoordsvar.xy, sourceBufferTexelSize); +#endif + vec4 base = texture(baseBuffer, uvcoordsvar.xy); + vec3 cout = base.rgb + blur * bloomIntensity; + return vec4(cout, base.a); +} + +void main(void) +{ +#if defined(STEP_BLIT) + FragColor = step_blit(); +#elif defined(STEP_DOWNSAMPLE) + FragColor = step_downsample(); +#elif defined(STEP_UPSAMPLE) + FragColor = step_upsample(); +#elif defined(STEP_RESOLVE) + FragColor = step_resolve(); +#endif +} \ No newline at end of file diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 52bdf05e26a..253b3e680c9 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1444,7 +1444,6 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) tex = *((GPUTexture **)uni->value); GPU_texture_bind(tex, uni->bindloc); GPU_texture_compare_mode(tex, false); - GPU_texture_filter_mode(tex, false); bound_tex = MEM_callocN(sizeof(DRWBoundTexture), "DRWBoundTexture"); bound_tex->tex = tex;