Eevee: Add Bloom post process.

Based on Kino/Bloom v2 - Bloom filter for Unity
MIT license.
This commit is contained in:
Clément Foucault 2017-05-07 14:27:43 +02:00
parent 29c5692eba
commit 0aa2a662b9
5 changed files with 492 additions and 20 deletions

View File

@ -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)

View File

@ -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]);
}

View File

@ -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),
};
/* *********************************** */

View File

@ -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
}

View File

@ -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;