From 2d66a0ef848bfa30e3d607ed3fda1cf9fe8d0beb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 17 May 2023 11:57:36 +0200 Subject: [PATCH] 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 --- .../startup/bl_ui/properties_view_layer.py | 3 + source/blender/draw/CMakeLists.txt | 1 + .../blender/draw/engines/eevee/eevee_engine.c | 1 + .../draw/engines/eevee/eevee_materials.c | 73 +++++++++++++++++++ .../draw/engines/eevee/eevee_private.h | 9 +++ .../blender/draw/engines/eevee/eevee_render.c | 16 ++++ .../draw/engines/eevee/eevee_renderpasses.c | 8 +- .../draw/engines/eevee/eevee_shaders.cc | 11 +++ .../infos/eevee_legacy_effects_info.hh | 8 ++ .../shaders/renderpass_accumulate_frag.glsl | 8 ++ source/blender/makesdna/DNA_layer_types.h | 1 + source/blender/makesdna/DNA_scene_types.h | 1 + source/blender/makesrna/intern/rna_scene.c | 6 ++ source/blender/makesrna/intern/rna_space.c | 1 + 14 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 source/blender/draw/engines/eevee/shaders/renderpass_accumulate_frag.glsl diff --git a/scripts/startup/bl_ui/properties_view_layer.py b/scripts/startup/bl_ui/properties_view_layer.py index 7914188349d..763c85342c0 100644 --- a/scripts/startup/bl_ui/properties_view_layer.py +++ b/scripts/startup/bl_ui/properties_view_layer.py @@ -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" diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index c60b9f3133b..89d96abc698 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -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 diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index 3afbc361dfd..9247178d9b2 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -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); diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index d38b0ec24a4..81283a52fd8 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -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); + } +} + /** \} */ diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 8326419ce1a..131768bdc28 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -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 * diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 8e892a3e9ae..8a79d80c2e9 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -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) { diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c index 5099d021f2d..5174981f90b 100644 --- a/source/blender/draw/engines/eevee/eevee_renderpasses.c +++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c @@ -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; diff --git a/source/blender/draw/engines/eevee/eevee_shaders.cc b/source/blender/draw/engines/eevee/eevee_shaders.cc index 279df8beb3d..00b18039d94 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders.cc +++ b/source/blender/draw/engines/eevee/eevee_shaders.cc @@ -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); diff --git a/source/blender/draw/engines/eevee/shaders/infos/eevee_legacy_effects_info.hh b/source/blender/draw/engines/eevee/shaders/infos/eevee_legacy_effects_info.hh index 6e4ea28b814..2f6a585440a 100644 --- a/source/blender/draw/engines/eevee/shaders/infos/eevee_legacy_effects_info.hh +++ b/source/blender/draw/engines/eevee/shaders/infos/eevee_legacy_effects_info.hh @@ -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") diff --git a/source/blender/draw/engines/eevee/shaders/renderpass_accumulate_frag.glsl b/source/blender/draw/engines/eevee/shaders/renderpass_accumulate_frag.glsl new file mode 100644 index 00000000000..079bdf375a6 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/renderpass_accumulate_frag.glsl @@ -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); +} diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 6ea35dfb770..7d2bec49753 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -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 diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index eb806077ce2..e54b70023a2 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -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" diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 44bad2010ca..dea81f37856 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -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) diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index b6d57587d40..deb96a677c0 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -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", ""},