Eevee: Add Bloom post process.
Based on Kino/Bloom v2 - Bloom filter for Unity MIT license.
This commit is contained in:
parent
29c5692eba
commit
0aa2a662b9
|
@ -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)
|
||||
|
|
|
@ -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]);
|
||||
}
|
|
@ -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),
|
||||
};
|
||||
|
||||
/* *********************************** */
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue