EEVEE: Add Transparent Render-Pass option

This renderpass pass outputs alpha blender surface
to allow combining them with the opaque passes.

Limitation: This only supports monochromatic opacity.
Colored opacity will show differently than in combined pass.

Pull Request: https://projects.blender.org/blender/blender/pulls/107890
This commit is contained in:
Clément Foucault
2023-05-17 11:57:36 +02:00
parent 39644e7f71
commit 2d66a0ef84
14 changed files with 146 additions and 1 deletions

View File

@@ -147,6 +147,9 @@ class VIEWLAYER_PT_eevee_layer_passes_effects(ViewLayerButtonsPanel, Panel):
col.prop(view_layer_eevee, "use_pass_bloom", text="Bloom")
col.active = scene_eevee.use_bloom
col = layout.column()
col.prop(view_layer_eevee, "use_pass_transparent")
class ViewLayerAOVPanel(ViewLayerButtonsPanel, Panel):
bl_label = "Shader AOV"

View File

@@ -399,6 +399,7 @@ set(GLSL_SRC
engines/eevee/shaders/bsdf_sampling_lib.glsl
engines/eevee/shaders/random_lib.glsl
engines/eevee/shaders/raytrace_lib.glsl
engines/eevee/shaders/renderpass_accumulate_frag.glsl
engines/eevee/shaders/renderpass_lib.glsl
engines/eevee/shaders/renderpass_postprocess_frag.glsl
engines/eevee/shaders/cryptomatte_frag.glsl

View File

@@ -329,6 +329,7 @@ static void eevee_draw_scene(void *vedata)
EEVEE_renderpasses_output_accumulate(sldata, vedata, false);
/* Transparent */
EEVEE_material_transparent_output_accumulate(vedata);
/* TODO(@fclem): should be its own Frame-buffer.
* This is needed because dual-source blending only works with 1 color buffer. */
GPU_framebuffer_texture_attach(fbl->main_color_fb, dtxl->depth, 0, 0);

View File

@@ -1186,4 +1186,77 @@ void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
}
}
void EEVEE_material_transparent_output_init(EEVEE_Data *vedata)
{
EEVEE_PassList *psl = vedata->psl;
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_PrivateData *pd = vedata->stl->g_data;
EEVEE_TextureList *txl = vedata->txl;
if (pd->render_passes & EEVEE_RENDER_PASS_TRANSPARENT) {
/* Intermediate result to blend objects on. */
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
DRW_texture_ensure_fullscreen_2d_ex(
&txl->transparent_depth_tmp, GPU_DEPTH24_STENCIL8, usage, 0);
DRW_texture_ensure_fullscreen_2d_ex(&txl->transparent_color_tmp, GPU_RGBA16F, usage, 0);
GPU_framebuffer_ensure_config(&fbl->transparent_rpass_fb,
{GPU_ATTACHMENT_TEXTURE(txl->transparent_depth_tmp),
GPU_ATTACHMENT_TEXTURE(txl->transparent_color_tmp)});
/* Final result to with AntiAliasing. */
/* TODO mem usage. */
const eGPUTextureFormat texture_format = (true) ? GPU_RGBA32F : GPU_RGBA16F;
eGPUTextureUsage usage_accum = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_HOST_READ |
GPU_TEXTURE_USAGE_ATTACHMENT;
DRW_texture_ensure_fullscreen_2d_ex(&txl->transparent_accum, texture_format, usage_accum, 0);
GPU_framebuffer_ensure_config(
&fbl->transparent_rpass_accum_fb,
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->transparent_accum)});
{
/* This pass Accumulate 1 sample of the transparent pass into the the transparent
* accumulation buffer. */
DRW_PASS_CREATE(psl->transparent_accum_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL);
DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_renderpasses_accumulate_sh_get(),
psl->transparent_accum_ps);
DRW_shgroup_uniform_texture(grp, "inputBuffer", txl->transparent_color_tmp);
DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
}
}
void EEVEE_material_transparent_output_accumulate(EEVEE_Data *vedata)
{
EEVEE_EffectsInfo *effects = vedata->stl->effects;
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_PassList *psl = vedata->psl;
EEVEE_PrivateData *pd = vedata->stl->g_data;
EEVEE_TextureList *txl = vedata->txl;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
if (pd->render_passes & EEVEE_RENDER_PASS_TRANSPARENT) {
const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
pd->renderpass_current_sample = effects->taa_current_sample;
/* Work on a copy of the depth texture to allow re-rendering
* the transparent object to the main pass. */
GPU_texture_copy(txl->transparent_depth_tmp, dtxl->depth);
/* Render transparent objects on a black background. */
GPU_framebuffer_bind(fbl->transparent_rpass_fb);
GPU_framebuffer_clear_color(fbl->transparent_rpass_fb, clear);
DRW_draw_pass(psl->transparent_pass);
/* Accumulate the resulting color buffer. */
GPU_framebuffer_bind(fbl->transparent_rpass_accum_fb);
if (effects->taa_current_sample == 1) {
GPU_framebuffer_clear_color(fbl->transparent_rpass_accum_fb, clear);
}
DRW_draw_pass(psl->transparent_accum_ps);
/* Restore default. */
GPU_framebuffer_bind(fbl->main_fb);
}
}
/** \} */

