EEVEE: GLSL Renderpasses

Most of the renderpasses in EEVEE used post-processing on the CPU. For
final image rendering this is sufficient, but when we want to display
the data to the user we don't want to transfer to the CPU to do post
processing to then upload it back to the GPU to display the result.

This patch moves the renderpass postprocessing to a GLSL shader.

This is the first step to do, before we will enable the renderpasses in the viewport.

Reviewed By: fclem

Differential Revision: https://developer.blender.org/D6206
This commit is contained in:
Jeroen Bakker 2019-11-07 13:14:15 +01:00
parent 17b63db4e2
commit 9d7f65630b
6 changed files with 336 additions and 193 deletions

View File

@ -102,6 +102,7 @@ set(SRC
engines/eevee/eevee_motion_blur.c
engines/eevee/eevee_occlusion.c
engines/eevee/eevee_render.c
engines/eevee/eevee_renderpasses.c
engines/eevee/eevee_sampling.c
engines/eevee/eevee_screen_raytrace.c
engines/eevee/eevee_shaders.c
@ -221,6 +222,7 @@ data_to_c_simple(engines/eevee/shaders/irradiance_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/octahedron_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/bsdf_sampling_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/raytrace_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/renderpass_postprocess_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/ltc_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/ssr_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/update_noise_frag.glsl SRC)

View File

@ -483,6 +483,7 @@ static void eevee_engine_free(void)
EEVEE_screen_raytrace_free();
EEVEE_subsurface_free();
EEVEE_volumes_free();
EEVEE_renderpasses_free();
}
static const DrawEngineDataSize eevee_data_size = DRW_VIEWPORT_DATA_SIZE(EEVEE_Data);

View File

@ -271,6 +271,7 @@ typedef struct EEVEE_PassList {
struct DRWPass *update_noise_pass;
struct DRWPass *lookdev_glossy_pass;
struct DRWPass *lookdev_diffuse_pass;
struct DRWPass *renderpass_pass;
} EEVEE_PassList;
typedef struct EEVEE_FramebufferList {
@ -295,6 +296,7 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *screen_tracing_fb;
struct GPUFrameBuffer *refract_fb;
struct GPUFrameBuffer *mist_accum_fb;
struct GPUFrameBuffer *renderpass_fb;
struct GPUFrameBuffer *ao_accum_fb;
struct GPUFrameBuffer *velocity_resolve_fb;
@ -341,6 +343,8 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *maxzbuffer;
struct GPUTexture *renderpass;
struct GPUTexture *color; /* R16_G16_B16 */
struct GPUTexture *color_double_buffer;
struct GPUTexture *depth_double_buffer;
@ -799,6 +803,10 @@ typedef struct EEVEE_PrivateData {
float studiolight_glossy_clamp;
float studiolight_filter_quality;
/* Renderpasses */
/* Bitmask containing the active render_passes */
eScenePassType render_passes;
/** For rendering shadows. */
struct DRWView *cube_views[6];
/** For rendering probes. */
@ -1039,6 +1047,16 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_mist_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_mist_free(void);
/* eevee_renderpasses.c */
void EEVEE_renderpasses_init(EEVEE_Data *vedata);
void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
uint tot_samples);
void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
eScenePassType renderpass_type);
void EEVEE_renderpasses_free(void);
/* eevee_temporal_sampling.c */
void EEVEE_temporal_sampling_reset(EEVEE_Data *vedata);
int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);

View File

