diff options
Diffstat (limited to 'source/blender/draw')
22 files changed, 959 insertions, 716 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index e52e30a6c44..8abd353d36d 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -197,7 +197,6 @@ set(LIB data_to_c_simple(engines/eevee/shaders/ambient_occlusion_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/background_vert.glsl SRC) -data_to_c_simple(engines/eevee/shaders/closure_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/common_uniforms_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/common_utiltex_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/lights_lib.glsl SRC) @@ -215,7 +214,12 @@ data_to_c_simple(engines/eevee/shaders/lightprobe_grid_fill_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_planar_display_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/lightprobe_planar_display_vert.glsl SRC) data_to_c_simple(engines/eevee/shaders/lookdev_world_frag.glsl SRC) -data_to_c_simple(engines/eevee/shaders/closure_lit_lib.glsl SRC) +data_to_c_simple(engines/eevee/shaders/closure_eval_lib.glsl SRC) +data_to_c_simple(engines/eevee/shaders/closure_eval_diffuse_lib.glsl SRC) +data_to_c_simple(engines/eevee/shaders/closure_eval_glossy_lib.glsl SRC) +data_to_c_simple(engines/eevee/shaders/closure_eval_refraction_lib.glsl SRC) +data_to_c_simple(engines/eevee/shaders/closure_eval_translucent_lib.glsl SRC) +data_to_c_simple(engines/eevee/shaders/closure_type_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_bloom_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_dof_bokeh_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_dof_dilate_tiles_frag.glsl SRC) diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 1465c9dd84c..db5c86dc5e1 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -191,6 +191,12 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_shgroup_uniform_texture_ref(grp, "hitBuffer", &effects->ssr_hit_output); DRW_shgroup_uniform_texture_ref(grp, "pdfBuffer", &effects->ssr_pdf_output); DRW_shgroup_uniform_texture_ref(grp, "prevColorBuffer", &txl->color_double_buffer); + DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); + DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool); + DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); + DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo); DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); @@ -198,7 +204,6 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); DRW_shgroup_uniform_int(grp, "neighborOffset", &effects->ssr_neighbor_ofs, 1); if ((effects->enabled_effects & EFFECT_GTAO) != 0) { - DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons); } diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c index ec058afd58e..64efca83915 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders.c +++ b/source/blender/draw/engines/eevee/eevee_shaders.c @@ -149,7 +149,6 @@ static struct { struct GPUShader *volumetric_accum_sh; /* Shader strings */ - char *closure_lit_lib; char *surface_lit_frag; char *surface_prepass_frag; char *surface_geom_barycentric; @@ -191,7 +190,7 @@ extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_lut_frag_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_btdf_lut_frag_glsl[]; -extern char datatoc_closure_lib_glsl[]; +extern char datatoc_closure_type_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_common_utiltex_lib_glsl[]; extern char datatoc_cryptomatte_frag_glsl[]; @@ -241,7 +240,11 @@ extern char datatoc_lightprobe_planar_downsample_geom_glsl[]; extern char datatoc_lightprobe_planar_downsample_vert_glsl[]; extern char datatoc_lightprobe_vert_glsl[]; extern char datatoc_lights_lib_glsl[]; -extern char datatoc_closure_lit_lib_glsl[]; +extern char datatoc_closure_eval_lib_glsl[]; +extern char datatoc_closure_eval_diffuse_lib_glsl[]; +extern char datatoc_closure_eval_glossy_lib_glsl[]; +extern char datatoc_closure_eval_refraction_lib_glsl[]; +extern char datatoc_closure_eval_translucent_lib_glsl[]; extern char datatoc_ltc_lib_glsl[]; extern char datatoc_object_motion_frag_glsl[]; extern char datatoc_object_motion_vert_glsl[]; @@ -296,24 +299,14 @@ static void eevee_shader_library_ensure(void) DRW_SHADER_LIB_ADD(e_data.lib, lights_lib); DRW_SHADER_LIB_ADD(e_data.lib, surface_lib); DRW_SHADER_LIB_ADD(e_data.lib, volumetric_lib); - DRW_SHADER_LIB_ADD(e_data.lib, closure_lib); DRW_SHADER_LIB_ADD(e_data.lib, ssr_lib); DRW_SHADER_LIB_ADD(e_data.lib, effect_dof_lib); - - /* Add one for each Closure */ - e_data.closure_lit_lib = BLI_string_joinN(datatoc_closure_lit_lib_glsl, - datatoc_closure_lit_lib_glsl, - datatoc_closure_lit_lib_glsl, - datatoc_closure_lit_lib_glsl, - datatoc_closure_lit_lib_glsl, - datatoc_closure_lit_lib_glsl, - datatoc_closure_lit_lib_glsl, - datatoc_closure_lit_lib_glsl, - datatoc_closure_lit_lib_glsl, - datatoc_closure_lit_lib_glsl, - datatoc_closure_lit_lib_glsl); - - DRW_shader_library_add_file(e_data.lib, e_data.closure_lit_lib, "closure_lit_lib.glsl"); + DRW_SHADER_LIB_ADD(e_data.lib, closure_type_lib); + DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_lib); + DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_diffuse_lib); + DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_glossy_lib); + DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_translucent_lib); + DRW_SHADER_LIB_ADD(e_data.lib, closure_eval_refraction_lib); e_data.surface_lit_frag = DRW_shader_library_create_shader_string(e_data.lib, datatoc_surface_frag_glsl); @@ -1545,7 +1538,6 @@ struct GPUMaterial *EEVEE_material_get( void EEVEE_shaders_free(void) { - MEM_SAFE_FREE(e_data.closure_lit_lib); MEM_SAFE_FREE(e_data.surface_prepass_frag); MEM_SAFE_FREE(e_data.surface_lit_frag); MEM_SAFE_FREE(e_data.surface_geom_barycentric); diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl index 2f6f8327f58..7c0ae3881d7 100644 --- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl @@ -191,15 +191,15 @@ void gtao_deferred( dirs.xy = get_ao_dir(noise.x * 0.5); dirs.zw = get_ao_dir(noise.x * 0.5 + 0.5); - bent_normal = normal * 1e-8; - visibility = 1e-8; + bent_normal = vec3(0.0); + visibility = 0.0; horizons = unpack_horizons(horizons); integrate_slice(normal, dirs.xy, horizons.xy, visibility, bent_normal); integrate_slice(normal, dirs.zw, horizons.zw, visibility, bent_normal); - bent_normal = normalize(bent_normal / visibility); + bent_normal = safe_normalize(bent_normal); visibility *= 0.5; /* We integrated 2 slices. */ } @@ -240,13 +240,24 @@ float gtao_multibounce(float visibility, vec3 albedo) return max(x, ((x * a + b) * x + c) * x); } +float diffuse_occlusion(vec3 N, vec3 vis_cone_dir, float vis_cone_aperture_cos, vec3 albedo) +{ + if ((int(aoSettings) & USE_AO) == 0) { + return 1.0; + } + /* If the shading normal is orthogonal to the geometric normal, it should be half lit. */ + float horizon_fac = saturate(dot(N, vis_cone_dir) * 0.5 + 0.5); + float ao = vis_cone_aperture_cos * horizon_fac; + return gtao_multibounce(ao, albedo); +} + float specular_occlusion(float NV, float AO, float roughness) { return saturate(pow(NV + AO, roughness) - 1.0 + AO); } /* Use the right occlusion */ -float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out vec3 bent_normal) +float occlusion_compute(vec3 N, vec3 vpos, vec4 rand, out vec3 bent_normal) { #ifndef USE_REFRACTION if ((int(aoSettings) & USE_AO) != 0) { @@ -263,10 +274,6 @@ float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out visibility = max(1e-3, visibility); if ((int(aoSettings) & USE_BENT_NORMAL) != 0) { - /* The bent normal will show the facet look of the mesh. Try to minimize this. */ - float mix_fac = visibility * visibility * visibility; - bent_normal = normalize(mix(bent_normal, vnor, mix_fac)); - bent_normal = transform_direction(ViewMatrixInverse, bent_normal); } else { @@ -276,10 +283,10 @@ float occlusion_compute(vec3 N, vec3 vpos, float user_occlusion, vec4 rand, out /* Scale by user factor */ visibility = pow(visibility, aoFactor); - return min(visibility, user_occlusion); + return visibility; } #endif bent_normal = N; - return user_occlusion; + return 1.0; } diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index 3560ae62a84..f050cf3a08a 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -1,6 +1,15 @@ #pragma BLENDER_REQUIRE(common_math_lib.glsl) +vec3 diffuse_dominant_dir(vec3 N, vec3 vis_cone_dir, float vis_cone_aperture_cos) +{ + /* TODO(fclem) revisit this. bent too much towards vis_cone_dir. */ + vis_cone_aperture_cos *= sqr(vis_cone_aperture_cos); + + N = mix(vis_cone_dir, N, vis_cone_aperture_cos); + return normalize(N); +} + vec3 specular_dominant_dir(vec3 N, vec3 V, float roughness) { vec3 R = -reflect(V, N); @@ -79,7 +88,7 @@ vec3 F_brdf_single_scatter(vec3 f0, vec3 f90, vec2 lut) { /* Unreal specular matching : if specular color is below 2% intensity, * treat as shadowning */ - return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * lut.y * abs(f90) + lut.x * f0; + return lut.y * f90 + lut.x * f0; } /* Multi-scattering brdf approximation from : @@ -87,11 +96,7 @@ vec3 F_brdf_single_scatter(vec3 f0, vec3 f90, vec2 lut) * by Carmelo J. Fdez-Agüera. */ vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut) { - vec3 FssEss = F_brdf_single_scatter(f0, f90, lut); - /* Hack to avoid many more shader variations. */ - if (f90.g < 0.0) { - return FssEss; - } + vec3 FssEss = lut.y * f90 + lut.x * f0; float Ess = lut.x + lut.y; float Ems = 1.0 - Ess; @@ -102,8 +107,6 @@ vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut) return FssEss + Fms * Ems; } -#define F_brdf(f0, f90, lut) F_brdf_multi_scatter(f0, f90, lut) - /* GGX */ float D_ggx_opti(float NH, float a2) { diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl new file mode 100644 index 00000000000..1e65d3ccb87 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_diffuse_lib.glsl @@ -0,0 +1,85 @@ +#pragma BLENDER_REQUIRE(lights_lib.glsl) +#pragma BLENDER_REQUIRE(lightprobe_lib.glsl) +#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl) + +struct ClosureInputDiffuse { + vec3 N; /** Shading normal. */ + vec3 albedo; /** Used for multibounce GTAO approximation. Not applied to final radiance. */ +}; + +#define CLOSURE_INPUT_Diffuse_DEFAULT ClosureInputDiffuse(vec3(0.0), vec3(0.0)) + +struct ClosureEvalDiffuse { + vec3 probe_sampling_dir; /** Direction to sample probes from. */ + float ambient_occlusion; /** Final occlusion for distant lighting. */ +}; + +/* Stubs. */ +#define ClosureOutputDiffuse ClosureOutput +#define closure_Diffuse_planar_eval(cl_in, cl_eval, cl_common, data, cl_out) +#define closure_Diffuse_cubemap_eval(cl_in, cl_eval, cl_common, data, cl_out) + +ClosureEvalDiffuse closure_Diffuse_eval_init(inout ClosureInputDiffuse cl_in, + ClosureEvalCommon cl_common, + out ClosureOutputDiffuse cl_out) +{ + cl_in.N = safe_normalize(cl_in.N); + cl_out.radiance = vec3(0.0); + + ClosureEvalDiffuse cl_eval; + cl_eval.ambient_occlusion = diffuse_occlusion( + cl_in.N, cl_common.bent_normal, cl_common.occlusion, cl_in.albedo); + cl_eval.probe_sampling_dir = diffuse_dominant_dir( + cl_in.N, cl_common.bent_normal, cl_common.occlusion); + return cl_eval; +} + +void closure_Diffuse_light_eval(ClosureInputDiffuse cl_in, + ClosureEvalDiffuse cl_eval, + ClosureEvalCommon cl_common, + ClosureLightData light, + inout ClosureOutputDiffuse cl_out) +{ + float radiance = light_diffuse(light.data, cl_in.N, cl_common.V, light.L); + /* TODO(fclem) We could try to shadow lights that are shadowless with the ambient_occlusion + * factor here. */ + cl_out.radiance += light.data.l_color * (light.vis * light.contact_shadow * radiance); +} + +void closure_Diffuse_grid_eval(ClosureInputDiffuse cl_in, + ClosureEvalDiffuse cl_eval, + ClosureEvalCommon cl_common, + ClosureGridData grid, + inout ClosureOutputDiffuse cl_out) +{ + vec3 probe_radiance = probe_evaluate_grid( + grid.data, cl_common.P, cl_eval.probe_sampling_dir, grid.local_pos); + cl_out.radiance += grid.attenuation * probe_radiance; +} + +void closure_Diffuse_indirect_end(ClosureInputDiffuse cl_in, + ClosureEvalDiffuse cl_eval, + ClosureEvalCommon cl_common, + inout ClosureOutputDiffuse cl_out) +{ + /* If not enough light has been accumulated from probes, use the world specular cubemap + * to fill the remaining energy needed. */ + if (cl_common.diffuse_accum > 0.0) { + vec3 probe_radiance = probe_evaluate_world_diff(cl_eval.probe_sampling_dir); + cl_out.radiance += cl_common.diffuse_accum * probe_radiance; + } + /* Apply occlusion on radiance before the light loop. */ + cl_out.radiance *= cl_eval.ambient_occlusion; +} + +void closure_Diffuse_eval_end(ClosureInputDiffuse cl_in, + ClosureEvalDiffuse cl_eval, + ClosureEvalCommon cl_common, + inout ClosureOutputDiffuse cl_out) +{ +#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND) + /* This makes shader resources become unused and avoid issues with samplers. (see T59747) */ + cl_out.radiance = vec3(0.0); + return; +#endif +} diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl new file mode 100644 index 00000000000..9d539ec5a48 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl @@ -0,0 +1,136 @@ + +#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl) +#pragma BLENDER_REQUIRE(lights_lib.glsl) +#pragma BLENDER_REQUIRE(lightprobe_lib.glsl) +#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl) + +struct ClosureInputGlossy { + vec3 N; /** Shading normal. */ + float roughness; /** Input roughness, not squared. */ +}; + +#define CLOSURE_INPUT_Glossy_DEFAULT ClosureInputGlossy(vec3(0.0), 0.0) + +struct ClosureEvalGlossy { + vec4 ltc_mat; /** LTC matrix values. */ + float ltc_brdf_scale; /** LTC BRDF scaling. */ + vec3 probe_sampling_dir; /** Direction to sample probes from. */ + float spec_occlusion; /** Specular Occlusion. */ + vec3 raytrace_radiance; /** Raytrace reflection to be accumulated after occlusion. */ +}; + +/* Stubs. */ +#define ClosureOutputGlossy ClosureOutput +#define closure_Glossy_grid_eval(cl_in, cl_eval, cl_common, data, cl_out) + +#ifdef STEP_RESOLVE /* SSR */ +/* Prototype. */ +void raytrace_resolve(ClosureInputGlossy cl_in, + inout ClosureEvalGlossy cl_eval, + inout ClosureEvalCommon cl_common, + inout ClosureOutputGlossy cl_out); +#endif + +ClosureEvalGlossy closure_Glossy_eval_init(inout ClosureInputGlossy cl_in, + inout ClosureEvalCommon cl_common, + out ClosureOutputGlossy cl_out) +{ + cl_in.N = safe_normalize(cl_in.N); + cl_in.roughness = clamp(cl_in.roughness, 1e-8, 0.9999); + cl_out.radiance = vec3(0.0); + + float NV = dot(cl_in.N, cl_common.V); + vec2 lut_uv = lut_coords_ltc(NV, cl_in.roughness); + + ClosureEvalGlossy cl_eval; + cl_eval.ltc_mat = texture(utilTex, vec3(lut_uv, LTC_MAT_LAYER)); + cl_eval.probe_sampling_dir = specular_dominant_dir(cl_in.N, cl_common.V, sqr(cl_in.roughness)); + cl_eval.spec_occlusion = specular_occlusion(NV, cl_common.occlusion, cl_in.roughness); + cl_eval.raytrace_radiance = vec3(0.0); + +#ifdef STEP_RESOLVE /* SSR */ + raytrace_resolve(cl_in, cl_eval, cl_common, cl_out); +#endif + + /* The brdf split sum LUT is applied after the radiance accumulation. + * Correct the LTC so that its energy is constant. */ + /* TODO(fclem) Optimize this so that only one scale factor is stored. */ + vec4 ltc_brdf = texture(utilTex, vec3(lut_uv, LTC_BRDF_LAYER)).barg; + vec2 split_sum_brdf = ltc_brdf.zw; + cl_eval.ltc_brdf_scale = (ltc_brdf.x + ltc_brdf.y) / (split_sum_brdf.x + split_sum_brdf.y); + return cl_eval; +} + +void closure_Glossy_light_eval(ClosureInputGlossy cl_in, + ClosureEvalGlossy cl_eval, + ClosureEvalCommon cl_common, + ClosureLightData light, + inout ClosureOutputGlossy cl_out) +{ + float radiance = light_specular(light.data, cl_eval.ltc_mat, cl_in.N, cl_common.V, light.L); + radiance *= cl_eval.ltc_brdf_scale; + cl_out.radiance += light.data.l_color * + (light.data.l_spec * light.vis * light.contact_shadow * radiance); +} + +void closure_Glossy_planar_eval(ClosureInputGlossy cl_in, + ClosureEvalGlossy cl_eval, + inout ClosureEvalCommon cl_common, + ClosurePlanarData planar, + inout ClosureOutputGlossy cl_out) +{ +#ifndef STEP_RESOLVE /* SSR already evaluates planar reflections. */ + vec3 probe_radiance = probe_evaluate_planar( + planar.id, planar.data, cl_common.P, cl_in.N, cl_common.V, cl_in.roughness); + cl_out.radiance += planar.attenuation * probe_radiance; +#else + /* HACK: Fix an issue with planar reflections still being counted inside the specular + * accumulator. This only works because we only use one Glossy closure in the resolve pass. */ + cl_common.specular_accum += planar.attenuation; +#endif +} + +void closure_Glossy_cubemap_eval(ClosureInputGlossy cl_in, + ClosureEvalGlossy cl_eval, + ClosureEvalCommon cl_common, + ClosureCubemapData cube, + inout ClosureOutputGlossy cl_out) +{ + vec3 probe_radiance = probe_evaluate_cube( + cube.id, cl_common.P, cl_eval.probe_sampling_dir, cl_in.roughness); + cl_out.radiance += cube.attenuation * probe_radiance; +} + +void closure_Glossy_indirect_end(ClosureInputGlossy cl_in, + ClosureEvalGlossy cl_eval, + ClosureEvalCommon cl_common, + inout ClosureOutputGlossy cl_out) +{ + /* If not enough light has been accumulated from probes, use the world specular cubemap + * to fill the remaining energy needed. */ + if (specToggle && cl_common.specular_accum > 0.0) { + vec3 probe_radiance = probe_evaluate_world_spec(cl_eval.probe_sampling_dir, cl_in.roughness); + cl_out.radiance += cl_common.specular_accum * probe_radiance; + } + + /* Apply occlusion on distant lighting. */ + cl_out.radiance *= cl_eval.spec_occlusion; + /* Apply Raytrace reflections after occlusion since they are direct, local reflections. */ + cl_out.radiance += cl_eval.raytrace_radiance; +} + +void closure_Glossy_eval_end(ClosureInputGlossy cl_in, + ClosureEvalGlossy cl_eval, + ClosureEvalCommon cl_common, + inout ClosureOutputGlossy cl_out) +{ +#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND) + /* This makes shader resources become unused and avoid issues with samplers. (see T59747) */ + cl_out.radiance = vec3(0.0); + return; +#endif + + if (!specToggle) { + cl_out.radiance = vec3(0.0); + } +} diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl new file mode 100644 index 00000000000..b1bb5f96f5c --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl @@ -0,0 +1,316 @@ + +#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl) +#pragma BLENDER_REQUIRE(lights_lib.glsl) +#pragma BLENDER_REQUIRE(lightprobe_lib.glsl) + +/** + * Extensive use of Macros to be able to change the maximum amount of evaluated closure easily. + * NOTE: GLSL does not support variadic macros. + * + * Example + * // Declare the cl_eval function + * CLOSURE_EVAL_FUNCTION_DECLARE_3(name, Diffuse, Glossy, Refraction); + * // Declare the inputs & outputs + * CLOSURE_VARS_DECLARE(Diffuse, Glossy, Refraction); + * // Specify inputs + * in_Diffuse_0.N = N; + * ... + * // Call the cl_eval function + * CLOSURE_EVAL_FUNCTION_3(name, Diffuse, Glossy, Refraction); + * // Get the cl_out + * closure.radiance = out_Diffuse_0.radiance + out_Glossy_1.radiance + out_Refraction_2.radiance; + **/ + +#define CLOSURE_VARS_DECLARE(t0, t1, t2, t3) \ + ClosureInputCommon in_common = CLOSURE_INPUT_COMMON_DEFAULT; \ + ClosureInput##t0 in_##t0##_0 = CLOSURE_INPUT_##t0##_DEFAULT; \ + ClosureInput##t1 in_##t1##_1 = CLOSURE_INPUT_##t1##_DEFAULT; \ + ClosureInput##t2 in_##t2##_2 = CLOSURE_INPUT_##t2##_DEFAULT; \ + ClosureInput##t3 in_##t3##_3 = CLOSURE_INPUT_##t3##_DEFAULT; \ + ClosureOutput##t0 out_##t0##_0; \ + ClosureOutput##t1 out_##t1##_1; \ + ClosureOutput##t2 out_##t2##_2; \ + ClosureOutput##t3 out_##t3##_3; + +#define CLOSURE_EVAL_DECLARE(t0, t1, t2, t3) \ + ClosureEvalCommon cl_common = closure_Common_eval_init(in_common); \ + ClosureEval##t0 eval_##t0##_0 = closure_##t0##_eval_init(in_##t0##_0, cl_common, out_##t0##_0); \ + ClosureEval##t1 eval_##t1##_1 = closure_##t1##_eval_init(in_##t1##_1, cl_common, out_##t1##_1); \ + ClosureEval##t2 eval_##t2##_2 = closure_##t2##_eval_init(in_##t2##_2, cl_common, out_##t2##_2); \ + ClosureEval##t3 eval_##t3##_3 = closure_##t3##_eval_init(in_##t3##_3, cl_common, out_##t3##_3); + +#define CLOSURE_META_SUBROUTINE(subroutine, t0, t1, t2, t3) \ + closure_##t0##_##subroutine(in_##t0##_0, eval_##t0##_0, cl_common, out_##t0##_0); \ + closure_##t1##_##subroutine(in_##t1##_1, eval_##t1##_1, cl_common, out_##t1##_1); \ + closure_##t2##_##subroutine(in_##t2##_2, eval_##t2##_2, cl_common, out_##t2##_2); \ + closure_##t3##_##subroutine(in_##t3##_3, eval_##t3##_3, cl_common, out_##t3##_3); + +#define CLOSURE_META_SUBROUTINE_DATA(subroutine, sub_data, t0, t1, t2, t3) \ + closure_##t0##_##subroutine(in_##t0##_0, eval_##t0##_0, cl_common, sub_data, out_##t0##_0); \ + closure_##t1##_##subroutine(in_##t1##_1, eval_##t1##_1, cl_common, sub_data, out_##t1##_1); \ + closure_##t2##_##subroutine(in_##t2##_2, eval_##t2##_2, cl_common, sub_data, out_##t2##_2); \ + closure_##t3##_##subroutine(in_##t3##_3, eval_##t3##_3, cl_common, sub_data, out_##t3##_3); + +/* Inputs are inout so that callers can get the final inputs used for evaluation. */ +#define CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, t3) \ + void closure_##name##_eval(ClosureInputCommon in_common, \ + inout ClosureInput##t0 in_##t0##_0, \ + inout ClosureInput##t1 in_##t1##_1, \ + inout ClosureInput##t2 in_##t2##_2, \ + inout ClosureInput##t3 in_##t3##_3, \ + out ClosureOutput##t0 out_##t0##_0, \ + out ClosureOutput##t1 out_##t1##_1, \ + out ClosureOutput##t2 out_##t2##_2, \ + out ClosureOutput##t3 out_##t3##_3) \ + { \ + CLOSURE_EVAL_DECLARE(t0, t1, t2, t3); \ +\ + for (int i = 0; cl_common.specular_accum > 0.0 && i < prbNumPlanar && i < MAX_PLANAR; i++) { \ + ClosurePlanarData planar = closure_planar_eval_init(i, cl_common); \ + if (planar.attenuation > 1e-8) { \ + CLOSURE_META_SUBROUTINE_DATA(planar_eval, planar, t0, t1, t2, t3); \ + } \ + } \ +\ + /* Starts at 1 because 0 is world cubemap. */ \ + for (int i = 1; cl_common.specular_accum > 0.0 && i < prbNumRenderCube && i < MAX_PROBE; \ + i++) { \ + ClosureCubemapData cube = closure_cubemap_eval_init(i, cl_common); \ + if (cube.attenuation > 1e-8) { \ + CLOSURE_META_SUBROUTINE_DATA(cubemap_eval, cube, t0, t1, t2, t3); \ + } \ + } \ +\ + /* Starts at 1 because 0 is world irradiance. */ \ + for (int i = 1; cl_common.diffuse_accum > 0.0 && i < prbNumRenderGrid && i < MAX_GRID; i++) { \ + ClosureGridData grid = closure_grid_eval_init(i, cl_common); \ + if (grid.attenuation > 1e-8) { \ + CLOSURE_META_SUBROUTINE_DATA(grid_eval, grid, t0, t1, t2, t3); \ + } \ + } \ +\ + CLOSURE_META_SUBROUTINE(indirect_end, t0, t1, t2, t3); \ +\ + for (int i = 0; i < laNumLight && i < MAX_LIGHT; i++) { \ + ClosureLightData light = closure_light_eval_init(cl_common, i); \ + if (light.vis > 1e-8) { \ + CLOSURE_META_SUBROUTINE_DATA(light_eval, light, t0, t1, t2, t3); \ + } \ + } \ +\ + CLOSURE_META_SUBROUTINE(eval_end, t0, t1, t2, t3); \ + } + +#define CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, t3) \ + closure_##name##_eval(in_common, \ + in_##t0##_0, \ + in_##t1##_1, \ + in_##t2##_2, \ + in_##t3##_3, \ + out_##t0##_0, \ + out_##t1##_1, \ + out_##t2##_2, \ + out_##t3##_3) + +#define CLOSURE_EVAL_FUNCTION_DECLARE_1(name, t0) \ + CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, Dummy, Dummy, Dummy) +#define CLOSURE_EVAL_FUNCTION_DECLARE_2(name, t0, t1) \ + CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, Dummy, Dummy) +#define CLOSURE_EVAL_FUNCTION_DECLARE_3(name, t0, t1, t2) \ + CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, Dummy) +#define CLOSURE_EVAL_FUNCTION_DECLARE_4(name, t0, t1, t2, t3) \ + CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, t3) + +#define CLOSURE_VARS_DECLARE_1(t0) CLOSURE_VARS_DECLARE(t0, Dummy, Dummy, Dummy) +#define CLOSURE_VARS_DECLARE_2(t0, t1) CLOSURE_VARS_DECLARE(t0, t1, Dummy, Dummy) +#define CLOSURE_VARS_DECLARE_3(t0, t1, t2) CLOSURE_VARS_DECLARE(t0, t1, t2, Dummy) +#define CLOSURE_VARS_DECLARE_4(t0, t1, t2, t3) CLOSURE_VARS_DECLARE(t0, t1, t2, t3) + +#define CLOSURE_EVAL_FUNCTION_1(name, t0) CLOSURE_EVAL_FUNCTION(name, t0, Dummy, Dummy, Dummy) +#define CLOSURE_EVAL_FUNCTION_2(name, t0, t1) CLOSURE_EVAL_FUNCTION(name, t0, t1, Dummy, Dummy) +#define CLOSURE_EVAL_FUNCTION_3(name, t0, t1, t2) CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, Dummy) +#define CLOSURE_EVAL_FUNCTION_4(name, t0, t1, t2, t3) CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, t3) + +/* -------------------------------------------------------------------- */ +/** \name Dummy Closure + * + * Dummy closure type that will be optimized out by the compiler. + * \{ */ + +#define ClosureInputDummy ClosureOutput +#define ClosureOutputDummy ClosureOutput +#define ClosureEvalDummy ClosureOutput +#define CLOSURE_EVAL_DUMMY ClosureOutput(vec3(0)) +#define CLOSURE_INPUT_Dummy_DEFAULT CLOSURE_EVAL_DUMMY +#define closure_Dummy_eval_init(cl_in, cl_common, cl_out) CLOSURE_EVAL_DUMMY +#define closure_Dummy_planar_eval(cl_in, cl_eval, cl_common, data, cl_out) +#define closure_Dummy_cubemap_eval(cl_in, cl_eval, cl_common, data, cl_out) +#define closure_Dummy_grid_eval(cl_in, cl_eval, cl_common, data, cl_out) +#define closure_Dummy_indirect_end(cl_in, cl_eval, cl_common, cl_out) +#define closure_Dummy_light_eval(cl_in, cl_eval, cl_common, data, cl_out) +#define closure_Dummy_eval_end(cl_in, cl_eval, cl_common, cl_out) + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Common cl_eval data + * + * Eval data not dependant on input parameters. All might not be used but unused ones + * will be optimized out. + * \{ */ + +struct ClosureInputCommon { + /** Custom occlusion value set by the user. */ + float occlusion; +}; + +#define CLOSURE_INPUT_COMMON_DEFAULT ClosureInputCommon(1.0) + +struct ClosureEvalCommon { + /** View vector. */ + vec3 V; + /** Surface position. */ + vec3 P; + /** Normal vector, always facing camera. */ + vec3 N; + /** Normal vector, always facing camera. (viewspace) */ + vec3 vN; + /** Surface position. (viewspace) */ + vec3 vP; + /** Geometric normal, always facing camera. (viewspace) */ + vec3 vNg; + /** Random numbers. 3 random sequences. zw is a random point on a circle. */ + vec4 rand; + /** Final occlusion factor. Mix of the user occlusion and SSAO. */ + float occlusion; + /** Least occluded direction in the hemisphere. */ + vec3 bent_normal; + + /** Specular probe accumulator. Shared between planar and cubemap probe. */ + float specular_accum; + /** Diffuse probe accumulator. */ + float diffuse_accum; + /** Viewspace depth to start raytracing from. */ + float tracing_depth; +}; + +/* Common cl_out struct used by most closures. */ +struct ClosureOutput { + vec3 radiance; +}; + +ClosureEvalCommon closure_Common_eval_init(ClosureInputCommon cl_in) +{ + ClosureEvalCommon cl_eval; + cl_eval.rand = texelfetch_noise_tex(gl_FragCoord.xy); + cl_eval.V = cameraVec; + cl_eval.P = worldPosition; + cl_eval.N = safe_normalize(gl_FrontFacing ? worldNormal : -worldNormal); + cl_eval.vN = safe_normalize(gl_FrontFacing ? viewNormal : -viewNormal); + cl_eval.vP = viewPosition; + cl_eval.vNg = safe_normalize(cross(dFdx(viewPosition), dFdy(viewPosition))); + /* TODO(fclem) See if we can avoid this complicated setup. */ + cl_eval.tracing_depth = gl_FragCoord.z; + /* Constant bias (due to depth buffer precision) */ + /* Magic numbers for 24bits of precision. + * From http://terathon.com/gdc07_lengyel.pdf (slide 26) */ + cl_eval.tracing_depth -= mix(2.4e-7, 4.8e-7, gl_FragCoord.z); + /* Convert to view Z. */ + cl_eval.tracing_depth = get_view_z_from_depth(cl_eval.tracing_depth); + + /* TODO(fclem) Do occlusion evaluation per Closure using shading normal. */ + cl_eval.occlusion = min( + cl_in.occlusion, + occlusion_compute(cl_eval.N, cl_eval.vP, cl_eval.rand, cl_eval.bent_normal)); + + cl_eval.specular_accum = 1.0; + cl_eval.diffuse_accum = 1.0; + return cl_eval; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loop data + * + * Loop datas are conveniently packed into struct to make it future proof. + * \{ */ + +struct ClosureLightData { + LightData data; /** Light Data. */ + vec4 L; /** Non-Normalized Light Vector (surface to light) with length in W component. */ + float vis; /** Light visibility. */ + float contact_shadow; /** Result of contact shadow tracing. */ +}; + +ClosureLightData closure_light_eval_init(ClosureEvalCommon cl_common, int light_id) +{ + ClosureLightData light; + light.data = lights_data[light_id]; + + light.L.xyz = light.data.l_position - cl_common.P; + light.L.w = length(light.L.xyz); + + light.vis = light_visibility(light.data, cl_common.P, light.L); + light.contact_shadow = light_contact_shadows(light.data, + cl_common.P, + cl_common.vP, + cl_common.tracing_depth, + cl_common.vNg, + cl_common.rand.x, + light.vis); + + return light; +} + +struct ClosureCubemapData { + int id; /** Probe id. */ + float attenuation; /** Attenuation. */ +}; + +ClosureCubemapData closure_cubemap_eval_init(int cube_id, inout ClosureEvalCommon cl_common) +{ + ClosureCubemapData cube; + cube.id = cube_id; + cube.attenuation = probe_attenuation_cube(cube_id, cl_common.P); + cube.attenuation = min(cube.attenuation, cl_common.specular_accum); + cl_common.specular_accum -= cube.attenuation; + return cube; +} + +struct ClosurePlanarData { + int id; /** Probe id. */ + PlanarData data; /** planars_data[id]. */ + float attenuation; /** Attenuation. */ +}; + +ClosurePlanarData closure_planar_eval_init(int planar_id, inout ClosureEvalCommon cl_common) +{ + ClosurePlanarData planar; + planar.id = planar_id; + planar.data = planars_data[planar_id]; + planar.attenuation = probe_attenuation_planar(planar.data, cl_common.P, cl_common.N, 0.0); + planar.attenuation = min(planar.attenuation, cl_common.specular_accum); + cl_common.specular_accum -= planar.attenuation; + return planar; +} + +struct ClosureGridData { + int id; /** Grid id. */ + GridData data; /** grids_data[id] */ + float attenuation; /** Attenuation. */ + vec3 local_pos; /** Local position inside the grid. */ +}; + +ClosureGridData closure_grid_eval_init(int id, inout ClosureEvalCommon cl_common) +{ + ClosureGridData grid; + grid.id = id; + grid.data = grids_data[id]; + grid.attenuation = probe_attenuation_grid(grid.data, cl_common.P, grid.local_pos); + grid.attenuation = min(grid.attenuation, cl_common.diffuse_accum); + cl_common.diffuse_accum -= grid.attenuation; + return grid; +} + +/** \} */ diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_refraction_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_refraction_lib.glsl new file mode 100644 index 00000000000..9011eea07c4 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_refraction_lib.glsl @@ -0,0 +1,128 @@ + +#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl) +#pragma BLENDER_REQUIRE(lights_lib.glsl) +#pragma BLENDER_REQUIRE(lightprobe_lib.glsl) +#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl) +#pragma BLENDER_REQUIRE(ssr_lib.glsl) + +struct ClosureInputRefraction { + vec3 N; /** Shading normal. */ + float roughness; /** Input roughness, not squared. */ + float ior; /** Index of refraction ratio. */ +}; + +#define CLOSURE_INPUT_Refraction_DEFAULT ClosureInputRefraction(vec3(0.0), 0.0, 0.0) + +struct ClosureEvalRefraction { + vec3 P; /** LTC matrix values. */ + vec3 ltc_brdf; /** LTC BRDF values. */ + vec3 probe_sampling_dir; /** Direction to sample probes from. */ + float probes_weight; /** Factor to apply to probe radiance. */ +}; + +/* Stubs. */ +#define ClosureOutputRefraction ClosureOutput +#define closure_Refraction_grid_eval(cl_in, cl_eval, cl_common, data, cl_out) + +ClosureEvalRefraction closure_Refraction_eval_init(inout ClosureInputRefraction cl_in, + ClosureEvalCommon cl_common, + out ClosureOutputRefraction cl_out) +{ + cl_in.N = safe_normalize(cl_in.N); + cl_in.roughness = clamp(cl_in.roughness, 1e-8, 0.9999); + cl_in.ior = max(cl_in.ior, 1e-5); + cl_out.radiance = vec3(0.0); + + ClosureEvalRefraction cl_eval; + vec3 cl_V; + float eval_ior; + /* Refract the view vector using the depth heuristic. + * Then later Refract a second time the already refracted + * ray using the inverse ior. */ + if (refractionDepth > 0.0) { + eval_ior = 1.0 / cl_in.ior; + cl_V = -refract(-cl_common.V, cl_in.N, eval_ior); + vec3 plane_pos = cl_common.P - cl_in.N * refractionDepth; + cl_eval.P = line_plane_intersect(cl_common.P, cl_V, plane_pos, cl_in.N); + } + else { + eval_ior = cl_in.ior; + cl_V = cl_common.V; + cl_eval.P = cl_common.P; + } + + cl_eval.probe_sampling_dir = refraction_dominant_dir(cl_in.N, cl_V, cl_in.roughness, eval_ior); + cl_eval.probes_weight = 1.0; + +#ifdef USE_REFRACTION + if (ssrefractToggle && cl_in.roughness < ssrMaxRoughness + 0.2) { + /* Find approximated position of the 2nd refraction event. */ + vec3 vP = (refractionDepth > 0.0) ? transform_point(ViewMatrix, cl_eval.P) : cl_common.vP; + vec4 ssr_output = screen_space_refraction( + vP, cl_in.N, cl_V, eval_ior, sqr(cl_in.roughness), cl_common.rand); + ssr_output.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, cl_in.roughness); + cl_out.radiance += ssr_output.rgb * ssr_output.a; + cl_eval.probes_weight -= ssr_output.a; + } +#endif + return cl_eval; +} + +void closure_Refraction_light_eval(ClosureInputRefraction cl_in, + ClosureEvalRefraction cl_eval, + ClosureEvalCommon cl_common, + ClosureLightData light, + inout ClosureOutputRefraction cl_out) +{ + /* Not implemented yet. */ +} + +void closure_Refraction_planar_eval(ClosureInputRefraction cl_in, + ClosureEvalRefraction cl_eval, + ClosureEvalCommon cl_common, + ClosurePlanarData planar, + inout ClosureOutputRefraction cl_out) +{ + /* Not implemented yet. */ +} + +void closure_Refraction_cubemap_eval(ClosureInputRefraction cl_in, + ClosureEvalRefraction cl_eval, + ClosureEvalCommon cl_common, + ClosureCubemapData cube, + inout ClosureOutputRefraction cl_out) +{ + vec3 probe_radiance = probe_evaluate_cube( + cube.id, cl_eval.P, cl_eval.probe_sampling_dir, sqr(cl_in.roughness)); + cl_out.radiance += (cube.attenuation * cl_eval.probes_weight) * probe_radiance; +} + +void closure_Refraction_indirect_end(ClosureInputRefraction cl_in, + ClosureEvalRefraction cl_eval, + ClosureEvalCommon cl_common, + inout ClosureOutputRefraction cl_out) +{ + /* If not enough light has been accumulated from probes, use the world specular cubemap + * to fill the remaining energy needed. */ + if (specToggle && cl_common.specular_accum > 0.0) { + vec3 probe_radiance = probe_evaluate_world_spec(cl_eval.probe_sampling_dir, + sqr(cl_in.roughness)); + cl_out.radiance += (cl_common.specular_accum * cl_eval.probes_weight) * probe_radiance; + } +} + +void closure_Refraction_eval_end(ClosureInputRefraction cl_in, + ClosureEvalRefraction cl_eval, + ClosureEvalCommon cl_common, + inout ClosureOutputRefraction cl_out) +{ +#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND) + /* This makes shader resources become unused and avoid issues with samplers. (see T59747) */ + cl_out.radiance = vec3(0.0); + return; +#endif + + if (!specToggle) { + cl_out.radiance = vec3(0.0); + } +} diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl new file mode 100644 index 00000000000..66c467af29b --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_translucent_lib.glsl @@ -0,0 +1,71 @@ + +#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl) +#pragma BLENDER_REQUIRE(lights_lib.glsl) +#pragma BLENDER_REQUIRE(lightprobe_lib.glsl) +#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl) + +struct ClosureInputTranslucent { + vec3 N; /** Shading normal. */ +}; + +#define CLOSURE_INPUT_Translucent_DEFAULT ClosureInputTranslucent(vec3(0.0)) + +/* Stubs. */ +#define ClosureEvalTranslucent ClosureEvalDummy +#define ClosureOutputTranslucent ClosureOutput +#define closure_Translucent_planar_eval(cl_in, cl_eval, cl_common, data, cl_out) +#define closure_Translucent_cubemap_eval(cl_in, cl_eval, cl_common, data, cl_out) + +ClosureEvalTranslucent closure_Translucent_eval_init(inout ClosureInputTranslucent cl_in, + ClosureEvalCommon cl_common, + out ClosureOutputTranslucent cl_out) +{ + cl_in.N = safe_normalize(cl_in.N); + cl_out.radiance = vec3(0.0); + return CLOSURE_EVAL_DUMMY; +} + +void closure_Translucent_light_eval(ClosureInputTranslucent cl_in, + ClosureEvalTranslucent cl_eval, + ClosureEvalCommon cl_common, + ClosureLightData light, + inout ClosureOutputTranslucent cl_out) +{ + float radiance = light_diffuse(light.data, cl_in.N, cl_common.V, light.L); + cl_out.radiance += light.data.l_color * (light.vis * radiance); +} + +void closure_Translucent_grid_eval(ClosureInputTranslucent cl_in, + ClosureEvalTranslucent cl_eval, + ClosureEvalCommon cl_common, + ClosureGridData grid, + inout ClosureOutputTranslucent cl_out) +{ + vec3 probe_radiance = probe_evaluate_grid(grid.data, cl_common.P, cl_in.N, grid.local_pos); + cl_out.radiance += grid.attenuation * probe_radiance; +} + +void closure_Translucent_indirect_end(ClosureInputTranslucent cl_in, + ClosureEvalTranslucent cl_eval, + ClosureEvalCommon cl_common, + inout ClosureOutputTranslucent cl_out) +{ + /* If not enough light has been accumulated from probes, use the world specular cubemap + * to fill the remaining energy needed. */ + if (cl_common.diffuse_accum > 0.0) { + vec3 probe_radiance = probe_evaluate_world_diff(cl_in.N); + cl_out.radiance += cl_common.diffuse_accum * probe_radiance; + } +} + +void closure_Translucent_eval_end(ClosureInputTranslucent cl_in, + ClosureEvalTranslucent cl_eval, + ClosureEvalCommon cl_common, + inout ClosureOutputTranslucent cl_out) +{ +#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND) + /* This makes shader resources become unused and avoid issues with samplers. (see T59747) */ + cl_out.radiance = vec3(0.0); + return; +#endif +} diff --git a/source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl deleted file mode 100644 index 30ce60f3ec0..00000000000 --- a/source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl +++ /dev/null @@ -1,545 +0,0 @@ - -#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl) -#pragma BLENDER_REQUIRE(lightprobe_lib.glsl) -#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl) -#pragma BLENDER_REQUIRE(ssr_lib.glsl) - -/** - * AUTO CONFIG - * We include the file multiple times each time with a different configuration. - * This leads to a lot of deadcode. Better idea would be to only generate the one needed. - */ -#if !defined(SURFACE_DEFAULT) -# define SURFACE_DEFAULT -# define CLOSURE_NAME eevee_closure_default -# define CLOSURE_DIFFUSE -# define CLOSURE_GLOSSY -#endif /* SURFACE_DEFAULT */ - -#if !defined(SURFACE_DEFAULT_CLEARCOAT) && !defined(CLOSURE_NAME) -# define SURFACE_DEFAULT_CLEARCOAT -# define CLOSURE_NAME eevee_closure_default_clearcoat -# define CLOSURE_DIFFUSE -# define CLOSURE_GLOSSY -# define CLOSURE_CLEARCOAT -#endif /* SURFACE_DEFAULT_CLEARCOAT */ - -#if !defined(SURFACE_PRINCIPLED) && !defined(CLOSURE_NAME) -# define SURFACE_PRINCIPLED -# define CLOSURE_NAME eevee_closure_principled -# define CLOSURE_DIFFUSE -# define CLOSURE_GLOSSY -# define CLOSURE_CLEARCOAT -# define CLOSURE_REFRACTION -# define CLOSURE_SUBSURFACE -#endif /* SURFACE_PRINCIPLED */ - -#if !defined(SURFACE_CLEARCOAT) && !defined(CLOSURE_NAME) -# define SURFACE_CLEARCOAT -# define CLOSURE_NAME eevee_closure_clearcoat -# define CLOSURE_GLOSSY -# define CLOSURE_CLEARCOAT -#endif /* SURFACE_CLEARCOAT */ - -#if !defined(SURFACE_DIFFUSE) && !defined(CLOSURE_NAME) -# define SURFACE_DIFFUSE -# define CLOSURE_NAME eevee_closure_diffuse -# define CLOSURE_DIFFUSE -#endif /* SURFACE_DIFFUSE */ - -#if !defined(SURFACE_SUBSURFACE) && !defined(CLOSURE_NAME) -# define SURFACE_SUBSURFACE -# define CLOSURE_NAME eevee_closure_subsurface -# define CLOSURE_DIFFUSE -# define CLOSURE_SUBSURFACE -#endif /* SURFACE_SUBSURFACE */ - -#if !defined(SURFACE_SKIN) && !defined(CLOSURE_NAME) -# define SURFACE_SKIN -# define CLOSURE_NAME eevee_closure_skin -# define CLOSURE_DIFFUSE -# define CLOSURE_SUBSURFACE -# define CLOSURE_GLOSSY -#endif /* SURFACE_SKIN */ - -#if !defined(SURFACE_GLOSSY) && !defined(CLOSURE_NAME) -# define SURFACE_GLOSSY -# define CLOSURE_NAME eevee_closure_glossy -# define CLOSURE_GLOSSY -#endif /* SURFACE_GLOSSY */ - -#if !defined(SURFACE_REFRACT) && !defined(CLOSURE_NAME) -# define SURFACE_REFRACT -# define CLOSURE_NAME eevee_closure_refraction -# define CLOSURE_REFRACTION -#endif /* SURFACE_REFRACT */ - -#if !defined(SURFACE_GLASS) && !defined(CLOSURE_NAME) -# define SURFACE_GLASS -# define CLOSURE_NAME eevee_closure_glass -# define CLOSURE_GLOSSY -# define CLOSURE_REFRACTION -#endif /* SURFACE_GLASS */ - -/* Safety : CLOSURE_CLEARCOAT implies CLOSURE_GLOSSY */ -#ifdef CLOSURE_CLEARCOAT -# ifndef CLOSURE_GLOSSY -# define CLOSURE_GLOSSY -# endif -#endif /* CLOSURE_CLEARCOAT */ - -void CLOSURE_NAME(vec3 N -#ifdef CLOSURE_DIFFUSE - , - vec3 albedo -#endif -#ifdef CLOSURE_GLOSSY - , - vec3 f0, - vec3 f90, - int ssr_id -#endif -#if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION) - , - float roughness -#endif -#ifdef CLOSURE_CLEARCOAT - , - vec3 C_N, - float C_intensity, - float C_roughness -#endif -#if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE) - , - float ao -#endif -#ifdef CLOSURE_SUBSURFACE - , - float sss_scale -#endif -#ifdef CLOSURE_REFRACTION - , - float ior -#endif - , - const bool use_contact_shadows -#ifdef CLOSURE_DIFFUSE - , - out vec3 out_diff -#endif -#ifdef CLOSURE_GLOSSY - , - out vec3 out_spec -#endif -#ifdef CLOSURE_REFRACTION - , - out vec3 out_refr -#endif -#ifdef CLOSURE_GLOSSY - , - out vec3 ssr_spec -#endif -) -{ -#ifdef CLOSURE_DIFFUSE - out_diff = vec3(0.0); -#endif - -#ifdef CLOSURE_GLOSSY - out_spec = vec3(0.0); -#endif - -#ifdef CLOSURE_REFRACTION - out_refr = vec3(0.0); -#endif - -#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND) - /* This makes shader resources become unused and avoid issues with samplers. (see T59747) */ - return; -#else - - /* Zero length vectors cause issues, see: T51979. */ - float len = length(N); - if (isnan(len)) { - return; - } - N /= len; - -# ifdef CLOSURE_CLEARCOAT - len = length(C_N); - if (isnan(len)) { - return; - } - C_N /= len; -# endif - -# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION) - roughness = clamp(roughness, 1e-8, 0.9999); - float roughnessSquared = roughness * roughness; -# endif - -# ifdef CLOSURE_CLEARCOAT - C_roughness = clamp(C_roughness, 1e-8, 0.9999); - float C_roughnessSquared = C_roughness * C_roughness; -# endif - - vec3 V = cameraVec; - - vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); - - /* ---------------------------------------------------------------- */ - /* -------------------- SCENE LIGHTS LIGHTING --------------------- */ - /* ---------------------------------------------------------------- */ - -# ifdef CLOSURE_GLOSSY - vec2 lut_uv = lut_coords_ltc(dot(N, V), roughness); - vec4 ltc_mat = texture(utilTex, vec3(lut_uv, 0.0)).rgba; -# endif - -# ifdef CLOSURE_CLEARCOAT - vec2 lut_uv_clear = lut_coords_ltc(dot(C_N, V), C_roughness); - vec4 ltc_mat_clear = texture(utilTex, vec3(lut_uv_clear, 0.0)).rgba; - vec3 out_spec_clear = vec3(0.0); -# endif - - float tracing_depth = gl_FragCoord.z; - /* Constant bias (due to depth buffer precision) */ - /* Magic numbers for 24bits of precision. - * From http://terathon.com/gdc07_lengyel.pdf (slide 26) */ - tracing_depth -= mix(2.4e-7, 4.8e-7, gl_FragCoord.z); - /* Convert to view Z. */ - tracing_depth = get_view_z_from_depth(tracing_depth); - - vec3 true_normal = normalize(cross(dFdx(viewPosition), dFdy(viewPosition))); - - for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) { - LightData ld = lights_data[i]; - - vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */ - l_vector.xyz = ld.l_position - worldPosition; - l_vector.w = length(l_vector.xyz); - - float l_vis = light_visibility(ld, - worldPosition, - viewPosition, - tracing_depth, - true_normal, - rand.x, - use_contact_shadows, - l_vector); - - if (l_vis < 1e-8) { - continue; - } - - vec3 l_color_vis = ld.l_color * l_vis; - -# ifdef CLOSURE_DIFFUSE - out_diff += l_color_vis * light_diffuse(ld, N, V, l_vector); -# endif - -# ifdef CLOSURE_GLOSSY - out_spec += l_color_vis * light_specular(ld, ltc_mat, N, V, l_vector) * ld.l_spec; -# endif - -# ifdef CLOSURE_CLEARCOAT - out_spec_clear += l_color_vis * light_specular(ld, ltc_mat_clear, C_N, V, l_vector) * - ld.l_spec; -# endif - } - -# ifdef CLOSURE_GLOSSY - vec2 brdf_lut_lights = texture(utilTex, vec3(lut_uv, 1.0)).ba; - out_spec *= F_brdf(f0, f90, brdf_lut_lights.xy); -# endif - -# ifdef CLOSURE_CLEARCOAT - vec2 brdf_lut_lights_clear = texture(utilTex, vec3(lut_uv_clear, 1.0)).ba; - out_spec_clear *= F_brdf(vec3(0.04), vec3(1.0), brdf_lut_lights_clear.xy); - out_spec += out_spec_clear * C_intensity; -# endif - - /* ---------------------------------------------------------------- */ - /* ---------------- SPECULAR ENVIRONMENT LIGHTING ----------------- */ - /* ---------------------------------------------------------------- */ - - /* Accumulate incoming light from all sources until accumulator is full. Then apply Occlusion and - * BRDF. */ -# ifdef CLOSURE_GLOSSY - vec4 spec_accum = vec4(0.0); -# endif - -# ifdef CLOSURE_CLEARCOAT - vec4 C_spec_accum = vec4(0.0); -# endif - -# ifdef CLOSURE_REFRACTION - vec4 refr_accum = vec4(0.0); -# endif - -# ifdef CLOSURE_GLOSSY - /* ---------------------------- */ - /* Planar Reflections */ - /* ---------------------------- */ - - for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar && spec_accum.a < 0.999; i++) { - PlanarData pd = planars_data[i]; - - /* Fade on geometric normal. */ - float fade = probe_attenuation_planar( - pd, worldPosition, (gl_FrontFacing) ? worldNormal : -worldNormal, roughness); - - if (fade > 0.0) { - if (!(ssrToggle && ssr_id == outputSsrId)) { - vec3 spec = probe_evaluate_planar(float(i), pd, worldPosition, N, V, roughness, fade); - accumulate_light(spec, fade, spec_accum); - } - -# ifdef CLOSURE_CLEARCOAT - vec3 C_spec = probe_evaluate_planar(float(i), pd, worldPosition, C_N, V, C_roughness, fade); - accumulate_light(C_spec, fade, C_spec_accum); -# endif - } - } -# endif - -# ifdef CLOSURE_GLOSSY - vec3 spec_dir = specular_dominant_dir(N, V, roughnessSquared); -# endif - -# ifdef CLOSURE_CLEARCOAT - vec3 C_spec_dir = specular_dominant_dir(C_N, V, C_roughnessSquared); -# endif - -# ifdef CLOSURE_REFRACTION - /* Refract the view vector using the depth heuristic. - * Then later Refract a second time the already refracted - * ray using the inverse ior. */ - float final_ior = (refractionDepth > 0.0) ? 1.0 / ior : ior; - vec3 refr_V = (refractionDepth > 0.0) ? -refract(-V, N, final_ior) : V; - vec3 refr_pos = (refractionDepth > 0.0) ? - line_plane_intersect( - worldPosition, refr_V, worldPosition - N * refractionDepth, N) : - worldPosition; - vec3 refr_dir = refraction_dominant_dir(N, refr_V, roughness, final_ior); -# endif - -# ifdef CLOSURE_REFRACTION -/* ---------------------------- */ -/* Screen Space Refraction */ -/* ---------------------------- */ -# ifdef USE_REFRACTION - if (ssrefractToggle && roughness < ssrMaxRoughness + 0.2) { - /* Find approximated position of the 2nd refraction event. */ - vec3 refr_vpos = (refractionDepth > 0.0) ? transform_point(ViewMatrix, refr_pos) : - viewPosition; - vec4 trans = screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand); - trans.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness); - accumulate_light(trans.rgb, trans.a, refr_accum); - } -# endif - -# endif - - /* ---------------------------- */ - /* Specular probes */ - /* ---------------------------- */ -# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_REFRACTION) - -# if defined(CLOSURE_GLOSSY) && defined(CLOSURE_REFRACTION) -# define GLASS_ACCUM 1 -# define ACCUM min(refr_accum.a, spec_accum.a) -# elif defined(CLOSURE_REFRACTION) -# define GLASS_ACCUM 0 -# define ACCUM refr_accum.a -# else -# define GLASS_ACCUM 0 -# define ACCUM spec_accum.a -# endif - - /* Starts at 1 because 0 is world probe */ - for (int i = 1; ACCUM < 0.999 && i < prbNumRenderCube && i < MAX_PROBE; i++) { - float fade = probe_attenuation_cube(i, worldPosition); - - if (fade > 0.0) { - -# if GLASS_ACCUM - if (spec_accum.a < 0.999) { -# endif -# ifdef CLOSURE_GLOSSY - if (!(ssrToggle && ssr_id == outputSsrId)) { - vec3 spec = probe_evaluate_cube(i, worldPosition, spec_dir, roughness); - accumulate_light(spec, fade, spec_accum); - } -# endif - -# ifdef CLOSURE_CLEARCOAT - vec3 C_spec = probe_evaluate_cube(i, worldPosition, C_spec_dir, C_roughness); - accumulate_light(C_spec, fade, C_spec_accum); -# endif -# if GLASS_ACCUM - } -# endif - -# if GLASS_ACCUM - if (refr_accum.a < 0.999) { -# endif -# ifdef CLOSURE_REFRACTION - vec3 trans = probe_evaluate_cube(i, refr_pos, refr_dir, roughnessSquared); - accumulate_light(trans, fade, refr_accum); -# endif -# if GLASS_ACCUM - } -# endif - } - } - -# undef GLASS_ACCUM -# undef ACCUM - -/* ---------------------------- */ -/* World Probe */ -/* ---------------------------- */ -# ifdef CLOSURE_GLOSSY - if (spec_accum.a < 0.999) { - if (!(ssrToggle && ssr_id == outputSsrId)) { - vec3 spec = probe_evaluate_world_spec(spec_dir, roughness); - accumulate_light(spec, 1.0, spec_accum); - } - -# ifdef CLOSURE_CLEARCOAT - vec3 C_spec = probe_evaluate_world_spec(C_spec_dir, C_roughness); - accumulate_light(C_spec, 1.0, C_spec_accum); -# endif - } -# endif - -# ifdef CLOSURE_REFRACTION - if (refr_accum.a < 0.999) { - vec3 trans = probe_evaluate_world_spec(refr_dir, roughnessSquared); - accumulate_light(trans, 1.0, refr_accum); - } -# endif -# endif /* Specular probes */ - - /* ---------------------------- */ - /* Ambient Occlusion */ - /* ---------------------------- */ -# if defined(CLOSURE_GLOSSY) || defined(CLOSURE_DIFFUSE) - if (!use_contact_shadows) { - /* HACK: Fix for translucent BSDF. (see T65631) */ - N = -N; - } - vec3 bent_normal; - float final_ao = occlusion_compute(N, viewPosition, ao, rand, bent_normal); - if (!use_contact_shadows) { - N = -N; - /* Bypass bent normal. */ - bent_normal = N; - } -# endif - - /* ---------------------------- */ - /* Specular Output */ - /* ---------------------------- */ - float NV = dot(N, V); -# ifdef CLOSURE_GLOSSY - vec2 uv = lut_coords(NV, roughness); - vec2 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rg; - - /* This factor is outputted to be used by SSR in order - * to match the intensity of the regular reflections. */ - ssr_spec = F_brdf(f0, f90, brdf_lut); - float spec_occlu = specular_occlusion(NV, final_ao, roughness); - - /* The SSR pass recompute the occlusion to not apply it to the SSR */ - if (ssrToggle && ssr_id == outputSsrId) { - spec_occlu = 1.0; - } - - out_spec += spec_accum.rgb * ssr_spec * spec_occlu; -# endif - -# ifdef CLOSURE_REFRACTION - float btdf = get_btdf_lut(NV, roughness, ior); - - out_refr += refr_accum.rgb * btdf; - - /* Global toggle for lightprobe baking. */ - out_refr *= float(specToggle); -# endif - -# ifdef CLOSURE_CLEARCOAT - NV = dot(C_N, V); - vec2 C_uv = lut_coords(NV, C_roughness); - vec2 C_brdf_lut = texture(utilTex, vec3(C_uv, 1.0)).rg; - vec3 C_fresnel = F_brdf(vec3(0.04), vec3(1.0), C_brdf_lut) * - specular_occlusion(NV, final_ao, C_roughness); - - out_spec += C_spec_accum.rgb * C_fresnel * C_intensity; -# endif - -# ifdef CLOSURE_GLOSSY - /* Global toggle for lightprobe baking. */ - out_spec *= float(specToggle); -# endif - - /* ---------------------------------------------------------------- */ - /* ---------------- DIFFUSE ENVIRONMENT LIGHTING ------------------ */ - /* ---------------------------------------------------------------- */ - - /* Accumulate light from all sources until accumulator is full. Then apply Occlusion and BRDF. */ -# ifdef CLOSURE_DIFFUSE - vec4 diff_accum = vec4(0.0); - - /* ---------------------------- */ - /* Irradiance Grids */ - /* ---------------------------- */ - /* Start at 1 because 0 is world irradiance */ - for (int i = 1; i < MAX_GRID && i < prbNumRenderGrid && diff_accum.a < 0.999; i++) { - GridData gd = grids_data[i]; - - vec3 localpos; - float fade = probe_attenuation_grid(gd, grids_data[i].localmat, worldPosition, localpos); - - if (fade > 0.0) { - vec3 diff = probe_evaluate_grid(gd, worldPosition, bent_normal, localpos); - accumulate_light(diff, fade, diff_accum); - } - } - - /* ---------------------------- */ - /* World Diffuse */ - /* ---------------------------- */ - if (diff_accum.a < 0.999 && prbNumRenderGrid > 0) { - vec3 diff = probe_evaluate_world_diff(bent_normal); - accumulate_light(diff, 1.0, diff_accum); - } - - out_diff += diff_accum.rgb * gtao_multibounce(final_ao, albedo); -# endif -#endif -} - -/* Cleanup for next configuration */ -#undef CLOSURE_NAME - -#ifdef CLOSURE_DIFFUSE -# undef CLOSURE_DIFFUSE -#endif - -#ifdef CLOSURE_GLOSSY -# undef CLOSURE_GLOSSY -#endif - -#ifdef CLOSURE_CLEARCOAT -# undef CLOSURE_CLEARCOAT -#endif - -#ifdef CLOSURE_REFRACTION -# undef CLOSURE_REFRACTION -#endif - -#ifdef CLOSURE_SUBSURFACE -# undef CLOSURE_SUBSURFACE -#endif diff --git a/source/blender/draw/engines/eevee/shaders/closure_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl index b56a186ab3f..9ca25ef240f 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl @@ -147,17 +147,27 @@ Closure closure_emission(vec3 rgb) #ifndef VOLUMETRICS +/* Let radiance passthrough or replace it to get the BRDF and color + * to applied to the SSR result. */ +vec3 closure_mask_ssr_radiance(vec3 radiance, float ssr_id) +{ + return (ssrToggle && int(ssr_id) == outputSsrId) ? vec3(1.0) : radiance; +} + void closure_load_ssr_data( - vec3 ssr_spec, float roughness, vec3 N, vec3 viewVec, int ssr_id, inout Closure cl) + vec3 ssr_radiance, float roughness, vec3 N, float ssr_id, inout Closure cl) { /* Still encode to avoid artifacts in the SSR pass. */ vec3 vN = normalize(mat3(ViewMatrix) * N); - cl.ssr_normal = normal_encode(vN, viewVec); + cl.ssr_normal = normal_encode(vN, viewCameraVec); - if (ssr_id == outputSsrId) { - cl.ssr_data = vec4(ssr_spec, roughness); + if (ssrToggle && int(ssr_id) == outputSsrId) { + cl.ssr_data = vec4(ssr_radiance, roughness); cl.flag |= CLOSURE_SSR_FLAG; } + else { + cl.radiance += ssr_radiance; + } } void closure_load_sss_data( @@ -169,13 +179,11 @@ void closure_load_sss_data( cl.sss_radius = radius; cl.sss_albedo = sss_albedo; cl.flag |= CLOSURE_SSS_FLAG; - cl.radiance += render_pass_diffuse_mask(sss_albedo, vec3(0)); + /* Irradiance will be convolved by SSSS pass. Do not add to radiance. */ + sss_irradiance = vec3(0); } - else # endif - { - cl.radiance += render_pass_diffuse_mask(sss_albedo, sss_irradiance * sss_albedo); - } + cl.radiance += render_pass_diffuse_mask(vec3(1), sss_irradiance) * sss_albedo; } #endif diff --git a/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl index 427657b19b7..7b1a0b263c0 100644 --- a/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl @@ -12,6 +12,13 @@ uniform sampler2DArray utilTex; #define LUT_SIZE 64 +#define LTC_MAT_LAYER 0 +#define LTC_BRDF_LAYER 1 +#define BRDF_LUT_LAYER 1 +#define NOISE_LAYER 2 +#define LTC_DISK_LAYER 3 /* UNUSED */ +/* Layers 4 to 20 are for BTDF Lut. */ + /** * Reminder: The 4 noise values are based of 3 uncorrelated blue noises: * x : Uniformly distributed value [0..1] (noise 1). @@ -23,6 +30,7 @@ uniform sampler2DArray utilTex; /* Return texture coordinates to sample Surface LUT */ vec2 lut_coords(float cosTheta, float roughness) { + /* TODO(fclem) Ugly Acos here. Get rid ot this. Should use same mapping as lut_coords_ltc. */ float theta = acos(cosTheta); vec2 coords = vec2(roughness, theta / M_PI_2); @@ -38,6 +46,11 @@ vec2 lut_coords_ltc(float cosTheta, float roughness) return coords * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE; } +vec2 brdf_lut(float cosTheta, float roughness) +{ + return textureLod(utilTex, vec3(lut_coords(cosTheta, roughness), BRDF_LUT_LAYER), 0.0).rg; +} + float get_btdf_lut(float NV, float roughness, float ior) { const vec3 lut_scale_bias_texel_size = vec3((LUT_SIZE - 1.0), 0.5, 1.5) / LUT_SIZE; diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl index d50a4eaea3c..b49cd987a6e 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl @@ -2,6 +2,8 @@ #pragma BLENDER_REQUIRE(common_math_lib.glsl) #pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) #pragma BLENDER_REQUIRE(common_utiltex_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_lib.glsl) #pragma BLENDER_REQUIRE(raytrace_lib.glsl) #pragma BLENDER_REQUIRE(lightprobe_lib.glsl) #pragma BLENDER_REQUIRE(ssr_lib.glsl) @@ -170,7 +172,7 @@ void main() /* Importance sampling bias */ rand.x = mix(rand.x, 0.0, ssrBrdfBias); - vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition); + vec3 W = transform_point(ViewMatrixInverse, viewPosition); vec3 wN = transform_direction(ViewMatrixInverse, N); vec3 T, B; @@ -180,12 +182,12 @@ void main() for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) { PlanarData pd = planars_data[i]; - float fade = probe_attenuation_planar(pd, worldPosition, wN, 0.0); + float fade = probe_attenuation_planar(pd, W, wN, 0.0); if (fade > 0.5) { /* Find view vector / reflection plane intersection. */ /* TODO optimize, use view space for all. */ - vec3 tracePosition = line_plane_intersect(worldPosition, cameraVec, pd.pl_plane_eq); + vec3 tracePosition = line_plane_intersect(W, cameraVec, pd.pl_plane_eq); tracePosition = transform_point(ViewMatrix, tracePosition); vec3 planeNormal = transform_direction(ViewMatrix, pd.pl_normal); @@ -213,6 +215,8 @@ uniform sampler2D pdfBuffer; uniform int neighborOffset; +in vec4 uvcoordsvar; + const ivec2 neighbors[32] = ivec2[32](ivec2(0, 0), ivec2(1, 1), ivec2(-2, 0), @@ -298,7 +302,7 @@ float get_sample_depth(vec2 hit_co, bool is_planar, float planar_index) vec3 get_hit_vector(vec3 hit_pos, PlanarData pd, - vec3 worldPosition, + vec3 P, vec3 N, vec3 V, bool is_planar, @@ -309,7 +313,7 @@ vec3 get_hit_vector(vec3 hit_pos, if (is_planar) { /* Reflect back the hit position to have it in non-reflected world space */ - vec3 trace_pos = line_plane_intersect(worldPosition, V, pd.pl_plane_eq); + vec3 trace_pos = line_plane_intersect(P, V, pd.pl_plane_eq); hit_vec = hit_pos - trace_pos; hit_vec = reflect(hit_vec, pd.pl_normal); /* Modify here so mip texel alignment is correct. */ @@ -317,8 +321,8 @@ vec3 get_hit_vector(vec3 hit_pos, } else { /* Find hit position in previous frame. */ - hit_co = get_reprojected_reflection(hit_pos, worldPosition, N); - hit_vec = hit_pos - worldPosition; + hit_co = get_reprojected_reflection(hit_pos, P, N); + hit_vec = hit_pos - P; } mask = screen_border_mask(hit_co); @@ -339,7 +343,7 @@ vec4 get_ssr_samples(vec4 hit_pdf, ivec4 hit_data[2], PlanarData pd, float planar_index, - vec3 worldPosition, + vec3 P, vec3 N, vec3 V, float roughnessSquared, @@ -379,14 +383,10 @@ vec4 get_ssr_samples(vec4 hit_pdf, /* Get actual hit vector and hit coordinate (from last frame). */ vec4 mask = vec4(1.0); - hit_pos[0] = get_hit_vector( - hit_pos[0], pd, worldPosition, N, V, is_planar.x, hit_co[0].xy, mask.x); - hit_pos[1] = get_hit_vector( - hit_pos[1], pd, worldPosition, N, V, is_planar.y, hit_co[0].zw, mask.y); - hit_pos[2] = get_hit_vector( - hit_pos[2], pd, worldPosition, N, V, is_planar.z, hit_co[1].xy, mask.z); - hit_pos[3] = get_hit_vector( - hit_pos[3], pd, worldPosition, N, V, is_planar.w, hit_co[1].zw, mask.w); + hit_pos[0] = get_hit_vector(hit_pos[0], pd, P, N, V, is_planar.x, hit_co[0].xy, mask.x); + hit_pos[1] = get_hit_vector(hit_pos[1], pd, P, N, V, is_planar.y, hit_co[0].zw, mask.y); + hit_pos[2] = get_hit_vector(hit_pos[2], pd, P, N, V, is_planar.z, hit_co[1].xy, mask.z); + hit_pos[3] = get_hit_vector(hit_pos[3], pd, P, N, V, is_planar.w, hit_co[1].zw, mask.w); vec4 hit_dist; hit_dist.x = length(hit_pos[0]); @@ -476,47 +476,30 @@ vec4 get_ssr_samples(vec4 hit_pdf, return accum; } -void main() +void raytrace_resolve(ClosureInputGlossy cl_in, + inout ClosureEvalGlossy cl_eval, + inout ClosureEvalCommon cl_common, + inout ClosureOutputGlossy cl_out) { - ivec2 fullres_texel = ivec2(gl_FragCoord.xy); # ifdef FULLRES - ivec2 halfres_texel = fullres_texel; + ivec2 texel = ivec2(gl_FragCoord.xy); # else - ivec2 halfres_texel = ivec2(gl_FragCoord.xy / 2.0); + ivec2 texel = ivec2(gl_FragCoord.xy / 2.0); # endif - vec2 uvs = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0)); - - float depth = textureLod(depthBuffer, uvs, 0.0).r; - - /* Early out */ - if (depth == 1.0) { - discard; - } - /* Using world space */ - vec3 viewPosition = get_view_space_from_depth(uvs, depth); /* Needed for viewCameraVec */ - vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition); - vec3 V = cameraVec; - vec3 vN = normal_decode(texelFetch(normalBuffer, fullres_texel, 0).rg, viewCameraVec); - vec3 N = transform_direction(ViewMatrixInverse, vN); - vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba; + vec3 V = cl_common.V; + vec3 N = cl_in.N; + vec3 P = cl_common.P; - /* Early out */ - if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) { - discard; - } - - float roughness = speccol_roughness.a; - float roughnessSquared = max(1e-3, roughness * roughness); - - vec4 spec_accum = vec4(0.0); + float roughness = cl_in.roughness; + float roughnessSquared = max(1e-3, sqr(roughness)); /* Resolve SSR */ float cone_cos = cone_cosine(roughnessSquared); float cone_tan = sqrt(1 - cone_cos * cone_cos) / cone_cos; cone_tan *= mix(saturate(dot(N, -V) * 2.0), 1.0, roughness); /* Elongation fit */ - vec2 source_uvs = project_point(pastViewProjectionMatrix, worldPosition).xy * 0.5 + 0.5; + vec2 source_uvs = project_point(pastViewProjectionMatrix, P).xy * 0.5 + 0.5; vec4 ssr_accum = vec4(0.0); float weight_acc = 0.0; @@ -525,16 +508,16 @@ void main() /* TODO optimize with textureGather */ /* Doing these fetches early to hide latency. */ vec4 hit_pdf; - hit_pdf.x = texelFetch(pdfBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).r; - hit_pdf.y = texelFetch(pdfBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).r; - hit_pdf.z = texelFetch(pdfBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).r; - hit_pdf.w = texelFetch(pdfBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).r; + hit_pdf.x = texelFetch(pdfBuffer, texel + neighbors[0 + neighborOffset], 0).r; + hit_pdf.y = texelFetch(pdfBuffer, texel + neighbors[1 + neighborOffset], 0).r; + hit_pdf.z = texelFetch(pdfBuffer, texel + neighbors[2 + neighborOffset], 0).r; + hit_pdf.w = texelFetch(pdfBuffer, texel + neighbors[3 + neighborOffset], 0).r; ivec4 hit_data[2]; - hit_data[0].xy = texelFetch(hitBuffer, halfres_texel + neighbors[0 + neighborOffset], 0).rg; - hit_data[0].zw = texelFetch(hitBuffer, halfres_texel + neighbors[1 + neighborOffset], 0).rg; - hit_data[1].xy = texelFetch(hitBuffer, halfres_texel + neighbors[2 + neighborOffset], 0).rg; - hit_data[1].zw = texelFetch(hitBuffer, halfres_texel + neighbors[3 + neighborOffset], 0).rg; + hit_data[0].xy = texelFetch(hitBuffer, texel + neighbors[0 + neighborOffset], 0).rg; + hit_data[0].zw = texelFetch(hitBuffer, texel + neighbors[1 + neighborOffset], 0).rg; + hit_data[1].xy = texelFetch(hitBuffer, texel + neighbors[2 + neighborOffset], 0).rg; + hit_data[1].zw = texelFetch(hitBuffer, texel + neighbors[3 + neighborOffset], 0).rg; /* Find Planar Reflections affecting this pixel */ PlanarData pd; @@ -542,7 +525,7 @@ void main() for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) { pd = planars_data[i]; - float fade = probe_attenuation_planar(pd, worldPosition, N, 0.0); + float fade = probe_attenuation_planar(pd, P, N, 0.0); if (fade > 0.5) { planar_index = float(i); @@ -554,7 +537,7 @@ void main() hit_data, pd, planar_index, - worldPosition, + P, N, V, roughnessSquared, @@ -564,19 +547,51 @@ void main() } /* Compute SSR contribution */ - if (weight_acc > 0.0) { - ssr_accum /= weight_acc; - /* fade between 0.5 and 1.0 roughness */ - ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness); - accumulate_light(ssr_accum.rgb, ssr_accum.a, spec_accum); + ssr_accum *= (weight_acc == 0.0) ? 0.0 : (1.0 / weight_acc); + /* fade between 0.5 and 1.0 roughness */ + ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness); + + cl_eval.raytrace_radiance = ssr_accum.rgb * ssr_accum.a; + cl_common.specular_accum -= ssr_accum.a; +} + +CLOSURE_EVAL_FUNCTION_DECLARE_1(ssr_resolve, Glossy) + +void main() +{ + ivec2 texel = ivec2(gl_FragCoord.xy); + float depth = texelFetch(depthBuffer, texel, 0).r; + + if (depth == 1.0) { + discard; } - /* If SSR contribution is not 1.0, blend with cubemaps */ - if (spec_accum.a < 1.0) { - fallback_cubemap(N, V, worldPosition, viewPosition, roughness, roughnessSquared, spec_accum); + vec4 speccol_roughness = texelFetch(specroughBuffer, texel, 0).rgba; + vec3 brdf = speccol_roughness.rgb; + float roughness = speccol_roughness.a; + + if (max_v3(brdf) <= 0.0) { + discard; } - fragColor = vec4(spec_accum.rgb * speccol_roughness.rgb, 1.0); + viewPosition = get_view_space_from_depth(uvcoordsvar.xy, depth); + worldPosition = transform_point(ViewMatrixInverse, viewPosition); + + vec2 normal_encoded = texelFetch(normalBuffer, texel, 0).rg; + viewNormal = normal_decode(normal_encoded, viewCameraVec); + worldNormal = transform_direction(ViewMatrixInverse, viewNormal); + + CLOSURE_VARS_DECLARE_1(Glossy); + + in_Glossy_0.N = worldNormal; + in_Glossy_0.roughness = roughness; + + /* Do a full deferred evaluation of the glossy BSDF. The only difference is that we inject the + * SSR resolve before the cubemap iter. BRDF term is already computed during main pass and is + * passed as specular color. */ + CLOSURE_EVAL_FUNCTION_1(ssr_resolve, Glossy); + + fragColor = vec4(out_Glossy_0.radiance * brdf, 1.0); } #endif diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl index a2e25b83532..fe4f3dcaa2f 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl @@ -137,9 +137,9 @@ float probe_attenuation_planar(PlanarData pd, vec3 W, vec3 N, float roughness) return fac; } -float probe_attenuation_grid(GridData gd, mat4 localmat, vec3 W, out vec3 localpos) +float probe_attenuation_grid(GridData gd, vec3 W, out vec3 localpos) { - localpos = transform_point(localmat, W); + localpos = transform_point(gd.localmat, W); vec3 pos_to_edge = max(vec3(0.0), abs(localpos) - 1.0); float fade = length(pos_to_edge); return saturate(-fade * gd.g_atten_scale + gd.g_atten_bias); @@ -183,8 +183,7 @@ vec3 probe_evaluate_world_spec(vec3 R, float roughness) return textureLod_cubemapArray(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax).rgb; } -vec3 probe_evaluate_planar( - float id, PlanarData pd, vec3 W, vec3 N, vec3 V, float roughness, inout float fade) +vec3 probe_evaluate_planar(int id, PlanarData pd, vec3 W, vec3 N, vec3 V, float roughness) { /* Find view vector / reflection plane intersection. */ vec3 point_on_plane = line_plane_intersect(W, V, pd.pl_plane_eq); @@ -226,7 +225,7 @@ void fallback_cubemap(vec3 N, #ifdef SSR_AO vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); vec3 bent_normal; - float final_ao = occlusion_compute(N, viewPosition, 1.0, rand, bent_normal); + float final_ao = occlusion_compute(N, viewPosition, rand, bent_normal); final_ao = specular_occlusion(dot(N, V), final_ao, roughness); #else const float final_ao = 1.0; diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl index 949e4d8f04f..b0845057a43 100644 --- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl @@ -252,32 +252,29 @@ float light_attenuation(LightData ld, vec4 l_vector) return vis; } -float light_shadowing(LightData ld, - vec3 W, -#ifndef VOLUMETRICS - vec3 viewPosition, - float tracing_depth, - vec3 true_normal, - float rand_x, - const bool use_contact_shadows, -#endif - float vis) +float light_shadowing(LightData ld, vec3 W, float vis) { #if !defined(VOLUMETRICS) || defined(VOLUME_SHADOW) - /* shadowing */ if (ld.l_shadowid >= 0.0 && vis > 0.001) { - if (ld.l_type == SUN) { vis *= sample_cascade_shadow(int(ld.l_shadowid), W); } else { vis *= sample_cube_shadow(int(ld.l_shadowid), W); } + } +#endif + return vis; +} -# ifndef VOLUMETRICS +#ifndef VOLUMETRICS +float light_contact_shadows( + LightData ld, vec3 P, vec3 vP, float tracing_depth, vec3 vNg, float rand_x, float vis) +{ + if (ld.l_shadowid >= 0.0 && vis > 0.001) { ShadowData sd = shadows_data[int(ld.l_shadowid)]; /* Only compute if not already in shadow. */ - if (use_contact_shadows && sd.sh_contact_dist > 0.0 && vis > 1e-8) { + if (sd.sh_contact_dist > 0.0) { /* Contact Shadows. */ vec3 ray_ori, ray_dir; float trace_distance; @@ -287,54 +284,34 @@ float light_shadowing(LightData ld, ray_dir = shadows_cascade_data[int(sd.sh_data_index)].sh_shadow_vec * trace_distance; } else { - ray_dir = shadows_cube_data[int(sd.sh_data_index)].position.xyz - W; + ray_dir = shadows_cube_data[int(sd.sh_data_index)].position.xyz - P; float len = length(ray_dir); trace_distance = min(sd.sh_contact_dist, len); ray_dir *= trace_distance / len; } ray_dir = transform_direction(ViewMatrix, ray_dir); - ray_ori = vec3(viewPosition.xy, tracing_depth) + true_normal * sd.sh_contact_offset; + ray_ori = vec3(vP.xy, tracing_depth) + vNg * sd.sh_contact_offset; vec3 hit_pos = raycast( -1, ray_ori, ray_dir, sd.sh_contact_thickness, rand_x, 0.1, 0.001, false); if (hit_pos.z > 0.0) { hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z); - float hit_dist = distance(viewPosition, hit_pos); + float hit_dist = distance(vP, hit_pos); float dist_ratio = hit_dist / trace_distance; - return vis * saturate(dist_ratio * 3.0 - 2.0); + return saturate(dist_ratio * 3.0 - 2.0); } } -# endif /* VOLUMETRICS */ } -#endif - - return vis; + return 1.0; } +#endif /* VOLUMETRICS */ -float light_visibility(LightData ld, - vec3 W, -#ifndef VOLUMETRICS - vec3 viewPosition, - float tracing_depth, - vec3 true_normal, - float rand_x, - const bool use_contact_shadows, -#endif - vec4 l_vector) +float light_visibility(LightData ld, vec3 W, vec4 l_vector) { float l_atten = light_attenuation(ld, l_vector); - return light_shadowing(ld, - W, -#ifndef VOLUMETRICS - viewPosition, - tracing_depth, - true_normal, - rand_x, - use_contact_shadows, -#endif - l_atten); + return light_shadowing(ld, W, l_atten); } float light_diffuse(LightData ld, vec3 N, vec3 V, vec4 l_vector) diff --git a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl index 34999076f9c..fd08dfda060 100644 --- a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl @@ -5,8 +5,12 @@ #pragma BLENDER_REQUIRE(common_view_lib.glsl) #pragma BLENDER_REQUIRE(common_uniforms_lib.glsl) -#pragma BLENDER_REQUIRE(closure_lib.glsl) -#pragma BLENDER_REQUIRE(closure_lit_lib.glsl) +#pragma BLENDER_REQUIRE(closure_type_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_diffuse_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_translucent_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_refraction_lib.glsl) #pragma BLENDER_REQUIRE(surface_lib.glsl) #ifdef USE_ALPHA_HASH diff --git a/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl index e0b9d4a60db..19eecdb5b79 100644 --- a/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/shadow_accum_frag.glsl @@ -39,7 +39,7 @@ void main() vec3 viewPosition = get_view_space_from_depth(uvs, depth); vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition); - vec3 true_normal = normalize(cross(dFdx(viewPosition), dFdy(viewPosition))); + vec3 true_normal = safe_normalize(cross(dFdx(viewPosition), dFdy(viewPosition))); for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) { LightData ld = lights_data[i]; @@ -48,8 +48,10 @@ void main() l_vector.xyz = ld.l_position - worldPosition; l_vector.w = length(l_vector.xyz); - float l_vis = light_shadowing( - ld, worldPosition, viewPosition, tracing_depth, true_normal, rand.x, true, 1.0); + float l_vis = light_shadowing(ld, worldPosition, 1.0); + + l_vis *= light_contact_shadows( + ld, worldPosition, viewPosition, tracing_depth, true_normal, rand.x, 1.0); accum_light += l_vis; } diff --git a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl index d0297c8cb7f..62930b9944a 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl @@ -3,8 +3,13 @@ #pragma BLENDER_REQUIRE(common_hair_lib.glsl) #pragma BLENDER_REQUIRE(common_utiltex_lib.glsl) -#pragma BLENDER_REQUIRE(closure_lib.glsl) -#pragma BLENDER_REQUIRE(closure_lit_lib.glsl) +#pragma BLENDER_REQUIRE(closure_type_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_diffuse_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_glossy_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_translucent_lib.glsl) +#pragma BLENDER_REQUIRE(closure_eval_refraction_lib.glsl) + #pragma BLENDER_REQUIRE(surface_lib.glsl) #pragma BLENDER_REQUIRE(volumetric_lib.glsl) diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl index b93a3a23eff..e80dc1761f0 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl @@ -13,7 +13,15 @@ uniform float refractionDepth; vec3 worldNormal; \ vec3 viewNormal; -#ifdef GPU_GEOMETRY_SHADER +#if defined(STEP_RESOLVE) || defined(STEP_RAYTRACE) +/* SSR will set these global variables itself. + * Also make false positive compiler warnings disapear by setting values. */ +vec3 worldPosition = vec3(0); +vec3 viewPosition = vec3(0); +vec3 worldNormal = vec3(0); +vec3 viewNormal = vec3(0); + +#elif defined(GPU_GEOMETRY_SHADER) in ShaderStageInterface{SURFACE_INTERFACE} dataIn[]; out ShaderStageInterface{SURFACE_INTERFACE} dataOut; @@ -24,7 +32,7 @@ out ShaderStageInterface{SURFACE_INTERFACE} dataOut; dataOut.worldNormal = dataIn[vert].worldNormal; \ dataOut.viewNormal = dataIn[vert].viewNormal; -#else +#else /* GPU_VERTEX_SHADER || GPU_FRAGMENT_SHADER*/ IN_OUT ShaderStageInterface{SURFACE_INTERFACE}; diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl index bac69ab0355..25661a0d731 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl @@ -1,6 +1,6 @@ #pragma BLENDER_REQUIRE(volumetric_lib.glsl) -#pragma BLENDER_REQUIRE(closure_lib.glsl) +#pragma BLENDER_REQUIRE(closure_type_lib.glsl) /* Based on Frosbite Unified Volumetric. * https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite */ diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl index 9cb1723346d..0213ba2622b 100644 --- a/source/blender/draw/intern/shaders/common_math_lib.glsl +++ b/source/blender/draw/intern/shaders/common_math_lib.glsl @@ -96,6 +96,7 @@ float len_squared(vec2 a) { return dot(a, a); } #define weighted_sum(val0, val1, val2, val3, weights) ((val0 * weights[0] + val1 * weights[1] + val2 * weights[2] + val3 * weights[3]) * safe_rcp(sum(weights))); #define weighted_sum_array(val, weights) ((val[0] * weights[0] + val[1] * weights[1] + val[2] * weights[2] + val[3] * weights[3]) * safe_rcp(sum(weights))); + /* clang-format on */ #define saturate(a) clamp(a, 0.0, 1.0) @@ -112,6 +113,15 @@ float distance_squared(vec3 a, vec3 b) return dot(a, a); } +vec3 safe_normalize(vec3 v) +{ + float len = length(v); + if (isnan(len) || len == 0.0) { + return vec3(1.0, 0.0, 0.0); + } + return v / len; +} + /** \} */ /* ---------------------------------------------------------------------- */ |