View File

@@ -267,6 +267,7 @@ typedef struct EEVEE_PassList {
/* Render-pass Accumulation. */
struct DRWPass *material_accum_ps;
struct DRWPass *background_accum_ps;
struct DRWPass *transparent_accum_ps;
struct DRWPass *cryptomatte_ps;
struct DRWPass *depth_ps;
@@ -350,6 +351,8 @@ typedef struct EEVEE_FramebufferList {
struct GPUFrameBuffer *double_buffer_fb;
struct GPUFrameBuffer *double_buffer_color_fb;
struct GPUFrameBuffer *double_buffer_depth_fb;
struct GPUFrameBuffer *transparent_rpass_fb;
struct GPUFrameBuffer *transparent_rpass_accum_fb;
struct GPUFrameBuffer *taa_history_fb;
struct GPUFrameBuffer *taa_history_color_fb;
} EEVEE_FramebufferList;
@@ -370,6 +373,9 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *bloom_accum;
struct GPUTexture *ssr_accum;
struct GPUTexture *shadow_accum;
struct GPUTexture *transparent_accum;
struct GPUTexture *transparent_depth_tmp;
struct GPUTexture *transparent_color_tmp;
struct GPUTexture *cryptomatte;
struct GPUTexture *taa_history;
/* Could not be pool texture because of mipmapping. */
@@ -1217,6 +1223,7 @@ struct GPUShader *EEVEE_shaders_effect_reflection_trace_sh_get(void);
struct GPUShader *EEVEE_shaders_effect_reflection_resolve_sh_get(void);
struct GPUShader *EEVEE_shaders_effect_reflection_resolve_probe_sh_get(void);
struct GPUShader *EEVEE_shaders_effect_reflection_resolve_refl_sh_get(void);
struct GPUShader *EEVEE_shaders_renderpasses_accumulate_sh_get(void);
struct GPUShader *EEVEE_shaders_renderpasses_post_process_sh_get(void);
struct GPUShader *EEVEE_shaders_cryptomatte_sh_get(bool is_hair);
struct GPUShader *EEVEE_shaders_shadow_sh_get(void);
@@ -1475,6 +1482,8 @@ void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve
void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
bool post_effect);
void EEVEE_material_transparent_output_init(EEVEE_Data *vedata);
void EEVEE_material_transparent_output_accumulate(EEVEE_Data *vedata);
/**
* Post-process data to construct a specific render-pass
*

View File

@@ -381,6 +381,19 @@ static void eevee_render_result_bloom(RenderLayer *rl,
}
}
static void eevee_render_result_transparent(RenderLayer *rl,
const char *viewname,
const rcti *rect,
EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata)
{
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_TRANSPARENT) != 0) {
EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_TRANSPARENT, 0);
eevee_render_color_result(
rl, viewname, rect, RE_PASSNAME_TRANSPARENT, 4, vedata->fbl->renderpass_fb, vedata);
}
}
#define EEVEE_RENDER_RESULT_MATERIAL_PASS(pass_name, eevee_pass_type) \
if ((vedata->stl->g_data->render_passes & EEVEE_RENDER_PASS_##eevee_pass_type) != 0) { \
EEVEE_renderpasses_postprocess(sldata, vedata, EEVEE_RENDER_PASS_##eevee_pass_type, 0); \
@@ -631,6 +644,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
/* Subsurface output, Occlusion output, Mist output */
EEVEE_renderpasses_output_accumulate(sldata, vedata, false);
/* Transparent */
EEVEE_material_transparent_output_accumulate(vedata);
GPU_framebuffer_texture_attach(fbl->main_color_fb, dtxl->depth, 0, 0);
GPU_framebuffer_bind(fbl->main_color_fb);
DRW_draw_pass(psl->transparent_pass);
@@ -672,6 +686,7 @@ void EEVEE_render_read_result(EEVEE_Data *vedata,
eevee_render_result_environment(rl, viewname, rect, vedata, sldata);
eevee_render_result_bloom(rl, viewname, rect, vedata, sldata);
eevee_render_result_volume_light(rl, viewname, rect, vedata, sldata);
eevee_render_result_transparent(rl, viewname, rect, vedata, sldata);
eevee_render_result_aovs(rl, viewname, rect, vedata, sldata);
eevee_render_result_cryptomatte(rl, viewname, rect, vedata, sldata);
}
@@ -706,6 +721,7 @@ void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *v
CHECK_PASS_LEGACY(SHADOW, SOCK_RGBA, 3, "RGB");
CHECK_PASS_LEGACY(AO, SOCK_RGBA, 3, "RGB");
CHECK_PASS_EEVEE(BLOOM, SOCK_RGBA, 3, "RGB");
CHECK_PASS_EEVEE(TRANSPARENT, SOCK_RGBA, 4, "RGBA");
LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) {
if ((aov->flag & AOV_CONFLICT) != 0) {

View File

@@ -36,7 +36,7 @@ typedef enum eRenderPassPostProcessType {
#define EEVEE_RENDERPASSES_WITH_POST_PROCESSING \
(EEVEE_RENDER_PASS_Z | EEVEE_RENDER_PASS_MIST | EEVEE_RENDER_PASS_NORMAL | \
EEVEE_RENDER_PASS_AO | EEVEE_RENDER_PASS_BLOOM | EEVEE_RENDER_PASS_VOLUME_LIGHT | \
EEVEE_RENDER_PASS_SHADOW | EEVEE_RENDERPASSES_MATERIAL)
EEVEE_RENDER_PASS_TRANSPARENT | EEVEE_RENDER_PASS_SHADOW | EEVEE_RENDERPASSES_MATERIAL)
#define EEVEE_RENDERPASSES_ALL \
(EEVEE_RENDERPASSES_WITH_POST_PROCESSING | EEVEE_RENDER_PASS_COMBINED)
@@ -130,6 +130,7 @@ void EEVEE_renderpasses_init(EEVEE_Data *vedata)
EEVEE_RENDER_PASS_COMBINED;
}
EEVEE_material_renderpasses_init(vedata);
EEVEE_material_transparent_output_init(vedata);
EEVEE_cryptomatte_renderpasses_init(vedata);
}
@@ -356,6 +357,11 @@ void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata),
g_data->renderpass_input = txl->aov_surface_accum[aov_index];
break;
}
case EEVEE_RENDER_PASS_TRANSPARENT: {
g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR_ALPHA;
g_data->renderpass_input = txl->transparent_accum;
break;
}
case EEVEE_RENDER_PASS_BLOOM: {
g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR;
g_data->renderpass_input = txl->bloom_accum;

View File

@@ -107,6 +107,7 @@ static struct {
struct GPUShader *ggx_refraction_lut_sh;
/* Render Passes */
struct GPUShader *rpass_accumulate_sh;
struct GPUShader *postprocess_sh;
struct GPUShader *cryptomatte_sh[2];
@@ -605,6 +606,15 @@ GPUShader *EEVEE_shaders_effect_ambient_occlusion_debug_sh_get(void)
/** \name Render Passes
* \{ */
GPUShader *EEVEE_shaders_renderpasses_accumulate_sh_get(void)
{
if (e_data.rpass_accumulate_sh == nullptr) {
e_data.rpass_accumulate_sh = DRW_shader_create_from_info_name(
"eevee_legacy_renderpass_accumulate");
}
return e_data.rpass_accumulate_sh;
}
GPUShader *EEVEE_shaders_renderpasses_post_process_sh_get(void)
{
if (e_data.postprocess_sh == nullptr) {
@@ -1467,6 +1477,7 @@ void EEVEE_shaders_free(void)
DRW_SHADER_FREE_SAFE(e_data.gtao_layer_sh);
DRW_SHADER_FREE_SAFE(e_data.gtao_debug_sh);
DRW_SHADER_FREE_SAFE(e_data.velocity_resolve_sh);
DRW_SHADER_FREE_SAFE(e_data.rpass_accumulate_sh);
DRW_SHADER_FREE_SAFE(e_data.postprocess_sh);
DRW_SHADER_FREE_SAFE(e_data.shadow_sh);
DRW_SHADER_FREE_SAFE(e_data.shadow_accum_sh);

View File

@@ -305,6 +305,14 @@ GPU_SHADER_CREATE_INFO(eevee_legacy_post_process)
.auto_resource_location(true)
.do_static_compilation(true);
/* EEVEE_shaders_renderpasses_accumulate_sh_get */
GPU_SHADER_CREATE_INFO(eevee_legacy_renderpass_accumulate)
.additional_info("draw_fullscreen")
.fragment_source("renderpass_accumulate_frag.glsl")
.sampler(1, ImageType::FLOAT_2D, "inputBuffer")
.fragment_out(0, Type::VEC4, "fragColor")
.do_static_compilation(true);
/* EEVEE_shaders_effect_mist_sh_get */
GPU_SHADER_CREATE_INFO(eevee_legacy_effect_mist_FIRST_PASS)
.define("FIRST_PASS")

View File

@@ -0,0 +1,8 @@
/** Stupidly simple shader to allow alpha blended accumulation. */
void main()
{
ivec2 texel = ivec2(gl_FragCoord.xy);
fragColor = texelFetch(inputBuffer, texel, 0);
}

View File

@@ -44,6 +44,7 @@ typedef enum eViewLayerEEVEEPassType {
EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET = (1 << 17),
EEVEE_RENDER_PASS_CRYPTOMATTE_MATERIAL = (1 << 18),
EEVEE_RENDER_PASS_VECTOR = (1 << 19),
EEVEE_RENDER_PASS_TRANSPARENT = (1 << 20),
} eViewLayerEEVEEPassType;
#define EEVEE_RENDER_PASS_MAX_BIT 20

View File

@@ -312,6 +312,7 @@ typedef enum eScenePassType {
#define RE_PASSNAME_FREESTYLE "Freestyle"
#define RE_PASSNAME_BLOOM "BloomCol"
#define RE_PASSNAME_VOLUME_LIGHT "VolumeDir"
#define RE_PASSNAME_TRANSPARENT "Transp"
#define RE_PASSNAME_CRYPTOMATTE_OBJECT "CryptoObject"
#define RE_PASSNAME_CRYPTOMATTE_ASSET "CryptoAsset"

View File

@@ -4354,6 +4354,12 @@ static void rna_def_view_layer_eevee(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "render_passes", EEVEE_RENDER_PASS_BLOOM);
RNA_def_property_ui_text(prop, "Bloom", "Deliver bloom pass");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
prop = RNA_def_property(srna, "use_pass_transparent", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "render_passes", EEVEE_RENDER_PASS_TRANSPARENT);
RNA_def_property_ui_text(
prop, "Transparent", "Deliver alpha blended surfaces in a separate pass");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update");
}
static void rna_def_view_layer_aovs(BlenderRNA *brna, PropertyRNA *cprop)

View File

@@ -448,6 +448,7 @@ static const EnumPropertyItem rna_enum_view3dshading_render_pass_type_items[] =
{EEVEE_RENDER_PASS_ENVIRONMENT, "ENVIRONMENT", 0, "Environment", ""},
{EEVEE_RENDER_PASS_AO, "AO", 0, "Ambient Occlusion", ""},
{EEVEE_RENDER_PASS_SHADOW, "SHADOW", 0, "Shadow", ""},
{EEVEE_RENDER_PASS_TRANSPARENT, "TRANSPARENT", 0, "Transparent", ""},
RNA_ENUM_ITEM_HEADING(N_("Light"), NULL),
{EEVEE_RENDER_PASS_DIFFUSE_LIGHT, "DIFFUSE_LIGHT", 0, "Diffuse Light", ""},