diff options
Diffstat (limited to 'source/blender/gpu/shaders')
9 files changed, 328 insertions, 520 deletions
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl index eea8d19efce..d718cc3f4fe 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl @@ -4,7 +4,7 @@ void node_ambient_occlusion( { vec3 bent_normal; vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); - result_ao = occlusion_compute(normalize(normal), viewPosition, 1.0, rand, bent_normal); + result_ao = occlusion_compute(normalize(normal), viewPosition, rand, bent_normal); result_color = result_ao * color; } #else diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl index d7b6143d2a1..01a16e194ca 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl @@ -1,12 +1,27 @@ #ifndef VOLUMETRICS + +CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_diffuse, Diffuse) + void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result) { - N = normalize(N); + CLOSURE_VARS_DECLARE_1(Diffuse); + + in_Diffuse_0.N = N; /* Normalized during eval. */ + in_Diffuse_0.albedo = color.rgb; + + CLOSURE_EVAL_FUNCTION_1(node_bsdf_diffuse, Diffuse); + result = CLOSURE_DEFAULT; - eevee_closure_diffuse(N, color.rgb, 1.0, true, result.radiance); - result.radiance = render_pass_diffuse_mask(color.rgb, result.radiance * color.rgb); - closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result); + + out_Diffuse_0.radiance = render_pass_diffuse_mask(vec3(1.0), out_Diffuse_0.radiance); + out_Diffuse_0.radiance *= color.rgb; + + result.radiance = out_Diffuse_0.radiance; + + /* TODO(fclem) Try to not use this. */ + closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1.0, result); } + #else /* Stub diffuse because it is not compatible with volumetrics. */ # define node_bsdf_diffuse(a, b, c, d) (d = CLOSURE_DEFAULT) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl index 443bab7529b..429c4ed41ac 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl @@ -1,4 +1,7 @@ #ifndef VOLUMETRICS + +CLOSURE_EVAL_FUNCTION_DECLARE_3(node_eevee_specular, Diffuse, Glossy, Glossy) + void node_eevee_specular(vec4 diffuse, vec4 specular, float roughness, @@ -12,34 +15,63 @@ void node_eevee_specular(vec4 diffuse, float ssr_id, out Closure result) { - normal = normalize(normal); - - vec3 out_diff, out_spec, ssr_spec; - eevee_closure_default_clearcoat(normal, - diffuse.rgb, - specular.rgb, - vec3(1.0), - int(ssr_id), - roughness, - clearcoat_normal, - clearcoat * 0.25, - clearcoat_roughness, - occlusion, - true, - out_diff, - out_spec, - ssr_spec); - - float alpha = 1.0 - transp; + CLOSURE_VARS_DECLARE_3(Diffuse, Glossy, Glossy); + + in_common.occlusion = occlusion; + + in_Diffuse_0.N = normal; /* Normalized during eval. */ + in_Diffuse_0.albedo = diffuse.rgb; + + in_Glossy_1.N = normal; /* Normalized during eval. */ + in_Glossy_1.roughness = roughness; + + in_Glossy_2.N = clearcoat_normal; /* Normalized during eval. */ + in_Glossy_2.roughness = clearcoat_roughness; + + CLOSURE_EVAL_FUNCTION_3(node_eevee_specular, Diffuse, Glossy, Glossy); + result = CLOSURE_DEFAULT; - result.radiance = render_pass_diffuse_mask(diffuse.rgb, out_diff * diffuse.rgb); - result.radiance += render_pass_glossy_mask(vec3(1.0), out_spec); - result.radiance += render_pass_emission_mask(emissive.rgb); - result.radiance *= alpha; - result.transmittance = vec3(transp); - closure_load_ssr_data(ssr_spec * alpha, roughness, normal, viewCameraVec, int(ssr_id), result); + { + /* Diffuse. */ + out_Diffuse_0.radiance = render_pass_diffuse_mask(vec3(1), out_Diffuse_0.radiance); + out_Diffuse_0.radiance *= in_Diffuse_0.albedo; + result += out_Diffuse_0.radiance; + } + { + /* Glossy. */ + float NV = dot(in_Glossy_1.N, cameraVec); + vec2 split_sum = brdf_lut(NV, in_Glossy_1.roughness); + vec3 brdf = F_brdf_single_scatter(specular.rgb, vec3(1.0), split_sum); + + out_Glossy_1.radiance = closure_mask_ssr_radiance(out_Glossy_1.radiance, ssr_id); + out_Glossy_1.radiance *= brdf; + out_Glossy_1.radiance = render_pass_glossy_mask(spec_color, out_Glossy_1.radiance); + closure_load_ssr_data( + out_Glossy_1.radiance, in_Glossy_1.roughness, in_Glossy_1.N, ssr_id, result); + } + { + /* Clearcoat. */ + float NV = dot(in_Glossy_2.N, cameraVec); + vec2 split_sum = brdf_lut(NV, in_Glossy_2.roughness); + vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum); + + out_Glossy_2.radiance *= brdf * clearcoat * 0.25; + out_Glossy_2.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_2.radiance); + result.radiance += out_Glossy_2.radiance; + } + { + /* Emission. */ + vec3 out_emission_radiance = render_pass_emission_mask(emission.rgb); + result.radiance += out_emission_radiance; + } + + float trans = 1.0 - trans; + result.transmittance = vec3(trans); + result.radiance *= alpha; + result.ssr_data.rgb *= alpha; } + #else /* Stub specular because it is not compatible with volumetrics. */ # define node_eevee_specular(a, b, c, d, e, f, g, h, i, j, k, result) (result = CLOSURE_DEFAULT) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl index c328b4800bc..ba02ae6d886 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_glass.glsl @@ -1,4 +1,7 @@ #ifndef VOLUMETRICS + +CLOSURE_EVAL_FUNCTION_DECLARE_2(node_bsdf_glass, Glossy, Refraction) + void node_bsdf_glass(vec4 color, float roughness, float ior, @@ -7,32 +10,38 @@ void node_bsdf_glass(vec4 color, float ssr_id, out Closure result) { - N = normalize(N); - vec3 out_spec, out_refr, ssr_spec; - vec3 refr_color = (refractionDepth > 0.0) ? color.rgb * color.rgb : - color.rgb; /* Simulate 2 transmission event */ - eevee_closure_glass(N, - vec3(1.0), - /* HACK: Pass the multiscatter flag as the sign to not add closure - * variations or increase register usage. */ - (use_multiscatter != 0.0) ? vec3(1.0) : -vec3(1.0), - int(ssr_id), - roughness, - 1.0, - ior, - true, - out_spec, - out_refr, - ssr_spec); - float fresnel = F_eta(ior, dot(N, cameraVec)); - vec3 vN = mat3(ViewMatrix) * N; + CLOSURE_VARS_DECLARE_2(Glossy, Refraction); + + in_Glossy_0.N = N; /* Normalized during eval. */ + in_Glossy_0.roughness = roughness; + + in_Refraction_1.N = N; /* Normalized during eval. */ + in_Refraction_1.roughness = roughness; + in_Refraction_1.ior = ior; + + CLOSURE_EVAL_FUNCTION_2(node_bsdf_glass, Glossy, Refraction); + result = CLOSURE_DEFAULT; - result.radiance = render_pass_glossy_mask(refr_color, out_refr * refr_color) * (1.0 - fresnel); - result.radiance += render_pass_glossy_mask(color.rgb, out_spec * color.rgb) * fresnel; + float fresnel = F_eta(in_Refraction_1.ior, dot(in_Glossy_0.N, cameraVec)); + + vec2 split_sum = brdf_lut(dot(in_Glossy_0.N, cameraVec), in_Glossy_0.roughness); + vec3 brdf = (use_multiscatter != 0.0) ? F_brdf_multi_scatter(vec3(1.0), vec3(1.0), split_sum) : + F_brdf_single_scatter(vec3(1.0), vec3(1.0), split_sum); + out_Glossy_0.radiance = closure_mask_ssr_radiance(out_Glossy_0.radiance, ssr_id); + out_Glossy_0.radiance *= brdf; + out_Glossy_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Glossy_0.radiance); + out_Glossy_0.radiance *= color.rgb * fresnel; closure_load_ssr_data( - ssr_spec * color.rgb * fresnel, roughness, N, viewCameraVec, int(ssr_id), result); + out_Glossy_0.radiance, in_Glossy_0.roughness, in_Glossy_0.N, ssr_id, result); + + out_Refraction_1.radiance = render_pass_glossy_mask(vec3(1.0), out_Refraction_1.radiance); + out_Refraction_1.radiance *= color.rgb * (1.0 - fresnel); + /* Simulate 2nd absorption event. */ + out_Refraction_1.radiance *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); + result.radiance += out_Refraction_1.radiance; } + #else /* Stub glass because it is not compatible with volumetrics. */ # define node_bsdf_glass(a, b, c, d, e, f, result) (result = CLOSURE_DEFAULT) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl index 36675cf720d..ca7c3749597 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl @@ -1,23 +1,32 @@ #ifndef VOLUMETRICS + +CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_glossy, Glossy) + void node_bsdf_glossy( vec4 color, float roughness, vec3 N, float use_multiscatter, float ssr_id, out Closure result) { - N = normalize(N); - vec3 out_spec, ssr_spec; - eevee_closure_glossy(N, - vec3(1.0), - use_multiscatter != 0.0 ? vec3(1.0) : vec3(-1.0), /* HACK */ - int(ssr_id), - roughness, - 1.0, - true, - out_spec, - ssr_spec); - vec3 vN = mat3(ViewMatrix) * N; + bool do_ssr = (ssrToggle && int(ssr_id) == outputSsrId); + + CLOSURE_VARS_DECLARE_1(Glossy); + + in_Glossy_0.N = N; /* Normalized during eval. */ + in_Glossy_0.roughness = roughness; + + CLOSURE_EVAL_FUNCTION_1(node_bsdf_glossy, Glossy); + result = CLOSURE_DEFAULT; - result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec) * color.rgb; - closure_load_ssr_data(ssr_spec * color.rgb, roughness, N, viewCameraVec, int(ssr_id), result); + + vec2 split_sum = brdf_lut(dot(in_Glossy_0.N, cameraVec), in_Glossy_0.roughness); + vec3 brdf = (use_multiscatter != 0.0) ? F_brdf_multi_scatter(vec3(1.0), vec3(1.0), split_sum) : + F_brdf_single_scatter(vec3(1.0), vec3(1.0), split_sum); + out_Glossy_0.radiance = closure_mask_ssr_radiance(out_Glossy_0.radiance, ssr_id); + out_Glossy_0.radiance *= brdf; + out_Glossy_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Glossy_0.radiance); + out_Glossy_0.radiance *= color.rgb; + closure_load_ssr_data( + out_Glossy_0.radiance, in_Glossy_0.roughness, in_Glossy_0.N, ssr_id, result); } + #else /* Stub glossy because it is not compatible with volumetrics. */ # define node_bsdf_glossy(a, b, c, d, e, result) (result = CLOSURE_DEFAULT) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl index 3bd578e1ffc..15958dcf65e 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl @@ -1,41 +1,20 @@ #ifndef VOLUMETRICS vec3 tint_from_color(vec3 color) { - float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */ - return (lum > 0) ? color / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */ + float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */ + return (lum > 0.0) ? color / lum : vec3(0.0); /* normalize lum. to isolate hue+sat */ } -void convert_metallic_to_specular_tinted(vec3 basecol, - vec3 basecol_tint, - float metallic, - float specular_fac, - float specular_tint, - out vec3 diffuse, - out vec3 f0) -{ - vec3 tmp_col = mix(vec3(1.0), basecol_tint, specular_tint); - f0 = mix((0.08 * specular_fac) * tmp_col, basecol, metallic); - diffuse = basecol * (1.0 - metallic); -} - -/* Output sheen is to be multiplied by sheen_color. */ -void principled_sheen(float NV, - vec3 basecol_tint, - float sheen, - float sheen_tint, - out float out_sheen, - out vec3 sheen_color) +float principled_sheen(float NV) { float f = 1.0 - NV; - /* Temporary fix for T59784. Normal map seems to contain NaNs for tangent space normal maps, - * therefore we need to clamp value. */ - f = clamp(f, 0.0, 1.0); /* Empirical approximation (manual curve fitting). Can be refined. */ - out_sheen = f * f * f * 0.077 + f * 0.01 + 0.00026; - - sheen_color = sheen * mix(vec3(1.0), basecol_tint, sheen_tint); + float sheen = f * f * f * 0.077 + f * 0.01 + 0.00026; + return sheen; } +CLOSURE_EVAL_FUNCTION_DECLARE_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction) + void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_radius, @@ -59,434 +38,163 @@ void node_bsdf_principled(vec4 base_color, vec3 N, vec3 CN, vec3 T, - vec3 I, - float use_multiscatter, + const float do_diffuse, + const float do_clearcoat, + const float do_refraction, + const float do_multiscatter, float ssr_id, float sss_id, vec3 sss_scale, out Closure result) { - N = normalize(N); - ior = max(ior, 1e-5); - metallic = saturate(metallic); - transmission = saturate(transmission); - float m_transmission = 1.0 - transmission; - - float dielectric = 1.0 - metallic; - transmission *= dielectric; - sheen *= dielectric; - subsurface_color *= dielectric; - - vec3 diffuse, f0, out_diff, out_spec, out_refr, ssr_spec, sheen_color; - float out_sheen; - vec3 ctint = tint_from_color(base_color.rgb); - convert_metallic_to_specular_tinted( - base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0); - - float NV = dot(N, cameraVec); - principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color); - - vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic); - - /* Far from being accurate, but 2 glossy evaluation is too expensive. - * Most noticeable difference is at grazing angles since the bsdf lut - * f0 color interpolation is done on top of this interpolation. */ - vec3 f0_glass = mix(vec3(1.0), base_color.rgb, specular_tint); - float fresnel = F_eta(ior, NV); - vec3 spec_col = F_color_blend(ior, fresnel, f0_glass) * fresnel; - f0 = mix(f0, spec_col, transmission); - f90 = mix(f90, spec_col, transmission); - - /* Really poor approximation but needed to workaround issues with renderpasses. */ - spec_col = mix(vec3(1.0), spec_col, transmission); /* Match cycles. */ - spec_col += float(clearcoat > 1e-5); - - vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface); - - float sss_scalef = avg(sss_scale) * subsurface; - eevee_closure_principled(N, - mixed_ss_base_color, - f0, - /* HACK: Pass the multiscatter flag as the sign to not add closure - * variations or increase register usage. */ - (use_multiscatter != 0.0) ? f90 : -f90, - int(ssr_id), - roughness, - CN, - clearcoat * 0.25, - clearcoat_roughness, - 1.0, - sss_scalef, - ior, - true, - out_diff, - out_spec, - out_refr, - ssr_spec); - - vec3 refr_color = base_color.rgb; - refr_color *= (refractionDepth > 0.0) ? refr_color : - vec3(1.0); /* Simulate 2 transmission event */ - refr_color *= saturate(1.0 - fresnel) * transmission; - - sheen_color *= m_transmission; - mixed_ss_base_color *= m_transmission; - - result = CLOSURE_DEFAULT; - result.radiance = render_pass_glossy_mask(refr_color, out_refr * refr_color); - result.radiance += render_pass_glossy_mask(spec_col, out_spec); - /* Coarse approx. */ - result.radiance += render_pass_diffuse_mask(sheen_color, out_diff * out_sheen * sheen_color); - result.radiance += render_pass_emission_mask(emission.rgb * emission_strength); - result.radiance *= alpha; - closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); - - mixed_ss_base_color *= alpha; - closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result); - result.transmittance = vec3(1.0 - alpha); -} - -void node_bsdf_principled_dielectric(vec4 base_color, - float subsurface, - vec3 subsurface_radius, - vec4 subsurface_color, - float metallic, - float specular, - float specular_tint, - float roughness, - float anisotropic, - float anisotropic_rotation, - float sheen, - float sheen_tint, - float clearcoat, - float clearcoat_roughness, - float ior, - float transmission, - float transmission_roughness, - vec4 emission, - float emission_strength, - float alpha, - vec3 N, - vec3 CN, - vec3 T, - vec3 I, - float use_multiscatter, - float ssr_id, - float sss_id, - vec3 sss_scale, - out Closure result) -{ - N = normalize(N); metallic = saturate(metallic); - float dielectric = 1.0 - metallic; - - vec3 diffuse, f0, out_diff, out_spec, ssr_spec, sheen_color; - float out_sheen; - vec3 ctint = tint_from_color(base_color.rgb); - convert_metallic_to_specular_tinted( - base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0); - - vec3 f90 = mix(vec3(1.0), f0, (1.0 - specular) * metallic); - - float NV = dot(N, cameraVec); - principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color); - - eevee_closure_default(N, - diffuse, - f0, - /* HACK: Pass the multiscatter flag as the sign to not add closure - * variations or increase register usage. */ - (use_multiscatter != 0.0) ? f90 : -f90, - int(ssr_id), - roughness, - 1.0, - true, - out_diff, - out_spec, - ssr_spec); + transmission = saturate(transmission); + float diffuse_weight = (1.0 - transmission) * (1.0 - metallic); + transmission *= (1.0 - metallic); + float specular_weight = (1.0 - transmission); + clearcoat = max(clearcoat, 0.0); + transmission_roughness = 1.0 - (1.0 - roughness) * (1.0 - transmission_roughness); - result = CLOSURE_DEFAULT; - result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec); - result.radiance += render_pass_diffuse_mask(sheen_color, out_diff * out_sheen * sheen_color); - result.radiance += render_pass_diffuse_mask(diffuse, out_diff * diffuse); - result.radiance += render_pass_emission_mask(emission.rgb * emission_strength); - result.radiance *= alpha; - closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); + CLOSURE_VARS_DECLARE_4(Diffuse, Glossy, Glossy, Refraction); - result.transmittance = vec3(1.0 - alpha); -} + in_Diffuse_0.N = N; /* Normalized during eval. */ + in_Diffuse_0.albedo = mix(base_color.rgb, subsurface_color.rgb, subsurface); -void node_bsdf_principled_metallic(vec4 base_color, - float subsurface, - vec3 subsurface_radius, - vec4 subsurface_color, - float metallic, - float specular, - float specular_tint, - float roughness, - float anisotropic, - float anisotropic_rotation, - float sheen, - float sheen_tint, - float clearcoat, - float clearcoat_roughness, - float ior, - float transmission, - float transmission_roughness, - vec4 emission, - float emission_strength, - float alpha, - vec3 N, - vec3 CN, - vec3 T, - vec3 I, - float use_multiscatter, - float ssr_id, - float sss_id, - vec3 sss_scale, - out Closure result) -{ - N = normalize(N); - vec3 out_spec, ssr_spec; - - vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic); - - eevee_closure_glossy(N, - base_color.rgb, - /* HACK: Pass the multiscatter flag as the sign to not add closure - * variations or increase register usage. */ - (use_multiscatter != 0.0) ? f90 : -f90, - int(ssr_id), - roughness, - 1.0, - true, - out_spec, - ssr_spec); + in_Glossy_1.N = N; /* Normalized during eval. */ + in_Glossy_1.roughness = roughness; - result = CLOSURE_DEFAULT; - result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec); - result.radiance += render_pass_emission_mask(emission.rgb * emission_strength); - result.radiance *= alpha; - closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); + in_Glossy_2.N = CN; /* Normalized during eval. */ + in_Glossy_2.roughness = clearcoat_roughness; - result.transmittance = vec3(1.0 - alpha); -} + in_Refraction_3.N = N; /* Normalized during eval. */ + in_Refraction_3.roughness = do_multiscatter != 0.0 ? roughness : transmission_roughness; + in_Refraction_3.ior = ior; + -void node_bsdf_principled_clearcoat(vec4 base_color, - float subsurface, - vec3 subsurface_radius, - vec4 subsurface_color, - float metallic, - float specular, - float specular_tint, - float roughness, - float anisotropic, - float anisotropic_rotation, - float sheen, - float sheen_tint, - float clearcoat, - float clearcoat_roughness, - float ior, - float transmission, - float transmission_roughness, - vec4 emission, - float emission_strength, - float alpha, - vec3 N, - vec3 CN, - vec3 T, - vec3 I, - float use_multiscatter, - float ssr_id, - float sss_id, - vec3 sss_scale, - out Closure result) -{ - vec3 out_spec, ssr_spec; - N = normalize(N); - - vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic); - - eevee_closure_clearcoat(N, - base_color.rgb, - /* HACK: Pass the multiscatter flag as the sign to not add closure - * variations or increase register usage. */ - (use_multiscatter != 0.0) ? f90 : -f90, - int(ssr_id), - roughness, - CN, - clearcoat * 0.25, - clearcoat_roughness, - 1.0, - true, - out_spec, - ssr_spec); - /* Match cycles. */ - float spec_col = 1.0 + float(clearcoat > 1e-5); + CLOSURE_EVAL_FUNCTION_4(node_bsdf_principled, Diffuse, Glossy, Glossy, Refraction); result = CLOSURE_DEFAULT; - result.radiance = render_pass_glossy_mask(vec3(spec_col), out_spec); - result.radiance += render_pass_emission_mask(emission.rgb * emission_strength); - result.radiance *= alpha; - closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); + /* This will tag the whole eval for optimisation. */ + if (do_diffuse == 0.0) { + out_Diffuse_0.radiance = vec3(0); + } + if (do_clearcoat == 0.0) { + out_Glossy_2.radiance = vec3(0); + } + if (do_refraction == 0.0) { + out_Refraction_3.radiance = vec3(0); + } + + /* Glossy_1 will always be evaluated. */ + float NV = dot(in_Glossy_1.N, cameraVec); + + vec3 base_color_tint = tint_from_color(base_color.rgb); + + /* TODO(fclem) This isn't good for rough glass using multiscatter (since the fresnel is applied + * on each microfacet in cycles). */ + float fresnel = F_eta(in_Refraction_3.ior, NV); + + { + /* Glossy reflections. + * Separate Glass reflections and main specular reflections to match Cycles renderpasses. */ + out_Glossy_1.radiance = closure_mask_ssr_radiance(out_Glossy_1.radiance, ssr_id); + + vec2 split_sum = brdf_lut(NV, roughness); + + vec3 glossy_radiance_final = vec3(0.0); + if (transmission > 1e-5) { + /* Glass Reflection: Reuse radiance from Glossy1. */ + vec3 out_glass_refl_radiance = out_Glossy_1.radiance; + + /* Poor approximation since we baked the LUT using a fixed IOR. */ + vec3 f0 = mix(vec3(1.0), base_color.rgb, specular_tint); + vec3 f90 = vec3(1); + + vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) : + F_brdf_single_scatter(f0, f90, split_sum); + + out_glass_refl_radiance *= brdf; + out_glass_refl_radiance = render_pass_glossy_mask(vec3(1), out_glass_refl_radiance); + out_glass_refl_radiance *= fresnel * transmission; + glossy_radiance_final += out_glass_refl_radiance; + } + if (specular_weight > 1e-5) { + vec3 dielectric_f0_color = mix(vec3(1.0), base_color_tint, specular_tint); + vec3 metallic_f0_color = base_color.rgb; + vec3 f0 = mix((0.08 * specular) * dielectric_f0_color, metallic_f0_color, metallic); + /* Cycles does this blending using the microfacet fresnel factor. However, our fresnel + * is already baked inside the split sum LUT. We approximate using by modifying the + * changing the f90 color directly in a non linear fashion. */ + vec3 f90 = mix(f0, vec3(1), fast_sqrt(specular)); + + vec3 brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) : + F_brdf_single_scatter(f0, f90, split_sum); + + out_Glossy_1.radiance *= brdf; + out_Glossy_1.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_1.radiance); + out_Glossy_1.radiance *= specular_weight; + glossy_radiance_final += out_Glossy_1.radiance; + } + + closure_load_ssr_data( + glossy_radiance_final, in_Glossy_1.roughness, in_Glossy_1.N, ssr_id, result); + } + + if (diffuse_weight > 1e-5) { + /* Mask over all diffuse radiance. */ + out_Diffuse_0.radiance *= diffuse_weight; + + /* Sheen Coarse approximation: We reuse the diffuse radiance and just scale it. */ + vec3 sheen_color = mix(vec3(1), base_color_tint, sheen_tint); + vec3 out_sheen_radiance = out_Diffuse_0.radiance * principled_sheen(NV); + out_sheen_radiance = render_pass_diffuse_mask(vec3(1), out_sheen_radiance); + out_sheen_radiance *= sheen * sheen_color; + result.radiance += out_sheen_radiance; + + /* Diffuse / Subsurface. */ + float scale = avg(sss_scale) * subsurface; + closure_load_sss_data(scale, out_Diffuse_0.radiance, in_Diffuse_0.albedo, int(sss_id), result); + } + + if (transmission > 1e-5) { + /* TODO(fclem) This could be going to a transmission render pass instead. */ + out_Refraction_3.radiance = render_pass_glossy_mask(vec3(1), out_Refraction_3.radiance); + out_Refraction_3.radiance *= base_color.rgb; + /* Simulate 2nd transmission event. */ + out_Refraction_3.radiance *= (refractionDepth > 0.0) ? base_color.rgb : vec3(1); + out_Refraction_3.radiance *= (1.0 - fresnel) * transmission; + result.radiance += out_Refraction_3.radiance; + } + + if (clearcoat > 1e-5) { + float NV = dot(in_Glossy_2.N, cameraVec); + vec2 split_sum = brdf_lut(NV, in_Glossy_2.roughness); + vec3 brdf = F_brdf_single_scatter(vec3(0.04), vec3(1.0), split_sum); + + out_Glossy_2.radiance *= brdf * clearcoat * 0.25; + out_Glossy_2.radiance = render_pass_glossy_mask(vec3(1), out_Glossy_2.radiance); + result.radiance += out_Glossy_2.radiance; + } + + { + vec3 out_emission_radiance = render_pass_emission_mask(emission.rgb); + out_emission_radiance *= emission_strength; + result.radiance += out_emission_radiance; + } result.transmittance = vec3(1.0 - alpha); -} - -void node_bsdf_principled_subsurface(vec4 base_color, - float subsurface, - vec3 subsurface_radius, - vec4 subsurface_color, - float metallic, - float specular, - float specular_tint, - float roughness, - float anisotropic, - float anisotropic_rotation, - float sheen, - float sheen_tint, - float clearcoat, - float clearcoat_roughness, - float ior, - float transmission, - float transmission_roughness, - vec4 emission, - float emission_strength, - float alpha, - vec3 N, - vec3 CN, - vec3 T, - vec3 I, - float use_multiscatter, - float ssr_id, - float sss_id, - vec3 sss_scale, - out Closure result) -{ - metallic = saturate(metallic); - N = normalize(N); - - vec3 diffuse, f0, out_diff, out_spec, ssr_spec, sheen_color; - float out_sheen; - vec3 ctint = tint_from_color(base_color.rgb); - convert_metallic_to_specular_tinted( - base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0); - - subsurface_color = subsurface_color * (1.0 - metallic); - vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface); - float sss_scalef = avg(sss_scale) * subsurface; - - float NV = dot(N, cameraVec); - principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color); - - vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic); - - eevee_closure_skin(N, - mixed_ss_base_color, - f0, - /* HACK: Pass the multiscatter flag as the sign to not add closure variations - * or increase register usage. */ - (use_multiscatter != 0.0) ? f90 : -f90, - int(ssr_id), - roughness, - 1.0, - sss_scalef, - true, - out_diff, - out_spec, - ssr_spec); - - result = CLOSURE_DEFAULT; - result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec); - result.radiance += render_pass_diffuse_mask(sheen_color, out_diff * out_sheen * sheen_color); - result.radiance += render_pass_emission_mask(emission.rgb * emission_strength); result.radiance *= alpha; - - closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); - - mixed_ss_base_color *= alpha; - closure_load_sss_data(sss_scalef, out_diff, mixed_ss_base_color, int(sss_id), result); - - result.transmittance = vec3(1.0 - alpha); + result.ssr_data.rgb *= alpha; +# ifdef USE_SSS + result.sss_irradiance *= alpha; +# endif } -void node_bsdf_principled_glass(vec4 base_color, - float subsurface, - vec3 subsurface_radius, - vec4 subsurface_color, - float metallic, - float specular, - float specular_tint, - float roughness, - float anisotropic, - float anisotropic_rotation, - float sheen, - float sheen_tint, - float clearcoat, - float clearcoat_roughness, - float ior, - float transmission, - float transmission_roughness, - vec4 emission, - float emission_strength, - float alpha, - vec3 N, - vec3 CN, - vec3 T, - vec3 I, - float use_multiscatter, - float ssr_id, - float sss_id, - vec3 sss_scale, - out Closure result) -{ - ior = max(ior, 1e-5); - N = normalize(N); - - vec3 f0, out_spec, out_refr, ssr_spec; - f0 = mix(vec3(1.0), base_color.rgb, specular_tint); - - eevee_closure_glass(N, - vec3(1.0), - vec3((use_multiscatter != 0.0) ? 1.0 : -1.0), - int(ssr_id), - roughness, - 1.0, - ior, - true, - out_spec, - out_refr, - ssr_spec); - - vec3 refr_color = base_color.rgb; - refr_color *= (refractionDepth > 0.0) ? refr_color : - vec3(1.0); /* Simulate 2 transmission events */ - - float fresnel = F_eta(ior, dot(N, cameraVec)); - vec3 spec_col = F_color_blend(ior, fresnel, f0); - spec_col *= fresnel; - refr_color *= (1.0 - fresnel); - - ssr_spec *= spec_col; - - result = CLOSURE_DEFAULT; - result.radiance = render_pass_glossy_mask(refr_color, out_refr * refr_color); - result.radiance += render_pass_glossy_mask(spec_col, out_spec * spec_col); - result.radiance += render_pass_emission_mask(emission.rgb * emission_strength); - result.radiance *= alpha; - closure_load_ssr_data(ssr_spec * alpha, roughness, N, viewCameraVec, int(ssr_id), result); - result.transmittance = vec3(1.0 - alpha); -} #else /* clang-format off */ /* Stub principled because it is not compatible with volumetrics. */ -# define node_bsdf_principled(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT) -# define node_bsdf_principled_dielectric(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT) -# define node_bsdf_principled_metallic(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT) -# define node_bsdf_principled_clearcoat(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT) -# define node_bsdf_principled_subsurface(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT) -# define node_bsdf_principled_glass(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT) +# define node_bsdf_principled(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, cc, dd, result) (result = CLOSURE_DEFAULT) /* clang-format on */ #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl index cd043020a7f..db820efa42e 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl @@ -1,15 +1,30 @@ #ifndef VOLUMETRICS + +CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_refraction, Refraction) + void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result) { - N = normalize(N); - vec3 out_refr; - color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */ - eevee_closure_refraction(N, roughness, ior, true, out_refr); - vec3 vN = mat3(ViewMatrix) * N; + CLOSURE_VARS_DECLARE_1(Refraction); + + in_Refraction_0.N = N; /* Normalized during eval. */ + in_Refraction_0.roughness = roughness; + in_Refraction_0.ior = ior; + + CLOSURE_EVAL_FUNCTION_1(node_bsdf_refraction, Refraction); + result = CLOSURE_DEFAULT; - result.ssr_normal = normal_encode(vN, viewCameraVec); - result.radiance = render_pass_glossy_mask(color.rgb, out_refr * color.rgb); + + out_Refraction_0.radiance = render_pass_glossy_mask(vec3(1.0), out_Refraction_0.radiance); + out_Refraction_0.radiance *= color.rgb; + /* Simulate 2nd absorption event. */ + out_Refraction_0.radiance *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); + + result.radiance = out_Refraction_0.radiance; + + /* TODO(fclem) Try to not use this. */ + result.ssr_normal = normal_encode(mat3(ViewMatrix) * in_Refraction_0.N, viewCameraVec); } + #else /* Stub refraction because it is not compatible with volumetrics. */ # define node_bsdf_refraction(a, b, c, d, e) (e = CLOSURE_DEFAULT) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl index c13b55513da..5a68f802659 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl @@ -1,4 +1,7 @@ #ifndef VOLUMETRICS + +CLOSURE_EVAL_FUNCTION_DECLARE_1(node_subsurface_scattering, Diffuse) + void node_subsurface_scattering(vec4 color, float scale, vec3 radius, @@ -8,20 +11,29 @@ void node_subsurface_scattering(vec4 color, float sss_id, out Closure result) { - N = normalize(N); - vec3 out_diff; - vec3 vN = mat3(ViewMatrix) * N; + CLOSURE_VARS_DECLARE_1(Diffuse); + + in_Diffuse_0.N = N; /* Normalized during eval. */ + in_Diffuse_0.albedo = color.rgb; + + CLOSURE_EVAL_FUNCTION_1(node_subsurface_scattering, Diffuse); + result = CLOSURE_DEFAULT; - closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result); - eevee_closure_subsurface(N, color.rgb, 1.0, scale, true, out_diff); + /* Not perfect for texture_blur values between 0.0 and 1.0. + * Interpolate between separated color and color applied on irradiance. */ + float one_minus_texture_blur = 1.0 - texture_blur; + vec3 sss_albedo = color.rgb * texture_blur + one_minus_texture_blur; + vec3 radiance_tint = color.rgb * one_minus_texture_blur + texture_blur; + /* Consider output radiance as irradiance. */ + out_Diffuse_0.radiance *= radiance_tint; + + closure_load_sss_data(scale, out_Diffuse_0.radiance, sss_albedo, int(sss_id), result); - /* Not perfect for texture_blur not exactly equal to 0.0 or 1.0. */ - vec3 sss_albedo = mix(color.rgb, vec3(1.0), texture_blur); - out_diff *= mix(vec3(1.0), color.rgb, texture_blur); - result.radiance = render_pass_sss_mask(sss_albedo); - closure_load_sss_data(scale, out_diff, sss_albedo, int(sss_id), result); + /* TODO(fclem) Try to not use this. */ + closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1.0, result); } + #else /* Stub subsurface scattering because it is not compatible with volumetrics. */ # define node_subsurface_scattering(a, b, c, d, e, f, g, h) (h = CLOSURE_DEFAULT) 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 79bfd9b24bb..80bd3941b22 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_translucent.glsl @@ -1,12 +1,20 @@ #ifndef VOLUMETRICS + +CLOSURE_EVAL_FUNCTION_DECLARE_1(node_bsdf_translucent, Translucent) + void node_bsdf_translucent(vec4 color, vec3 N, out Closure result) { - N = normalize(N); + CLOSURE_VARS_DECLARE_1(Translucent); + + in_Translucent_0.N = -N; /* Normalized during eval. */ + + CLOSURE_EVAL_FUNCTION_1(node_bsdf_translucent, Translucent); + result = CLOSURE_DEFAULT; - eevee_closure_diffuse(-N, color.rgb, 1.0, false, result.radiance); - closure_load_ssr_data(vec3(0.0), 0.0, N, viewCameraVec, -1, result); - result.radiance = render_pass_diffuse_mask(color.rgb, result.radiance * color.rgb); + closure_load_ssr_data(vec3(0.0), 0.0, -in_Translucent_0.N, -1.0, result); + result.radiance = render_pass_diffuse_mask(color.rgb, out_Translucent_0.radiance * color.rgb); } + #else /* Stub translucent because it is not compatible with volumetrics. */ # define node_bsdf_translucent(a, b, c) (c = CLOSURE_DEFAULT) |