@ -130,7 +130,9 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
DRW_view_default_set(view);
DRW_view_set_active(view);
/* EEVEE_effects_init needs to go first for TAA */
/* `EEVEE_renderpasses_init` will set the active render passes used by `EEVEE_effects_init`.
* `EEVEE_effects_init` needs to go second for TAA. */
EEVEE_renderpasses_init(vedata);
EEVEE_effects_init(sldata, vedata, ob_camera_eval, false);
EEVEE_materials_init(sldata, stl, fbl);
EEVEE_shadows_init(sldata);
@ -202,79 +204,60 @@ void EEVEE_render_cache(void *vedata,
}
}
static void eevee_render_color_result(RenderLayer *rl,
const char *viewname,
const rcti *rect,
const char *render_pass_name,
int num_channels,
GPUFrameBuffer *framebuffer,
EEVEE_Data *vedata)
{
RenderPass *rp = RE_pass_find_by_name(rl, render_pass_name, viewname);
GPU_framebuffer_bind(framebuffer);
GPU_framebuffer_read_color(framebuffer,
vedata->stl->g_data->overscan_pixels + rect->xmin,
vedata->stl->g_data->overscan_pixels + rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
num_channels,
0,
rp->rect);
}
static void eevee_render_result_combined(RenderLayer *rl,
const char *viewname,
const rcti *rect,
EEVEE_Data *vedata,
EEVEE_ViewLayerData *UNUSED(sldata))
{
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
GPU_framebuffer_bind(vedata->stl->effects->final_fb);
GPU_framebuffer_read_color(vedata->stl->effects->final_fb,
vedata->stl->g_data->overscan_pixels + rect->xmin,
vedata->stl->g_data->overscan_pixels + rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
4,
0,
rp->rect);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_COMBINED, 4, vedata->stl->effects->final_fb, vedata);
}
static void eevee_render_result_subsurface(RenderLayer *rl,
const char *viewname,
const rcti *rect,
EEVEE_Data *vedata,
EEVEE_ViewLayerData *UNUSED(sldata),
int render_samples)
EEVEE_ViewLayerData *sldata)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
if (vedata->fbl->sss_accum_fb == NULL) {
/* SSS is not enabled. */
return;
}
if ((view_layer->passflag & SCE_PASS_SUBSURFACE_COLOR) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_SUBSURFACE_COLOR, viewname);
GPU_framebuffer_bind(vedata->fbl->sss_accum_fb);
GPU_framebuffer_read_color(vedata->fbl->sss_accum_fb,
vedata->stl->g_data->overscan_pixels + rect->xmin,
vedata->stl->g_data->overscan_pixels + rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
3,
1,
rp->rect);
/* This is the accumulated color. Divide by the number of samples. */
for (int i = 0; i < rp->rectx * rp->recty * 3; i++) {
rp->rect[i] /= (float)render_samples;
}
if ((vedata->stl->g_data->render_passes & SCE_PASS_SUBSURFACE_COLOR) != 0) {
EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_SUBSURFACE_COLOR);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_SUBSURFACE_COLOR, 3, vedata->fbl->renderpass_fb, vedata);
}
if ((view_layer->passflag & SCE_PASS_SUBSURFACE_DIRECT) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_SUBSURFACE_DIRECT, viewname);
GPU_framebuffer_bind(vedata->fbl->sss_accum_fb);
GPU_framebuffer_read_color(vedata->fbl->sss_accum_fb,
vedata->stl->g_data->overscan_pixels + rect->xmin,
vedata->stl->g_data->overscan_pixels + rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
3,
0,
rp->rect);
/* This is the accumulated color. Divide by the number of samples. */
for (int i = 0; i < rp->rectx * rp->recty * 3; i++) {
rp->rect[i] /= (float)render_samples;
}
if ((vedata->stl->g_data->render_passes & SCE_PASS_SUBSURFACE_DIRECT) != 0) {
EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_SUBSURFACE_DIRECT);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_SUBSURFACE_DIRECT, 3, vedata->fbl->renderpass_fb, vedata);
}
if ((view_layer->passflag & SCE_PASS_SUBSURFACE_INDIRECT) != 0) {
if ((vedata->stl->g_data->render_passes & SCE_PASS_SUBSURFACE_INDIRECT) != 0) {
/* Do nothing as all the lighting is in the direct pass.
* TODO : Separate Direct from indirect lighting. */
}
@ -284,54 +267,19 @@ static void eevee_render_result_normal(RenderLayer *rl,
const char *viewname,
const rcti *rect,
EEVEE_Data *vedata,
EEVEE_ViewLayerData *UNUSED(sldata))
EEVEE_ViewLayerData *sldata)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_PrivateData *g_data = stl->g_data;
const int current_sample = vedata->stl->effects->taa_current_sample;
/* Only read the center texel. */
if (stl->effects->taa_current_sample > 1) {
if (current_sample > 1) {
return;
}
if ((view_layer->passflag & SCE_PASS_NORMAL) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_NORMAL, viewname);
GPU_framebuffer_bind(vedata->fbl->main_fb);
GPU_framebuffer_read_color(vedata->fbl->main_fb,
g_data->overscan_pixels + rect->xmin,
g_data->overscan_pixels + rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
3,
1,
rp->rect);
float viewinv[4][4];
DRW_view_viewmat_get(NULL, viewinv, true);
/* Convert Eevee encoded normals to Blender normals. */
for (int i = 0; i < rp->rectx * rp->recty * 3; i += 3) {
if (rp->rect[i] == 0.0f && rp->rect[i + 1] == 0.0f) {
/* If normal is not correct then do not produce NANs. */
continue;
}
float fenc[2];
fenc[0] = rp->rect[i + 0] * 4.0f - 2.0f;
fenc[1] = rp->rect[i + 1] * 4.0f - 2.0f;
float f = dot_v2v2(fenc, fenc);
float g = sqrtf(1.0f - f / 4.0f);
rp->rect[i + 0] = fenc[0] * g;
rp->rect[i + 1] = fenc[1] * g;
rp->rect[i + 2] = 1.0f - f / 2.0f;
mul_mat3_m4_v3(viewinv, &rp->rect[i]);
}
if ((vedata->stl->g_data->render_passes & SCE_PASS_NORMAL) != 0) {
EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_NORMAL);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_NORMAL, 3, vedata->fbl->renderpass_fb, vedata);
}
}
@ -341,49 +289,17 @@ static void eevee_render_result_z(RenderLayer *rl,
EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
EEVEE_CommonUniformBuffer *common_data = &sldata->common_data;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_PrivateData *g_data = stl->g_data;
const int current_sample = vedata->stl->effects->taa_current_sample;
/* Only read the center texel. */
if (stl->effects->taa_current_sample > 1) {
if (current_sample > 1) {
return;
}
if ((view_layer->passflag & SCE_PASS_Z) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname);
GPU_framebuffer_bind(vedata->fbl->main_fb);
GPU_framebuffer_read_depth(vedata->fbl->main_fb,
g_data->overscan_pixels + rect->xmin,
g_data->overscan_pixels + rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
rp->rect);
bool is_persp = DRW_view_is_persp_get(NULL);
float winmat[4][4];
DRW_view_winmat_get(NULL, winmat, false);
/* Convert ogl depth [0..1] to view Z [near..far] */
for (int i = 0; i < rp->rectx * rp->recty; i++) {
if (rp->rect[i] == 1.0f) {
rp->rect[i] = 1e10f; /* Background */
}
else {
if (is_persp) {
rp->rect[i] = rp->rect[i] * 2.0f - 1.0f;
rp->rect[i] = winmat[3][2] / (rp->rect[i] + winmat[2][2]);
}
else {
rp->rect[i] = -common_data->view_vecs[0][2] +
rp->rect[i] * -common_data->view_vecs[1][2];
}
}
}
if ((vedata->stl->g_data->render_passes & SCE_PASS_Z) != 0) {
EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_Z);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_Z, 1, vedata->fbl->renderpass_fb, vedata);
}
}
@ -391,29 +307,12 @@ static void eevee_render_result_mist(RenderLayer *rl,
const char *viewname,
const rcti *rect,
EEVEE_Data *vedata,
EEVEE_ViewLayerData *UNUSED(sldata),
int render_samples)
EEVEE_ViewLayerData *sldata)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
if ((view_layer->passflag & SCE_PASS_MIST) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_MIST, viewname);
GPU_framebuffer_bind(vedata->fbl->mist_accum_fb);
GPU_framebuffer_read_color(vedata->fbl->mist_accum_fb,
vedata->stl->g_data->overscan_pixels + rect->xmin,
vedata->stl->g_data->overscan_pixels + rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
1,
0,
rp->rect);
/* This is the accumulated color. Divide by the number of samples. */
for (int i = 0; i < rp->rectx * rp->recty; i++) {
rp->rect[i] /= (float)render_samples;
}
if ((vedata->stl->g_data->render_passes & SCE_PASS_MIST) != 0) {
EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_MIST);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_MIST, 1, vedata->fbl->renderpass_fb, vedata);
}
}
@ -421,35 +320,17 @@ static void eevee_render_result_occlusion(RenderLayer *rl,
const char *viewname,
const rcti *rect,
EEVEE_Data *vedata,
EEVEE_ViewLayerData *UNUSED(sldata),
int render_samples)
EEVEE_ViewLayerData *sldata)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
if (vedata->fbl->ao_accum_fb == NULL) {
/* AO is not enabled. */
return;
}
if ((view_layer->passflag & SCE_PASS_AO) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_AO, viewname);
GPU_framebuffer_bind(vedata->fbl->ao_accum_fb);
GPU_framebuffer_read_color(vedata->fbl->ao_accum_fb,
vedata->stl->g_data->overscan_pixels + rect->xmin,
vedata->stl->g_data->overscan_pixels + rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
3,
0,
rp->rect);
/* This is the accumulated color. Divide by the number of samples. */
for (int i = 0; i < rp->rectx * rp->recty * 3; i += 3) {
rp->rect[i] = rp->rect[i + 1] = rp->rect[i + 2] = min_ff(
1.0f, rp->rect[i] / (float)render_samples);
}
if ((vedata->stl->g_data->render_passes & SCE_PASS_AO) != 0) {
EEVEE_renderpasses_postprocess(sldata, vedata, SCE_PASS_AO);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_AO, 3, vedata->fbl->renderpass_fb, vedata);
}
}
@ -488,7 +369,6 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
{
const DRWContextState *draw_ctx = DRW_context_state_get();
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
ViewLayer *view_layer = draw_ctx->view_layer;
const char *viewname = RE_GetActiveRenderView(engine->re);
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
@ -525,18 +405,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
tot_sample += 1;
}
if ((view_layer->passflag & (SCE_PASS_SUBSURFACE_COLOR | SCE_PASS_SUBSURFACE_DIRECT |
SCE_PASS_SUBSURFACE_INDIRECT)) != 0) {
EEVEE_subsurface_output_init(sldata, vedata, tot_sample);
}
if ((view_layer->passflag & SCE_PASS_MIST) != 0) {
EEVEE_mist_output_init(sldata, vedata);
}
if ((view_layer->passflag & SCE_PASS_AO) != 0) {
EEVEE_occlusion_output_init(sldata, vedata, tot_sample);
}
EEVEE_renderpasses_output_init(sldata, vedata, tot_sample);
if (RE_engine_test_break(engine)) {
return;
@ -644,9 +513,9 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
}
eevee_render_result_combined(rl, viewname, rect, vedata, sldata);
eevee_render_result_subsurface(rl, viewname, rect, vedata, sldata, render_samples);
eevee_render_result_mist(rl, viewname, rect, vedata, sldata, render_samples);
eevee_render_result_occlusion(rl, viewname, rect, vedata, sldata, render_samples);
eevee_render_result_subsurface(rl, viewname, rect, vedata, sldata);
eevee_render_result_mist(rl, viewname, rect, vedata, sldata);
eevee_render_result_occlusion(rl, viewname, rect, vedata, sldata);
/* Restore original viewport size. */
DRW_render_viewport_size_set((int[2]){g_data->size_orig[0], g_data->size_orig[1]});

