From ac11ccd2bdc587addecd8e3006f80fae3155ddf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 13 Dec 2023 02:19:19 +0100 Subject: [PATCH] EEVEE-Next: Add Translucent BSDF support This adds support for Translucent BSDF. This also fixes a bug to allow correct shadowing. The input normal had to be set back to non-inverted in the node function to allow for correct interpretation of the Normal by Screen Space Reflections. This add the necessary optimization and code deduplication to hybrid deferred and forward pipeline. Pull Request: https://projects.blender.org/blender/blender/pulls/116070 --- source/blender/draw/CMakeLists.txt | 1 + .../shaders/closure_eval_surface_lib.glsl | 2 +- .../draw/engines/eevee_next/eevee_material.hh | 3 + .../draw/engines/eevee_next/eevee_pipeline.cc | 6 +- .../draw/engines/eevee_next/eevee_pipeline.hh | 8 +- .../draw/engines/eevee_next/eevee_shader.cc | 52 +++++- .../engines/eevee_next/eevee_shader_shared.hh | 2 + .../shaders/eevee_deferred_combine_frag.glsl | 35 ++-- .../shaders/eevee_deferred_light_frag.glsl | 55 +++--- .../eevee_deferred_tile_classify_frag.glsl | 6 +- .../eevee_next/shaders/eevee_forward_lib.glsl | 121 +++++++++++++ .../eevee_next/shaders/eevee_gbuffer_lib.glsl | 40 ++++- .../shaders/eevee_horizon_denoise_comp.glsl | 15 +- .../shaders/eevee_light_eval_lib.glsl | 3 +- .../eevee_next/shaders/eevee_light_lib.glsl | 31 ---- .../shaders/eevee_lightprobe_eval_lib.glsl | 10 +- .../shaders/eevee_nodetree_lib.glsl | 11 +- .../shaders/eevee_shadow_tracing_lib.glsl | 14 +- .../shaders/eevee_subsurface_setup_comp.glsl | 2 +- .../shaders/eevee_surf_deferred_frag.glsl | 8 +- .../shaders/eevee_surf_forward_frag.glsl | 168 ++---------------- .../shaders/eevee_surf_hybrid_frag.glsl | 62 ++----- .../shaders/infos/eevee_deferred_info.hh | 7 +- .../shaders/infos/eevee_material_info.hh | 2 - source/blender/gpu/GPU_material.h | 9 +- .../gpu_shader_material_translucent.glsl | 2 +- .../nodes/node_shader_bsdf_translucent.cc | 2 +- 27 files changed, 351 insertions(+), 326 deletions(-) create mode 100644 source/blender/draw/engines/eevee_next/shaders/eevee_forward_lib.glsl diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index b17d01b0bd7..a20186dde14 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -506,6 +506,7 @@ set(GLSL_SRC engines/eevee_next/shaders/eevee_film_cryptomatte_post_comp.glsl engines/eevee_next/shaders/eevee_film_frag.glsl engines/eevee_next/shaders/eevee_film_lib.glsl + engines/eevee_next/shaders/eevee_forward_lib.glsl engines/eevee_next/shaders/eevee_gbuffer_lib.glsl engines/eevee_next/shaders/eevee_geom_curves_vert.glsl engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl index e02759f6c82..92f46a59c8b 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl @@ -95,7 +95,7 @@ Closure closure_eval(ClosureTranslucent translucent) /* Glue with the old system. */ CLOSURE_VARS_DECLARE_1(Translucent); - in_Translucent_0.N = translucent.N; + in_Translucent_0.N = -translucent.N; CLOSURE_EVAL_FUNCTION_1(TranslucentBSDF, Translucent); diff --git a/source/blender/draw/engines/eevee_next/eevee_material.hh b/source/blender/draw/engines/eevee_next/eevee_material.hh index 4cab9576cf9..5ed96b5bf7c 100644 --- a/source/blender/draw/engines/eevee_next/eevee_material.hh +++ b/source/blender/draw/engines/eevee_next/eevee_material.hh @@ -125,6 +125,9 @@ static inline eClosureBits shader_closure_bits_from_flag(const GPUMaterial *gpum if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSPARENT)) { closure_bits |= CLOSURE_TRANSPARENCY; } + if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSLUCENT)) { + closure_bits |= CLOSURE_TRANSLUCENT; + } if (GPU_material_flag_get(gpumat, GPU_MATFLAG_EMISSION)) { closure_bits |= CLOSURE_EMISSION; } diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index 79af1709820..fc3fd77a1c0 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -491,7 +491,8 @@ void DeferredLayer::begin_sync() void DeferredLayer::end_sync() { - eClosureBits evaluated_closures = CLOSURE_DIFFUSE | CLOSURE_REFLECTION | CLOSURE_REFRACTION; + eClosureBits evaluated_closures = CLOSURE_DIFFUSE | CLOSURE_TRANSLUCENT | CLOSURE_REFLECTION | + CLOSURE_REFRACTION; if (closure_bits_ & evaluated_closures) { /* Add the tile classification step at the end of the GBuffer pass. */ { @@ -716,7 +717,8 @@ void DeferredLayer::render(View &main_view, inst_.manager->submit(gbuffer_ps_, render_view); - int closure_count = count_bits_i(closure_bits_ & (CLOSURE_REFLECTION | CLOSURE_DIFFUSE)); + int closure_count = count_bits_i(closure_bits_ & + (CLOSURE_REFLECTION | CLOSURE_DIFFUSE | CLOSURE_TRANSLUCENT)); for (int i = 0; i < ARRAY_SIZE(direct_radiance_txs_); i++) { direct_radiance_txs_[i].acquire( (closure_count > 1) ? extent : int2(1), GPU_R11F_G11F_B10F, usage_rw); diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh index 27363ee2d24..90364ebcd19 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh @@ -188,15 +188,15 @@ struct DeferredLayerBase { /* Return the amount of gbuffer layer needed. */ int closure_layer_count() const { - return count_bits_i(closure_bits_ & - (CLOSURE_REFRACTION | CLOSURE_REFLECTION | CLOSURE_DIFFUSE | CLOSURE_SSS)); + return count_bits_i(closure_bits_ & (CLOSURE_REFRACTION | CLOSURE_REFLECTION | + CLOSURE_DIFFUSE | CLOSURE_TRANSLUCENT | CLOSURE_SSS)); } /* Return the amount of gbuffer layer needed. */ int color_layer_count() const { - return count_bits_i(closure_bits_ & - (CLOSURE_REFRACTION | CLOSURE_REFLECTION | CLOSURE_DIFFUSE)); + return count_bits_i(closure_bits_ & (CLOSURE_REFRACTION | CLOSURE_REFLECTION | + CLOSURE_DIFFUSE | CLOSURE_TRANSLUCENT)); } }; diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.cc b/source/blender/draw/engines/eevee_next/eevee_shader.cc index c0fe54f83be..d8da4340f7f 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc @@ -406,8 +406,56 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu info.additional_info("eevee_cryptomatte_out"); } - if (GPU_material_flag_get(gpumat, GPU_MATFLAG_SUBSURFACE) && pipeline_type == MAT_PIPE_FORWARD) { - info.define("SSS_TRANSMITTANCE"); + int lit_closure_count = 0; + if (GPU_material_flag_get(gpumat, GPU_MATFLAG_DIFFUSE)) { + info.define("MAT_DIFFUSE"); + lit_closure_count++; + } + if (GPU_material_flag_get(gpumat, GPU_MATFLAG_GLOSSY)) { + info.define("MAT_REFLECTION"); + lit_closure_count++; + } + if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSLUCENT)) { + info.define("MAT_TRANSLUCENT"); + lit_closure_count++; + } + if (GPU_material_flag_get(gpumat, GPU_MATFLAG_SUBSURFACE)) { + info.define("MAT_SUBSURFACE"); + lit_closure_count++; + } + if (GPU_material_flag_get(gpumat, GPU_MATFLAG_REFRACT)) { + info.define("MAT_REFRACTION"); + /* TODO(fclem): Support refracted lights. */ + } + + if (GPU_material_flag_get(gpumat, GPU_MATFLAG_TRANSLUCENT | GPU_MATFLAG_SUBSURFACE)) { + info.define("SHADOW_SUBSURFACE"); + } + + if ((pipeline_type == MAT_PIPE_FORWARD) || + GPU_material_flag_get(gpumat, GPU_MATFLAG_SHADER_TO_RGBA)) + { + switch (lit_closure_count) { + case 0: + /* Define nothing. This will in turn define SKIP_LIGHT_EVAL. */ + break; + /* These need to be separated since the strings need to be static. */ + case 1: + info.define("LIGHT_CLOSURE_EVAL_COUNT", "1"); + break; + case 2: + info.define("LIGHT_CLOSURE_EVAL_COUNT", "2"); + break; + case 3: + info.define("LIGHT_CLOSURE_EVAL_COUNT", "3"); + break; + case 4: + info.define("LIGHT_CLOSURE_EVAL_COUNT", "4"); + break; + default: + BLI_assert_unreachable(); + break; + } } if (GPU_material_flag_get(gpumat, GPU_MATFLAG_BARYCENTRIC)) { diff --git a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh index fd99ccbe94e..599b4a20ca7 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh @@ -1182,6 +1182,7 @@ enum eClosureBits : uint32_t { CLOSURE_SSS = (1u << 1u), CLOSURE_REFLECTION = (1u << 2u), CLOSURE_REFRACTION = (1u << 3u), + CLOSURE_TRANSLUCENT = (1u << 4u), CLOSURE_TRANSPARENCY = (1u << 8u), CLOSURE_EMISSION = (1u << 9u), CLOSURE_HOLDOUT = (1u << 10u), @@ -1198,6 +1199,7 @@ enum GBufferMode : uint32_t { GBUF_REFRACTION = 2u, GBUF_DIFFUSE = 3u, GBUF_SSS = 4u, + GBUF_TRANSLUCENT = 5u, /** Special configurations. Packs multiple closures into 1 layer. */ GBUF_OPAQUE_DIELECTRIC = 14u, diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_combine_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_combine_frag.glsl index f341cc4ac99..90f0732aaf8 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_combine_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_combine_frag.glsl @@ -17,35 +17,42 @@ void main() GBufferData gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel); - vec3 diffuse_light = vec3(0.0); - vec3 reflect_light = vec3(0.0); - vec3 refract_light = vec3(0.0); + vec3 glossy_reflect_light = vec3(0.0); + vec3 glossy_refract_light = vec3(0.0); + vec3 diffuse_reflect_light = vec3(0.0); + vec3 diffuse_refract_light = vec3(0.0); if (gbuf.has_diffuse) { - diffuse_light = imageLoad(direct_radiance_1_img, texel).rgb + - imageLoad(indirect_diffuse_img, texel).rgb; + diffuse_reflect_light = imageLoad(direct_radiance_1_img, texel).rgb + + imageLoad(indirect_diffuse_img, texel).rgb; } if (gbuf.has_reflection) { - reflect_light = imageLoad(direct_radiance_2_img, texel).rgb + - imageLoad(indirect_reflect_img, texel).rgb; + glossy_reflect_light = imageLoad(direct_radiance_2_img, texel).rgb + + imageLoad(indirect_reflect_img, texel).rgb; + } + + if (gbuf.has_translucent) { + /* Indirect radiance not implemented yet. */ + diffuse_refract_light = imageLoad(direct_radiance_3_img, texel).rgb; } if (gbuf.has_refraction) { - refract_light = - /* imageLoad(direct_radiance_3_img, texel).rgb + */ /* TODO: Not implemented. */ - imageLoad(indirect_refract_img, texel).rgb; + /* Direct radiance not implemented yet. */ + glossy_refract_light = imageLoad(indirect_refract_img, texel).rgb; } /* Light passes. */ - vec3 specular_light = reflect_light + refract_light; + vec3 diffuse_light = diffuse_reflect_light + diffuse_refract_light; + vec3 specular_light = glossy_reflect_light + glossy_refract_light; output_renderpass_color(uniform_buf.render_pass.diffuse_light_id, vec4(diffuse_light, 1.0)); output_renderpass_color(uniform_buf.render_pass.specular_light_id, vec4(specular_light, 1.0)); /* Combine. */ out_combined = vec4(0.0); - out_combined.xyz += diffuse_light * gbuf.diffuse.color; - out_combined.xyz += reflect_light * gbuf.reflection.color; - out_combined.xyz += refract_light * gbuf.refraction.color; + out_combined.xyz += diffuse_reflect_light * gbuf.diffuse.color; + out_combined.xyz += diffuse_refract_light * gbuf.translucent.color; + out_combined.xyz += glossy_reflect_light * gbuf.reflection.color; + out_combined.xyz += glossy_refract_light * gbuf.refraction.color; if (any(isnan(out_combined))) { out_combined = vec4(1.0, 0.0, 1.0, 0.0); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl index 383ac58e479..da91acfdb4d 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl @@ -31,43 +31,42 @@ void main() vec3 V = drw_world_incident_vector(P); float vPz = dot(drw_view_forward(), P) - dot(drw_view_forward(), drw_view_position()); - ClosureLightStack stack; + ClosureLight cl_diff; + cl_diff.N = gbuf.diffuse.N; + cl_diff.ltc_mat = LTC_LAMBERT_MAT; + cl_diff.type = LIGHT_DIFFUSE; - /* TODO(fclem): This is waiting for fully flexible evaluation pipeline. We need to refactor the - * raytracing pipeline first. */ - if (gbuf.has_diffuse) { - ClosureLight cl_diff; - cl_diff.N = gbuf.diffuse.N; - cl_diff.ltc_mat = LTC_LAMBERT_MAT; - cl_diff.type = LIGHT_DIFFUSE; - stack.cl[0] = cl_diff; - } - else { - ClosureLight cl_refl; - cl_refl.N = gbuf.reflection.N; - cl_refl.ltc_mat = LTC_GGX_MAT(dot(gbuf.reflection.N, V), gbuf.reflection.roughness); - cl_refl.type = LIGHT_SPECULAR; - stack.cl[0] = cl_refl; - } - -#if LIGHT_CLOSURE_EVAL_COUNT > 1 ClosureLight cl_refl; cl_refl.N = gbuf.reflection.N; cl_refl.ltc_mat = LTC_GGX_MAT(dot(gbuf.reflection.N, V), gbuf.reflection.roughness); cl_refl.type = LIGHT_SPECULAR; - stack.cl[1] = cl_refl; -#endif -#if LIGHT_CLOSURE_EVAL_COUNT > 2 ClosureLight cl_sss; cl_sss.N = -gbuf.diffuse.N; cl_sss.ltc_mat = LTC_LAMBERT_MAT; cl_sss.type = LIGHT_DIFFUSE; - stack.cl[2] = cl_sss; + + ClosureLight cl_translucent; + cl_translucent.N = -gbuf.translucent.N; + cl_translucent.ltc_mat = LTC_LAMBERT_MAT; + cl_translucent.type = LIGHT_DIFFUSE; + + ClosureLightStack stack; + + /* TODO(fclem): This is waiting for fully flexible evaluation pipeline. We need to refactor the + * raytracing pipeline first. */ + stack.cl[0] = (gbuf.has_diffuse) ? cl_diff : cl_refl; + +#if LIGHT_CLOSURE_EVAL_COUNT > 1 + stack.cl[1] = cl_refl; #endif - float thickness = 0.0; -#ifdef SSS_TRANSMITTANCE +#if LIGHT_CLOSURE_EVAL_COUNT > 2 + stack.cl[2] = (gbuf.has_translucent) ? cl_translucent : cl_sss; +#endif + + float thickness = (gbuf.has_translucent) ? gbuf.thickness : 0.0; +#ifdef MAT_SUBSURFACE if (gbuf.has_sss) { float shadow_thickness = thickness_from_shadow(P, Ng, vPz); thickness = (shadow_thickness != THICKNESS_NO_VALUE) ? max(shadow_thickness, gbuf.thickness) : @@ -88,7 +87,7 @@ void main() radiance_unshadowed += stack.cl[2].light_unshadowed; #endif -#ifdef SSS_TRANSMITTANCE +#ifdef MAT_SUBSURFACE if (gbuf.has_sss) { vec3 sss_profile = subsurface_transmission(gbuf.diffuse.sss_radius, thickness); stack.cl[2].light_shadowed *= sss_profile; @@ -121,10 +120,8 @@ void main() #endif #if LIGHT_CLOSURE_EVAL_COUNT > 2 -# if 0 /* Will work when we have fully flexible evaluation. */ - if (gbuf.closure_count > 2) { + if (gbuf.closure_count > 2 || gbuf.has_translucent) { imageStore(direct_radiance_3_img, texel, vec4(stack.cl[2].light_shadowed, 1.0)); } -# endif #endif } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_tile_classify_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_tile_classify_frag.glsl index 8a409fe1bb2..da171d377ba 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_tile_classify_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_tile_classify_frag.glsl @@ -27,7 +27,11 @@ void main() if (gbuffer_has_closure(in_gbuffer_header, eClosureBits(CLOSURE_REFRACTION))) { imageStore(tile_mask_img, ivec3(tile_co, 2), uvec4(1u)); } - if (gbuffer_has_closure(in_gbuffer_header, eClosureBits(CLOSURE_SSS))) { + if (gbuffer_has_closure(in_gbuffer_header, eClosureBits(CLOSURE_TRANSLUCENT))) { + imageStore(tile_mask_img, ivec3(tile_co, 3), uvec4(1u)); + } + /* TODO(fclem): For now, override SSS if we have translucency. */ + else if (gbuffer_has_closure(in_gbuffer_header, eClosureBits(CLOSURE_SSS))) { imageStore(tile_mask_img, ivec3(tile_co, 3), uvec4(1u)); } } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_forward_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_forward_lib.glsl new file mode 100644 index 00000000000..e64acd62e55 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_forward_lib.glsl @@ -0,0 +1,121 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** + * Forward lighting evaluation: Lighting is evaluated during the geometry rasterization. + * + * This is used by alpha blended materials and materials using Shader to RGB nodes. + */ + +#pragma BLENDER_REQUIRE(eevee_subsurface_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_lightprobe_eval_lib.glsl) + +void forward_lighting_eval(float thickness, out vec3 radiance, out vec3 transmittance) +{ + float vPz = dot(drw_view_forward(), g_data.P) - dot(drw_view_forward(), drw_view_position()); + vec3 V = drw_world_incident_vector(g_data.P); + + ClosureLightStack stack; + + ClosureLight cl_diffuse; + cl_diffuse.N = g_diffuse_data.N; + cl_diffuse.ltc_mat = LTC_LAMBERT_MAT; + cl_diffuse.type = LIGHT_DIFFUSE; + + ClosureLight cl_subsurface; + cl_subsurface.N = -g_diffuse_data.N; + cl_subsurface.ltc_mat = LTC_LAMBERT_MAT; + cl_subsurface.type = LIGHT_DIFFUSE; + + ClosureLight cl_translucent; + cl_translucent.N = -g_translucent_data.N; + cl_translucent.ltc_mat = LTC_LAMBERT_MAT; + cl_translucent.type = LIGHT_DIFFUSE; + + ClosureLight cl_reflection; + cl_reflection.N = g_reflection_data.N; + cl_reflection.ltc_mat = LTC_GGX_MAT(dot(g_reflection_data.N, V), g_reflection_data.roughness); + cl_reflection.type = LIGHT_SPECULAR; + + int cl_layer = 0; + +#ifdef MAT_DIFFUSE + const int cl_diffuse_id = cl_layer++; + stack.cl[cl_diffuse_id] = cl_diffuse; +#endif + +#ifdef MAT_SUBSURFACE + const int cl_subsurface_id = cl_layer++; + stack.cl[cl_subsurface_id] = cl_subsurface; +#endif + +#ifdef MAT_TRANSLUCENT + const int cl_translucent_id = cl_layer++; + stack.cl[cl_translucent_id] = cl_translucent; +#endif + +#ifdef MAT_REFLECTION + const int cl_reflection_id = cl_layer++; + stack.cl[cl_reflection_id] = cl_reflection; +#endif + +#ifndef SKIP_LIGHT_EVAL + light_eval(stack, g_data.P, g_data.Ng, V, vPz, thickness); +#endif + +#ifdef MAT_SUBSURFACE + vec3 sss_profile = subsurface_transmission(g_diffuse_data.sss_radius, thickness); + stack.cl[cl_subsurface_id].light_shadowed *= sss_profile; + stack.cl[cl_subsurface_id].light_unshadowed *= sss_profile; + /* Fuse back the SSS transmittance with the diffuse lighting. */ + stack.cl[cl_diffuse_id].light_shadowed += stack.cl[cl_subsurface_id].light_shadowed; + stack.cl[cl_diffuse_id].light_unshadowed += stack.cl[cl_subsurface_id].light_unshadowed; +#endif + + vec3 diffuse_light = vec3(0.0); + vec3 translucent_light = vec3(0.0); + vec3 reflection_light = vec3(0.0); + vec3 refraction_light = vec3(0.0); + + vec2 noise_probe = interlieved_gradient_noise(gl_FragCoord.xy, vec2(0, 1), vec2(0.0)); + LightProbeSample samp = lightprobe_load(g_data.P, g_data.Ng, V); + +#ifdef MAT_DIFFUSE + diffuse_light = stack.cl[cl_diffuse_id].light_shadowed; + diffuse_light += lightprobe_eval(samp, g_diffuse_data, g_data.P, V, noise_probe); +#endif +#ifdef MAT_TRANSLUCENT + translucent_light = stack.cl[cl_translucent_id].light_shadowed; + translucent_light += lightprobe_eval(samp, g_translucent_data, g_data.P, V, noise_probe); +#endif +#ifdef MAT_REFLECTION + reflection_light = stack.cl[cl_reflection_id].light_shadowed; + reflection_light += lightprobe_eval(samp, g_reflection_data, g_data.P, V, noise_probe); +#endif +#ifdef MAT_REFRACTION + /* TODO(fclem): Refraction from lightprobe. */ + // refraction_light += lightprobe_eval(samp, g_refraction_data, g_data.P, V, noise_probe); +#endif + + /* Apply weight. */ + g_diffuse_data.color *= g_diffuse_data.weight; + g_translucent_data.color *= g_translucent_data.weight; + g_reflection_data.color *= g_reflection_data.weight; + g_refraction_data.color *= g_refraction_data.weight; + /* Mask invalid lighting from undefined closure. */ + diffuse_light = (g_diffuse_data.weight > 1e-5) ? diffuse_light : vec3(0.0); + translucent_light = (g_translucent_data.weight > 1e-5) ? translucent_light : vec3(0.0); + reflection_light = (g_reflection_data.weight > 1e-5) ? reflection_light : vec3(0.0); + refraction_light = (g_refraction_data.weight > 1e-5) ? refraction_light : vec3(0.0); + + /* Combine all radiance. */ + radiance = g_emission; + radiance += g_diffuse_data.color * diffuse_light; + radiance += g_reflection_data.color * reflection_light; + radiance += g_refraction_data.color * refraction_light; + radiance += g_translucent_data.color * translucent_light; + + transmittance = g_transmittance; +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_lib.glsl index dd2f769637f..ad826a62088 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_gbuffer_lib.glsl @@ -163,6 +163,13 @@ bool gbuffer_has_closure(uint header, eClosureBits closure) return has_diffuse; } + bool has_translucent = (gbuffer_header_unpack(header, layer) == GBUF_TRANSLUCENT); + layer += int(has_translucent); + + if (closure == eClosureBits(CLOSURE_TRANSLUCENT)) { + return has_translucent; + } + bool has_sss = (gbuffer_header_unpack(header, layer) == GBUF_SSS); layer += int(has_sss); @@ -181,6 +188,7 @@ struct GBufferDataPacked { }; GBufferDataPacked gbuffer_pack(ClosureDiffuse diffuse, + ClosureTranslucent translucent, ClosureReflection reflection, ClosureRefraction refraction, vec3 default_N, @@ -192,6 +200,7 @@ GBufferDataPacked gbuffer_pack(ClosureDiffuse diffuse, bool has_refraction = refraction.weight > 1e-5; bool has_reflection = reflection.weight > 1e-5; bool has_diffuse = diffuse.weight > 1e-5; + bool has_translucent = translucent.weight > 1e-5; bool has_sss = diffuse.sss_id > 0; int layer = 0; @@ -241,7 +250,16 @@ GBufferDataPacked gbuffer_pack(ClosureDiffuse diffuse, layer += 1; } - if (has_sss) { + if (has_translucent) { + gbuf.color[layer] = gbuffer_color_pack(translucent.color); + gbuf.closure[layer].xy = gbuffer_normal_pack(translucent.N); + gbuf.closure[layer].z = 0.0; /* Unused. */ + gbuf.closure[layer].w = gbuffer_thickness_pack(thickness); + gbuf.header |= gbuffer_header_pack(GBUF_TRANSLUCENT, layer); + layer += 1; + } + /* TODO(fclem): For now, override SSS if we have translucency. */ + else if (has_sss) { gbuf.closure[layer].xyz = gbuffer_sss_radii_pack(diffuse.sss_radius); gbuf.closure[layer].w = gbuffer_object_id_unorm16_pack(diffuse.sss_id); gbuf.header |= gbuffer_header_pack(GBUF_SSS, layer); @@ -264,12 +282,14 @@ GBufferDataPacked gbuffer_pack(ClosureDiffuse diffuse, struct GBufferData { /* Only valid (or null) if `has_diffuse`, `has_reflection` or `has_refraction` is true. */ ClosureDiffuse diffuse; + ClosureTranslucent translucent; ClosureReflection reflection; ClosureRefraction refraction; /* First world normal stored in the gbuffer. Only valid if `has_any_surface` is true. */ vec3 surface_N; float thickness; bool has_diffuse; + bool has_translucent; bool has_reflection; bool has_refraction; bool has_sss; @@ -394,6 +414,24 @@ GBufferData gbuffer_read(usampler2D header_tx, gbuf.thickness = 0.0; } + gbuf.has_translucent = (gbuffer_header_unpack(gbuf.header, layer) == GBUF_TRANSLUCENT); + + if (gbuf.has_translucent) { + vec4 closure_packed = texelFetch(closure_tx, ivec3(texel, layer), 0); + vec4 color_packed = texelFetch(color_tx, ivec3(texel, layer), 0); + + gbuf.translucent.color = gbuffer_color_unpack(color_packed); + gbuf.translucent.N = gbuffer_normal_unpack(closure_packed.xy); + gbuf.thickness = gbuffer_thickness_unpack(closure_packed.w); + gbuf.closure_count += 1u; + layer += 1; + } + else { + /* Default values. */ + gbuf.translucent.color = vec3(0.0); + gbuf.translucent.N = vec3(0.0, 0.0, 1.0); + } + gbuf.has_sss = (gbuffer_header_unpack(gbuf.header, layer) == GBUF_SSS); if (gbuf.has_sss) { diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_denoise_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_denoise_comp.glsl index dec304346a7..d5bddbdd218 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_denoise_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_horizon_denoise_comp.glsl @@ -55,20 +55,7 @@ vec3 from_accumulation_space(vec3 color) vec3 load_normal(ivec2 texel) { - GBufferData gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel); - - /* TODO(fclem): Load preprocessed Normal. */ - vec3 N = vec3(0.0); - if (gbuf.has_diffuse) { - N = gbuf.diffuse.N; - } - else if (gbuf.has_reflection) { - N = gbuf.reflection.N; - } - else if (gbuf.has_refraction) { - N = gbuf.refraction.N; - } - return N; + return gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel).surface_N; } void main() diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_light_eval_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_light_eval_lib.glsl index 8a0f6f1b302..c2b22cbfeaa 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_light_eval_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_light_eval_lib.glsl @@ -25,6 +25,7 @@ #if !defined(LIGHT_CLOSURE_EVAL_COUNT) # define LIGHT_CLOSURE_EVAL_COUNT 1 +# define SKIP_LIGHT_EVAL #endif uint shadow_pack(float visibility, uint bit_depth, uint shift) @@ -192,7 +193,7 @@ void light_eval(inout ClosureLightStack stack, vec3 P, vec3 Ng, vec3 V, float vP light_eval(stack, P, Ng, V, vPz, thickness, 0u); } -# if !defined(SSS_TRANSMITTANCE) && defined(LIGHT_ITER_FORCE_NO_CULLING) +# if !defined(SHADOW_SUBSURFACE) && defined(LIGHT_ITER_FORCE_NO_CULLING) void light_eval(inout ClosureLightStack stack, vec3 P, vec3 Ng, vec3 V) { light_eval(stack, P, Ng, V, 0.0, 0.0, 0u); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_light_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_light_lib.glsl index 094b2db2d0c..2339deae622 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_light_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_light_lib.glsl @@ -233,35 +233,4 @@ float light_ltc( } } -#ifdef SSS_TRANSMITTANCE -float sample_transmittance_profile(float u) -{ - return utility_tx_sample(utility_tx, vec2(u, 0.0), UTIL_SSS_TRANSMITTANCE_PROFILE_LAYER).r; -} - -vec3 light_translucent(const bool is_directional, - LightData light, - vec3 N, - LightVector lv, - vec3 sss_radius, - float delta) -{ - /* TODO(fclem): We should compute the power at the entry point. */ - /* NOTE(fclem): we compute the light attenuation using the light vector but the transmittance - * using the shadow depth delta. */ - float power = light_point_light(light, is_directional, lv); - /* Do not add more energy on front faces. Also apply lambertian BSDF. */ - power *= max(0.0, dot(-N, lv.L)) * M_1_PI; - - sss_radius *= SSS_TRANSMIT_LUT_RADIUS; - vec3 channels_co = saturate(delta / sss_radius) * SSS_TRANSMIT_LUT_SCALE + SSS_TRANSMIT_LUT_BIAS; - - vec3 translucency; - translucency.x = (sss_radius.x > 0.0) ? sample_transmittance_profile(channels_co.x) : 0.0; - translucency.y = (sss_radius.y > 0.0) ? sample_transmittance_profile(channels_co.y) : 0.0; - translucency.z = (sss_radius.z > 0.0) ? sample_transmittance_profile(channels_co.z) : 0.0; - return translucency * power; -} -#endif - /** \} */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_lightprobe_eval_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_lightprobe_eval_lib.glsl index 2b84f468336..5970ae6d707 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_lightprobe_eval_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_lightprobe_eval_lib.glsl @@ -282,9 +282,15 @@ float lightprobe_roughness_to_lod(float roughness) return sqrt(roughness) * 11.0; } -vec3 lightprobe_eval(LightProbeSample samp, ClosureDiffuse diffuse, vec3 P, vec3 V, vec2 noise) +vec3 lightprobe_eval(LightProbeSample samp, ClosureDiffuse cl, vec3 P, vec3 V, vec2 noise) { - vec3 radiance_sh = spherical_harmonics_evaluate_lambert(diffuse.N, samp.volume_irradiance); + vec3 radiance_sh = spherical_harmonics_evaluate_lambert(cl.N, samp.volume_irradiance); + return radiance_sh; +} + +vec3 lightprobe_eval(LightProbeSample samp, ClosureTranslucent cl, vec3 P, vec3 V, vec2 noise) +{ + vec3 radiance_sh = spherical_harmonics_evaluate_lambert(-cl.N, samp.volume_irradiance); return radiance_sh; } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl index 48d5d2e7534..9fe1ce85178 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl @@ -18,12 +18,14 @@ float g_holdout; /* Sampled closure parameters. */ ClosureDiffuse g_diffuse_data; +ClosureTranslucent g_translucent_data; ClosureReflection g_reflection_data; ClosureRefraction g_refraction_data; ClosureVolumeScatter g_volume_scatter_data; ClosureVolumeAbsorption g_volume_absorption_data; /* Random number per sampled closure type. */ float g_diffuse_rand; +float g_translucent_rand; float g_reflection_rand; float g_refraction_rand; float g_volume_scatter_rand; @@ -63,6 +65,10 @@ void closure_weights_reset() g_diffuse_data.sss_radius = vec3(0.0); g_diffuse_data.sss_id = uint(0); + g_translucent_data.weight = 0.0; + g_translucent_data.color = vec3(0.0); + g_translucent_data.N = vec3(0.0); + g_reflection_data.weight = 0.0; g_reflection_data.color = vec3(0.0); g_reflection_data.N = vec3(0.0); @@ -82,10 +88,11 @@ void closure_weights_reset() g_volume_absorption_data.absorption = vec3(0.0); #if defined(GPU_FRAGMENT_SHADER) - g_diffuse_rand = g_reflection_rand = g_refraction_rand = g_closure_rand; + g_diffuse_rand = g_translucent_rand = g_reflection_rand = g_refraction_rand = g_closure_rand; g_volume_scatter_rand = g_volume_absorption_rand = g_closure_rand; #else g_diffuse_rand = 0.0; + g_translucent_rand = 0.0; g_reflection_rand = 0.0; g_refraction_rand = 0.0; g_volume_scatter_rand = 0.0; @@ -106,7 +113,7 @@ Closure closure_eval(ClosureDiffuse diffuse) Closure closure_eval(ClosureTranslucent translucent) { - /* TODO */ + SELECT_CLOSURE(g_translucent_data, g_translucent_rand, translucent); return Closure(0); } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tracing_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tracing_lib.glsl index d71c26d9e30..36526ff6000 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tracing_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tracing_lib.glsl @@ -310,12 +310,10 @@ ShadowRayPunctual shadow_ray_generate_punctual(LightData light, direction = point_on_light_shape - lP; r_is_above_surface = dot(direction, lNg) > 0.0; -#ifdef SSS_TRANSMITTANCE +#ifdef SHADOW_SUBSURFACE if (!r_is_above_surface) { - float dir_len; - vec3 L = normalize_and_get_length(direction, dir_len); /* Skip the object volume. Do not push behind the light. */ - float offset_len = saturate(thickness / dir_len); + float offset_len = saturate(thickness / length(direction)); lP += direction * offset_len; direction *= 1.0 - offset_len; } @@ -341,12 +339,10 @@ ShadowRayPunctual shadow_ray_generate_punctual(LightData light, direction = point_on_light_shape - lP; r_is_above_surface = dot(direction, lNg) > 0.0; -#ifdef SSS_TRANSMITTANCE +#ifdef SHADOW_SUBSURFACE if (!r_is_above_surface) { - float dir_len; - vec3 L = normalize_and_get_length(direction, dir_len); /* Skip the object volume. Do not push behind the light. */ - float offset_len = saturate(thickness / dir_len); + float offset_len = saturate(thickness / length(direction)); lP += direction * offset_len; direction *= 1.0 - offset_len; } @@ -477,7 +473,7 @@ ShadowEvalResult shadow_eval(LightData light, ShadowEvalResult result; result.light_visibilty = saturate(1.0 - surface_hit * safe_rcp(surface_ray_count)); result.light_visibilty = min(result.light_visibilty, - saturate(1.0 - subsurface_hit * safe_rcp(surface_ray_count))); + saturate(1.0 - subsurface_hit * safe_rcp(subsurface_ray_count))); result.occluder_distance = 0.0; /* Unused. Could reintroduced if needed. */ return result; } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_subsurface_setup_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_subsurface_setup_comp.glsl index 5aeb200b859..d7fb28df892 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_subsurface_setup_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_subsurface_setup_comp.glsl @@ -25,7 +25,7 @@ void main(void) GBufferData gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_color_tx, texel); - if (gbuf.has_diffuse && gbuf.diffuse.sss_id != 0u) { + if (gbuf.has_sss) { vec3 radiance = imageLoad(direct_light_img, texel).rgb + imageLoad(indirect_light_img, texel).rgb; diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl index 09c6f240261..09a73feba00 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_deferred_frag.glsl @@ -82,8 +82,12 @@ void main() /* ----- GBuffer output ----- */ - GBufferDataPacked gbuf = gbuffer_pack( - g_diffuse_data, g_reflection_data, g_refraction_data, out_normal, thickness); + GBufferDataPacked gbuf = gbuffer_pack(g_diffuse_data, + g_translucent_data, + g_reflection_data, + g_refraction_data, + out_normal, + thickness); /* Output header and first closure using frame-buffer attachment. */ out_gbuf_header = gbuf.header; diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl index 2ae72f0f514..c200d780c4f 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl @@ -9,63 +9,26 @@ */ #pragma BLENDER_REQUIRE(draw_view_lib.glsl) -#pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl) -#pragma BLENDER_REQUIRE(eevee_lightprobe_eval_lib.glsl) #pragma BLENDER_REQUIRE(eevee_ambient_occlusion_lib.glsl) #pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl) #pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl) #pragma BLENDER_REQUIRE(eevee_surf_lib.glsl) -#pragma BLENDER_REQUIRE(eevee_subsurface_lib.glsl) #pragma BLENDER_REQUIRE(eevee_volume_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_forward_lib.glsl) #pragma BLENDER_REQUIRE(common_hair_lib.glsl) -vec4 closure_to_rgba(Closure cl) +/* Global thickness because it is needed for closure_to_rgba. */ +float g_thickness; + +vec4 closure_to_rgba(Closure cl_unused) { - vec3 diffuse_light = vec3(0.0); - vec3 reflection_light = vec3(0.0); - vec3 refraction_light = vec3(0.0); - float shadow = 1.0; - - float vPz = dot(drw_view_forward(), g_data.P) - dot(drw_view_forward(), drw_view_position()); - vec3 V = drw_world_incident_vector(g_data.P); - - ClosureLightStack stack; - - ClosureLight cl_diff; - cl_diff.N = g_diffuse_data.N; - cl_diff.ltc_mat = LTC_LAMBERT_MAT; - cl_diff.type = LIGHT_DIFFUSE; - stack.cl[0] = cl_diff; - - ClosureLight cl_refl; - cl_refl.N = g_reflection_data.N; - cl_refl.ltc_mat = LTC_GGX_MAT(dot(g_reflection_data.N, V), g_reflection_data.roughness); - cl_refl.type = LIGHT_SPECULAR; - stack.cl[1] = cl_refl; - - float thickness = 0.01; /* TODO(fclem) thickness. */ - light_eval(stack, g_data.P, g_data.Ng, V, vPz, thickness); - - vec2 noise_probe = interlieved_gradient_noise(gl_FragCoord.xy, vec2(0, 1), vec2(0.0)); - LightProbeSample samp = lightprobe_load(g_data.P, g_data.Ng, V); - - diffuse_light += stack.cl[0].light_shadowed; - diffuse_light += lightprobe_eval(samp, g_diffuse_data, g_data.P, V, noise_probe); - - reflection_light += stack.cl[1].light_shadowed; - reflection_light += lightprobe_eval(samp, g_reflection_data, g_data.P, V, noise_probe); - - vec4 out_color; - out_color.rgb = g_emission; - out_color.rgb += g_diffuse_data.color * g_diffuse_data.weight * diffuse_light; - out_color.rgb += g_reflection_data.color * g_reflection_data.weight * reflection_light; - - out_color.a = saturate(1.0 - average(g_transmittance)); + vec3 radiance, transmittance; + forward_lighting_eval(g_thickness, radiance, transmittance); /* Reset for the next closure tree. */ closure_weights_reset(); - return out_color; + return vec4(radiance, saturate(1.0 - average(transmittance))); } void main() @@ -80,124 +43,25 @@ void main() fragment_displacement(); + g_thickness = max(0.0, nodetree_thickness()); + nodetree_surface(); - g_holdout = saturate(g_holdout); + vec3 radiance, transmittance; + forward_lighting_eval(g_thickness, radiance, transmittance); - float thickness = nodetree_thickness(); - - float vPz = dot(drw_view_forward(), g_data.P) - dot(drw_view_forward(), drw_view_position()); - vec3 V = drw_world_incident_vector(g_data.P); - - ClosureLightStack stack; - - ClosureLight cl_diff; - cl_diff.N = g_diffuse_data.N; - cl_diff.ltc_mat = LTC_LAMBERT_MAT; - cl_diff.type = LIGHT_DIFFUSE; - stack.cl[0] = cl_diff; - - ClosureLight cl_refl; - cl_refl.N = g_reflection_data.N; - cl_refl.ltc_mat = LTC_GGX_MAT(dot(g_reflection_data.N, V), g_reflection_data.roughness); - cl_refl.type = LIGHT_SPECULAR; - stack.cl[1] = cl_refl; - -#ifdef SSS_TRANSMITTANCE - ClosureLight cl_sss; - cl_sss.N = -g_diffuse_data.N; - cl_sss.ltc_mat = LTC_LAMBERT_MAT; - cl_sss.type = LIGHT_DIFFUSE; - stack.cl[2] = cl_sss; -#endif - - light_eval(stack, g_data.P, g_data.Ng, V, vPz, thickness); - - vec3 diffuse_light = stack.cl[0].light_shadowed; - vec3 reflection_light = stack.cl[1].light_shadowed; - vec3 refraction_light = vec3(0.0); -#ifdef SSS_TRANSMITTANCE - diffuse_light += stack.cl[2].light_shadowed; -#endif - - vec2 noise_probe = interlieved_gradient_noise(gl_FragCoord.xy, vec2(0, 1), vec2(0.0)); - LightProbeSample samp = lightprobe_load(g_data.P, g_data.Ng, V); - - diffuse_light += lightprobe_eval(samp, g_diffuse_data, g_data.P, V, noise_probe); - reflection_light += lightprobe_eval(samp, g_reflection_data, g_data.P, V, noise_probe); - - g_diffuse_data.color *= g_diffuse_data.weight; - g_reflection_data.color *= g_reflection_data.weight; - g_refraction_data.color *= g_refraction_data.weight; - diffuse_light *= step(1e-5, g_diffuse_data.weight); - reflection_light *= step(1e-5, g_reflection_data.weight); - refraction_light *= step(1e-5, g_refraction_data.weight); - - out_radiance.rgb = g_emission; - out_radiance.rgb += g_diffuse_data.color * diffuse_light; - out_radiance.rgb += g_reflection_data.color * reflection_light; - out_radiance.rgb += g_refraction_data.color * refraction_light; - out_radiance.a = 0.0; - - vec3 specular_light = reflection_light + refraction_light; - vec3 specular_color = g_reflection_data.color + g_refraction_data.color; - - /* TODO(fclem): This feels way too complex for what is it. */ - bool has_any_bsdf_weight = g_diffuse_data.weight != 0.0 || g_reflection_data.weight != 0.0 || - g_refraction_data.weight != 0.0; - vec3 out_normal = has_any_bsdf_weight ? vec3(0.0) : g_data.N; - out_normal += g_diffuse_data.N * g_diffuse_data.weight; - out_normal += g_reflection_data.N * g_reflection_data.weight; - out_normal += g_refraction_data.N * g_refraction_data.weight; - out_normal = safe_normalize(out_normal); - -#ifdef MAT_RENDER_PASS_SUPPORT - ivec2 out_texel = ivec2(gl_FragCoord.xy); - if (imageSize(rp_cryptomatte_img).x > 1) { - vec4 cryptomatte_output = vec4( - cryptomatte_object_buf[resource_id], node_tree.crypto_hash, 0.0); - imageStore(rp_cryptomatte_img, out_texel, cryptomatte_output); - } - - vec3 radiance_shadowed = stack.cl[0].light_shadowed; - vec3 radiance_unshadowed = stack.cl[0].light_unshadowed; - radiance_shadowed += stack.cl[1].light_shadowed; - radiance_unshadowed += stack.cl[1].light_unshadowed; -# ifdef SSS_TRANSMITTANCE - radiance_shadowed += stack.cl[2].light_shadowed; - radiance_unshadowed += stack.cl[2].light_unshadowed; -# endif - - vec3 shadows = radiance_shadowed / safe_rcp(radiance_unshadowed); - - output_renderpass_color(uniform_buf.render_pass.normal_id, vec4(out_normal, 1.0)); - output_renderpass_color(uniform_buf.render_pass.position_id, vec4(g_data.P, 1.0)); - output_renderpass_color(uniform_buf.render_pass.diffuse_color_id, - vec4(g_diffuse_data.color, 1.0)); - output_renderpass_color(uniform_buf.render_pass.diffuse_light_id, vec4(diffuse_light, 1.0)); - output_renderpass_color(uniform_buf.render_pass.specular_color_id, vec4(specular_color, 1.0)); - output_renderpass_color(uniform_buf.render_pass.specular_light_id, vec4(specular_light, 1.0)); - output_renderpass_color(uniform_buf.render_pass.emission_id, vec4(g_emission, 1.0)); - output_renderpass_value(uniform_buf.render_pass.shadow_id, average(shadows)); - /** NOTE: AO is done on its own pass. */ -#endif - -#ifdef MAT_TRANSPARENT /* Volumetric resolve and compositing. */ vec2 uvs = gl_FragCoord.xy * uniform_buf.volumes.viewport_size_inv; VolumeResolveSample vol = volume_resolve( vec3(uvs, gl_FragCoord.z), volume_transmittance_tx, volume_scattering_tx); - /* Removes the part of the volume scattering that has * already been added to the destination pixels by the opaque resolve. * Since we do that using the blending pipeline we need to account for material transmittance. */ vol.scattering -= vol.scattering * g_transmittance; + radiance = radiance * vol.transmittance + vol.scattering; - out_radiance.rgb = out_radiance.rgb * vol.transmittance + vol.scattering; -#endif + radiance *= 1.0 - saturate(g_holdout); - out_radiance.rgb *= 1.0 - g_holdout; - - out_transmittance.rgb = g_transmittance; - out_transmittance.a = saturate(average(g_transmittance)); + out_radiance = vec4(radiance, 0.0); + out_transmittance = vec4(transmittance, saturate(average(transmittance))); } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_hybrid_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_hybrid_frag.glsl index 60446715b7b..0b7e1aa3df3 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_hybrid_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_hybrid_frag.glsl @@ -14,58 +14,22 @@ #pragma BLENDER_REQUIRE(common_hair_lib.glsl) #pragma BLENDER_REQUIRE(eevee_ambient_occlusion_lib.glsl) #pragma BLENDER_REQUIRE(eevee_surf_lib.glsl) -#pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl) -#pragma BLENDER_REQUIRE(eevee_lightprobe_eval_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_forward_lib.glsl) #pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl) #pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl) -vec4 closure_to_rgba(Closure cl) +/* Global thickness because it is needed for closure_to_rgba. */ +float g_thickness; + +vec4 closure_to_rgba(Closure cl_unused) { - vec3 diffuse_light = vec3(0.0); - vec3 reflection_light = vec3(0.0); - vec3 refraction_light = vec3(0.0); - float shadow = 1.0; - - float vPz = dot(drw_view_forward(), g_data.P) - dot(drw_view_forward(), drw_view_position()); - vec3 V = drw_world_incident_vector(g_data.P); - - ClosureLightStack stack; - - ClosureLight cl_diff; - cl_diff.N = g_diffuse_data.N; - cl_diff.ltc_mat = LTC_LAMBERT_MAT; - cl_diff.type = LIGHT_DIFFUSE; - stack.cl[0] = cl_diff; - - ClosureLight cl_refl; - cl_refl.N = g_reflection_data.N; - cl_refl.ltc_mat = LTC_GGX_MAT(dot(g_reflection_data.N, V), g_reflection_data.roughness); - cl_refl.type = LIGHT_SPECULAR; - stack.cl[1] = cl_refl; - - float thickness = 0.01; /* TODO(fclem) thickness. */ - light_eval(stack, g_data.P, g_data.Ng, V, vPz, thickness); - - vec2 noise_probe = interlieved_gradient_noise(gl_FragCoord.xy, vec2(0, 1), vec2(0.0)); - LightProbeSample samp = lightprobe_load(g_data.P, g_data.Ng, V); - - diffuse_light += stack.cl[0].light_shadowed; - diffuse_light += lightprobe_eval(samp, g_diffuse_data, g_data.P, V, noise_probe); - - reflection_light += stack.cl[1].light_shadowed; - reflection_light += lightprobe_eval(samp, g_reflection_data, g_data.P, V, noise_probe); - - vec4 out_color; - out_color.rgb = g_emission; - out_color.rgb += g_diffuse_data.color * g_diffuse_data.weight * diffuse_light; - out_color.rgb += g_reflection_data.color * g_reflection_data.weight * reflection_light; - - out_color.a = saturate(1.0 - average(g_transmittance)); + vec3 radiance, transmittance; + forward_lighting_eval(g_thickness, radiance, transmittance); /* Reset for the next closure tree. */ closure_weights_reset(); - return out_color; + return vec4(radiance, saturate(1.0 - average(transmittance))); } void main() @@ -84,7 +48,7 @@ void main() g_holdout = saturate(g_holdout); - float thickness = nodetree_thickness(); + g_thickness = max(0.0, nodetree_thickness()); g_diffuse_data.color *= g_diffuse_data.weight; g_reflection_data.color *= g_reflection_data.weight; @@ -121,8 +85,12 @@ void main() /* ----- GBuffer output ----- */ - GBufferDataPacked gbuf = gbuffer_pack( - g_diffuse_data, g_reflection_data, g_refraction_data, out_normal, thickness); + GBufferDataPacked gbuf = gbuffer_pack(g_diffuse_data, + g_translucent_data, + g_reflection_data, + g_refraction_data, + out_normal, + g_thickness); /* Output header and first closure using frame-buffer attachment. */ out_gbuf_header = gbuf.header; diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh index 71ed5fc87e2..f5e6861ce77 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh @@ -85,7 +85,8 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_light_double) GPU_SHADER_CREATE_INFO(eevee_deferred_light_triple) .additional_info("eevee_deferred_light") - .define("SSS_TRANSMITTANCE") + .define("SHADOW_SUBSURFACE") + .define("MAT_SUBSURFACE") .define("LIGHT_CLOSURE_EVAL_COUNT", "3") .do_static_compilation(true); @@ -112,7 +113,7 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_capture_eval) .early_fragment_test(true) /* Inputs. */ .fragment_out(0, Type::VEC4, "out_radiance") - .define("SSS_TRANSMITTANCE") + .define("SHADOW_SUBSURFACE") .additional_info("eevee_shared", "eevee_gbuffer_data", "eevee_utility_texture", @@ -132,7 +133,7 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_planar_eval) /* Inputs. */ .fragment_out(0, Type::VEC4, "out_radiance") .define("REFLECTION_PROBE") - .define("SSS_TRANSMITTANCE") + .define("SHADOW_SUBSURFACE") .define("LIGHT_CLOSURE_EVAL_COUNT", "2") .additional_info("eevee_shared", "eevee_gbuffer_data", diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh index 2bcd5ba7667..b1b96cc62f4 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh @@ -175,7 +175,6 @@ GPU_SHADER_CREATE_INFO(eevee_surf_deferred) GPU_SHADER_CREATE_INFO(eevee_surf_deferred_hybrid) .fragment_source("eevee_surf_hybrid_frag.glsl") - .define("LIGHT_CLOSURE_EVAL_COUNT", "2") .additional_info("eevee_surf_deferred_base", "eevee_light_data", "eevee_lightprobe_data", @@ -189,7 +188,6 @@ GPU_SHADER_CREATE_INFO(eevee_surf_forward) .fragment_out(0, Type::VEC4, "out_radiance", DualBlend::SRC_0) .fragment_out(0, Type::VEC4, "out_transmittance", DualBlend::SRC_1) .fragment_source("eevee_surf_forward_frag.glsl") - .define("LIGHT_CLOSURE_EVAL_COUNT", "3") .additional_info("eevee_global_ubo", "eevee_light_data", "eevee_lightprobe_data", diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index a2615cd6927..45115bf6c95 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -79,12 +79,13 @@ typedef enum eGPUMaterialFlag { GPU_MATFLAG_SHADER_TO_RGBA = (1 << 7), GPU_MATFLAG_AO = (1 << 8), GPU_MATFLAG_COAT = (1 << 9), + GPU_MATFLAG_TRANSLUCENT = (1 << 10), - GPU_MATFLAG_VOLUME_SCATTER = (1 << 10), - GPU_MATFLAG_VOLUME_ABSORPTION = (1 << 11), + GPU_MATFLAG_VOLUME_SCATTER = (1 << 16), + GPU_MATFLAG_VOLUME_ABSORPTION = (1 << 17), - GPU_MATFLAG_OBJECT_INFO = (1 << 12), - GPU_MATFLAG_AOV = (1 << 13), + GPU_MATFLAG_OBJECT_INFO = (1 << 18), + GPU_MATFLAG_AOV = (1 << 19), GPU_MATFLAG_BARYCENTRIC = (1 << 20), diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl index 801f921be1a..f7829443efc 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl @@ -10,7 +10,7 @@ void node_bsdf_translucent(vec4 color, vec3 N, float weight, out Closure result) ClosureTranslucent translucent_data; translucent_data.weight = weight; translucent_data.color = color.rgb; - translucent_data.N = -N; + translucent_data.N = N; result = closure_eval(translucent_data); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc index add64251ace..3857f8175f9 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc @@ -24,7 +24,7 @@ static int node_shader_gpu_bsdf_translucent(GPUMaterial *mat, GPU_link(mat, "world_normals_get", &in[1].link); } - GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE); + GPU_material_flag_set(mat, GPU_MATFLAG_TRANSLUCENT); return GPU_stack_link(mat, node, "node_bsdf_translucent", in, out); }