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); }