View File

@ -0,0 +1,190 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright 2019, Blender Foundation.
*/
/** \file
* \ingroup draw_engine
*/
#include "DRW_engine.h"
#include "DRW_render.h"
#include "BLI_string_utils.h"
#include "eevee_private.h"
extern char datatoc_common_view_lib_glsl[];
extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_renderpass_postprocess_frag_glsl[];
static struct {
struct GPUShader *postprocess_sh;
} e_data = {NULL}; /* Engine data */
/* bitmask containing all renderpasses that need post-processing */
#define EEVEE_RENDERPASSES_WITH_POST_PROCESSING \
(SCE_PASS_Z | SCE_PASS_MIST | SCE_PASS_NORMAL | SCE_PASS_AO | SCE_PASS_SUBSURFACE_COLOR | \
SCE_PASS_SUBSURFACE_DIRECT)
#define EEVEE_RENDERPASSES_SUBSURFACE \
(SCE_PASS_SUBSURFACE_COLOR | SCE_PASS_SUBSURFACE_DIRECT | SCE_PASS_SUBSURFACE_INDIRECT)
#define EEVEE_RENDERPASSES_ALL (EEVEE_RENDERPASSES_WITH_POST_PROCESSING | SCE_PASS_COMBINED)
void EEVEE_renderpasses_init(EEVEE_Data *vedata)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
EEVEE_StorageList *stl = vedata->stl;
EEVEE_PrivateData *g_data = stl->g_data;
ViewLayer *view_layer = draw_ctx->view_layer;
g_data->render_passes = (view_layer->passflag & EEVEE_RENDERPASSES_ALL) | SCE_PASS_COMBINED;
}
void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
uint tot_samples)
{
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_TextureList *txl = vedata->txl;
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_PrivateData *g_data = stl->g_data;
const bool needs_post_processing = (g_data->render_passes &
EEVEE_RENDERPASSES_WITH_POST_PROCESSING) > 0;
if (needs_post_processing) {
if (e_data.postprocess_sh == NULL) {
char *frag_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
datatoc_common_uniforms_lib_glsl,
datatoc_bsdf_common_lib_glsl,
datatoc_renderpass_postprocess_frag_glsl);
e_data.postprocess_sh = DRW_shader_create_fullscreen(frag_str, NULL);
MEM_freeN(frag_str);
}
/* Create FrameBuffer. */
/* Should be enough to store the data needs for a single pass.
* Some passes will use less, but it is only relevant for final renderings and
* when renderpasses other than `SCE_PASS_COMBINED` are requested */
DRW_texture_ensure_fullscreen_2d(&txl->renderpass, GPU_RGBA16F, 0);
GPU_framebuffer_ensure_config(&fbl->renderpass_fb,
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->renderpass)});
if ((g_data->render_passes & EEVEE_RENDERPASSES_SUBSURFACE) != 0) {
EEVEE_subsurface_output_init(sldata, vedata, tot_samples);
}
if ((g_data->render_passes & SCE_PASS_MIST) != 0) {
EEVEE_mist_output_init(sldata, vedata);
}
if ((g_data->render_passes & SCE_PASS_AO) != 0) {
EEVEE_occlusion_output_init(sldata, vedata, tot_samples);
}
/* Create Pass. */
DRW_PASS_CREATE(psl->renderpass_pass, DRW_STATE_WRITE_COLOR);
}
else {
/* Free unneeded memory */
DRW_TEXTURE_FREE_SAFE(txl->renderpass);
GPU_FRAMEBUFFER_FREE_SAFE(fbl->renderpass_fb);
psl->renderpass_pass = NULL;
}
}
/* Postprocess data to construct a specific renderpass
*
* This method will create a shading group to perform the post-processing for the given
* `renderpass_type`. The post-processing will be done and the result will be stored in the
* `vedata->txl->renderpass` texture.
*
* Only invoke this function for passes that need post-processing.
*
* After invoking this function the active framebuffer is set to `vedata->fbl->renderpass_fb`. */
void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
eScenePassType renderpass_type)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_TextureList *txl = vedata->txl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_EffectsInfo *effects = stl->effects;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
const int current_sample = effects->taa_current_sample;
DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.postprocess_sh, psl->renderpass_pass);
DRW_shgroup_uniform_int_copy(shgrp, "renderpassType", renderpass_type);
switch (renderpass_type) {
case SCE_PASS_Z: {
DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
DRW_shgroup_uniform_texture_ref(shgrp, "depthBuffer", &dtxl->depth);
break;
}
case SCE_PASS_AO: {
DRW_shgroup_uniform_texture_ref(shgrp, "inputBuffer", &txl->ao_accum);
DRW_shgroup_uniform_int_copy(shgrp, "currentSample", current_sample);
break;
}
case SCE_PASS_NORMAL: {
DRW_shgroup_uniform_texture_ref(shgrp, "inputBuffer", &effects->ssr_normal_input);
break;
}
case SCE_PASS_MIST: {
DRW_shgroup_uniform_texture_ref(shgrp, "inputBuffer", &txl->mist_accum);
DRW_shgroup_uniform_int_copy(shgrp, "currentSample", current_sample);
break;
}
case SCE_PASS_SUBSURFACE_DIRECT: {
DRW_shgroup_uniform_texture_ref(shgrp, "inputBuffer", &txl->sss_dir_accum);
DRW_shgroup_uniform_int_copy(shgrp, "currentSample", current_sample);
break;
}
case SCE_PASS_SUBSURFACE_COLOR: {
DRW_shgroup_uniform_texture_ref(shgrp, "inputBuffer", &txl->sss_col_accum);
DRW_shgroup_uniform_int_copy(shgrp, "currentSample", current_sample);
break;
}
default: {
break;
}
}
DRW_shgroup_call(shgrp, DRW_cache_fullscreen_quad_get(), NULL);
/* only draw the shading group that has been added. This function can be called multiple times
* and the pass still hold the previous shading groups.*/
GPU_framebuffer_bind(fbl->renderpass_fb);
DRW_draw_pass_subset(psl->renderpass_pass, shgrp, shgrp);
}
void EEVEE_renderpasses_free(void)
{
DRW_SHADER_FREE_SAFE(e_data.postprocess_sh);
}

View File

@ -0,0 +1,63 @@
#define SCE_PASS_Z (1 << 1)
#define SCE_PASS_AO (1 << 6)
#define SCE_PASS_NORMAL (1 << 8)
#define SCE_PASS_MIST (1 << 14)
#define SCE_PASS_SUBSURFACE_DIRECT (1 << 28)
#define SCE_PASS_SUBSURFACE_COLOR (1 << 30)
#define ACCUMULATED_COLOR_PASSES (SCE_PASS_SUBSURFACE_DIRECT | SCE_PASS_SUBSURFACE_COLOR)
#define ACCUMULATED_VALUE_PASSES (SCE_PASS_MIST)
uniform int renderpassType;
uniform int currentSample;
uniform sampler2D inputBuffer;
out vec4 fragColor;
void main()
{
ivec2 texel = ivec2(gl_FragCoord.xy);
if (renderpassType == SCE_PASS_Z) {
float depth = texelFetch(depthBuffer, texel, 0).r;
if (depth == 1.0f) {
depth = 1e10;
}
else {
depth = -get_view_z_from_depth(depth);
}
fragColor.r = depth;
}
else if (renderpassType == SCE_PASS_AO) {
float ao_accum = texelFetch(inputBuffer, texel, 0).r;
fragColor = vec4(vec3(min(1.0, ao_accum / currentSample)), 1.0);
}
else if (renderpassType == SCE_PASS_NORMAL) {
vec2 encoded_normal = texelFetch(inputBuffer, texel, 0).rg;
/* decode the normals only when they are valid. otherwise the result buffer will be filled with
* NaN's */
if (any(notEqual(encoded_normal, vec2(0.0)))) {
vec3 decoded_normal = normal_decode(texelFetch(inputBuffer, texel, 0).rg, vec3(0.0));
vec3 world_normal = mat3(ViewMatrixInverse) * decoded_normal;
fragColor = vec4(world_normal, 0.0);
}
else {
fragColor = vec4(0.0);
}
}
else if ((renderpassType & ACCUMULATED_VALUE_PASSES) != 0) {
float accumulated_value = texelFetch(inputBuffer, texel, 0).r;
fragColor.r = accumulated_value / currentSample;
}
else if ((renderpassType & ACCUMULATED_COLOR_PASSES) != 0) {
vec3 accumulated_color = texelFetch(inputBuffer, texel, 0).rgb;
fragColor.rgb = accumulated_color / currentSample;
}
else {
fragColor = vec4(1.0, 0.0, 1.0, 1.0);
}
}