diff options
7 files changed, 225 insertions, 47 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 769ac11736d..cd6b5db5b56 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -405,7 +405,7 @@ static void add_standard_uniforms( DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1); } - if (use_ssrefraction) { + if (use_refract || use_ssrefraction) { BLI_assert(refract_depth != NULL); DRW_shgroup_uniform_float(shgrp, "refractionDepth", refract_depth, 1); DRW_shgroup_uniform_texture_ref(shgrp, "colorBuffer", &vedata->txl->refract_color); @@ -563,6 +563,8 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, E datatoc_lit_surface_frag_glsl, datatoc_lit_surface_frag_glsl, datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, + datatoc_lit_surface_frag_glsl, datatoc_volumetric_lib_glsl); e_data.volume_shader_lib = BLI_string_joinN( 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 8b232bf14a4..286f00783d9 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -548,6 +548,14 @@ float F_eta(float eta, float cos_theta) return result; } +/* Fresnel color blend base on fresnel factor */ +vec3 F_color_blend(float eta, float fresnel, vec3 f0_color) +{ + float f0 = F_eta(eta, 1.0); + float fac = saturate((fresnel - f0) / max(1e-8, 1.0 - f0)); + return mix(f0_color, vec3(1.0), fac); +} + /* Fresnel */ vec3 F_schlick(vec3 f0, float cos_theta) { diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl index 22194c22f39..c2e45ebb879 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -54,6 +54,13 @@ uniform int hairThicknessRes = 1; #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 @@ -67,6 +74,14 @@ uniform int hairThicknessRes = 1; #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 diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index cc1150b6d77..9dcf308a414 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -128,6 +128,7 @@ typedef enum GPUMatFlag { GPU_MATFLAG_DIFFUSE = (1 << 0), GPU_MATFLAG_GLOSSY = (1 << 1), GPU_MATFLAG_REFRACT = (1 << 2), + GPU_MATFLAG_SSS = (1 << 3), } GPUMatFlag; typedef enum GPUBlendMode { diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 808d2f73659..c9564a21d15 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -1069,11 +1069,11 @@ void convert_metallic_to_specular_tinted( vec3 basecol, float metallic, float specular_fac, float specular_tint, out vec3 diffuse, out vec3 f0) { - vec3 dielectric = vec3(0.034) * specular_fac * 2.0; float lum = dot(basecol, vec3(0.3, 0.6, 0.1)); /* luminance approx. */ vec3 tint = lum > 0 ? basecol / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */ - f0 = mix(dielectric * mix(vec3(1.0), tint, specular_tint), basecol, metallic); - diffuse = mix(basecol, vec3(0.0), metallic); + vec3 tmp_col = mix(vec3(1.0), tint, specular_tint); + f0 = mix((0.08 * specular_fac) * tmp_col, basecol, metallic); + diffuse = basecol * (1.0 - metallic); } #ifndef VOLUMETRICS @@ -1126,52 +1126,142 @@ void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure r node_bsdf_diffuse(color, 0.0, N, result); } -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, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id, - float sss_id, vec3 sss_scale, out Closure result) +void node_bsdf_principled( + 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, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id, + float sss_id, vec3 sss_scale, out Closure result) { + ior = max(ior, 1e-5); metallic = saturate(metallic); transmission = saturate(transmission); + float dielectric = 1.0 - metallic; + transmission *= dielectric; + subsurface_color *= dielectric; vec3 diffuse, f0, out_diff, out_spec, out_trans, out_refr, ssr_spec; convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0); - transmission *= 1.0 - metallic; - subsurface *= 1.0 - metallic; - - clearcoat *= 0.25; - clearcoat *= 1.0 - transmission; + /* 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, dot(N, cameraVec)); + vec3 spec_col = F_color_blend(ior, fresnel, f0_glass) * fresnel; + f0 = mix(f0, spec_col, transmission); vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface); -#ifdef USE_SSS - diffuse = vec3(0.0); -#else - diffuse = mixed_ss_base_color; -#endif - - f0 = mix(f0, vec3(1.0), transmission); - float sss_scalef = dot(sss_scale, vec3(1.0 / 3.0)) * subsurface; eevee_closure_principled(N, mixed_ss_base_color, f0, int(ssr_id), roughness, - CN, clearcoat, clearcoat_roughness, 1.0, sss_scalef, ior, + CN, clearcoat * 0.25, clearcoat_roughness, 1.0, sss_scalef, ior, out_diff, out_trans, 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 */ + out_refr *= refr_color * (1.0 - fresnel) * transmission; - float fresnel = F_eta(ior, dot(N, cameraVec)); - vec3 refr_spec_color = base_color.rgb * fresnel; - /* This bit maybe innacurate. */ - out_refr = out_refr * refr_color * (1.0 - fresnel) + out_spec * refr_spec_color; + vec3 vN = normalize(mat3(ViewMatrix) * N); + result = CLOSURE_DEFAULT; + result.radiance = out_spec + out_refr; +#ifndef USE_SSS + result.radiance += (out_diff + out_trans) * mixed_ss_base_color * (1.0 - transmission); +#endif + result.ssr_data = vec4(ssr_spec, roughness); + result.ssr_normal = normal_encode(vN, viewCameraVec); + result.ssr_id = int(ssr_id); +#ifdef USE_SSS + result.sss_data.a = sss_scalef; + result.sss_data.rgb = out_diff + out_trans; +# ifdef USE_SSS_ALBEDO + result.sss_albedo.rgb = mixed_ss_base_color; +# else + result.sss_data.rgb *= mixed_ss_base_color; +# endif + result.sss_data.rgb *= (1.0 - transmission); +#endif +} + +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, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id, + float sss_id, vec3 sss_scale, out Closure result) +{ + metallic = saturate(metallic); + float dielectric = 1.0 - metallic; + + vec3 diffuse, f0, out_diff, out_spec, ssr_spec; + convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0); - ssr_spec = mix(ssr_spec, refr_spec_color, transmission); + eevee_closure_default(N, diffuse, f0, int(ssr_id), roughness, 1.0, out_diff, out_spec, ssr_spec); vec3 vN = normalize(mat3(ViewMatrix) * N); result = CLOSURE_DEFAULT; result.radiance = out_spec + out_diff * diffuse; - result.radiance = mix(result.radiance, out_refr, transmission); + result.ssr_data = vec4(ssr_spec, roughness); + result.ssr_normal = normal_encode(vN, viewCameraVec); + result.ssr_id = int(ssr_id); +} + +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, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id, + float sss_id, vec3 sss_scale, out Closure result) +{ + vec3 out_spec, ssr_spec; + + eevee_closure_glossy(N, base_color.rgb, int(ssr_id), roughness, 1.0, out_spec, ssr_spec); + + vec3 vN = normalize(mat3(ViewMatrix) * N); + result = CLOSURE_DEFAULT; + result.radiance = out_spec; + result.ssr_data = vec4(ssr_spec, roughness); + result.ssr_normal = normal_encode(vN, viewCameraVec); + result.ssr_id = int(ssr_id); +} + +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, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id, + float sss_id, vec3 sss_scale, out Closure result) +{ + vec3 out_spec, ssr_spec; + + eevee_closure_clearcoat(N, base_color.rgb, int(ssr_id), roughness, CN, clearcoat * 0.25, clearcoat_roughness, + 1.0, out_spec, ssr_spec); + + vec3 vN = normalize(mat3(ViewMatrix) * N); + result = CLOSURE_DEFAULT; + result.radiance = out_spec; + result.ssr_data = vec4(ssr_spec, roughness); + result.ssr_normal = normal_encode(vN, viewCameraVec); + result.ssr_id = int(ssr_id); +} + +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, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id, + float sss_id, vec3 sss_scale, out Closure result) +{ + metallic = saturate(metallic); + + vec3 diffuse, f0, out_diff, out_spec, out_trans, ssr_spec; + convert_metallic_to_specular_tinted(base_color.rgb, 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 = dot(sss_scale, vec3(1.0 / 3.0)) * subsurface; + + eevee_closure_skin(N, mixed_ss_base_color, f0, int(ssr_id), roughness, 1.0, sss_scalef, + out_diff, out_trans, out_spec, ssr_spec); + + vec3 vN = normalize(mat3(ViewMatrix) * N); + result = CLOSURE_DEFAULT; + result.radiance = out_spec; result.ssr_data = vec4(ssr_spec, roughness); result.ssr_normal = normal_encode(vN, viewCameraVec); result.ssr_id = int(ssr_id); @@ -1183,10 +1273,41 @@ void node_bsdf_principled_clearcoat(vec4 base_color, float subsurface, vec3 subs # else result.sss_data.rgb *= mixed_ss_base_color; # endif - result.sss_data.rgb *= (1.0 - transmission); +#else + result.radiance += (out_diff + out_trans) * mixed_ss_base_color; #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, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id, + float sss_id, vec3 sss_scale, out Closure result) +{ + ior = max(ior, 1e-5); + + 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), int(ssr_id), roughness, 1.0, ior, 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 */ + out_refr *= refr_color; + + float fresnel = F_eta(ior, dot(N, cameraVec)); + vec3 spec_col = F_color_blend(ior, fresnel, f0); + out_spec *= spec_col; + ssr_spec *= spec_col * fresnel; + + vec3 vN = normalize(mat3(ViewMatrix) * N); + result = CLOSURE_DEFAULT; + result.radiance = mix(out_refr, out_spec, fresnel); + result.ssr_data = vec4(ssr_spec, roughness); + result.ssr_normal = normal_encode(vN, viewCameraVec); + result.ssr_id = int(ssr_id); +} + void node_bsdf_translucent(vec4 color, vec3 N, out Closure result) { node_bsdf_diffuse(color, 0.0, -N, result); @@ -1220,13 +1341,13 @@ void node_subsurface_scattering( result.sss_data.a = scale; eevee_closure_subsurface(N, color.rgb, 1.0, scale, out_diff, out_trans); result.sss_data.rgb = out_diff + out_trans; -#ifdef USE_SSS_ALBEDO +# ifdef USE_SSS_ALBEDO /* Not perfect for texture_blur not exaclty equal to 0.0 or 1.0. */ result.sss_albedo.rgb = mix(color.rgb, vec3(1.0), texture_blur); result.sss_data.rgb *= mix(vec3(1.0), color.rgb, texture_blur); -#else +# else result.sss_data.rgb *= color.rgb; -#endif +# endif #else node_bsdf_diffuse(color, 0.0, N, result); #endif diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c index 831ac1c98da..370dcdcc2ea 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c @@ -64,22 +64,12 @@ static void node_shader_init_principled(bNodeTree *UNUSED(ntree), bNode *node) node->custom2 = SHD_SUBSURFACE_BURLEY; } +#define socket_not_zero(sock) (in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) > 1e-5f)) +#define socket_not_one(sock) (in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) < 1.0f - 1e-5f)) + static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { GPUNodeLink *sss_scale; -#if 0 /* Old 2.7 glsl viewport */ - // normal - if (!in[17].link) - in[17].link = GPU_builtin(GPU_VIEW_NORMAL); - else - GPU_link(mat, "direction_transform_m4v3", in[17].link, GPU_builtin(GPU_VIEW_MATRIX), &in[17].link); - - // clearcoat normal - if (!in[18].link) - in[18].link = GPU_builtin(GPU_VIEW_NORMAL); - else - GPU_link(mat, "direction_transform_m4v3", in[18].link, GPU_builtin(GPU_VIEW_MATRIX), &in[18].link); -#endif /* Normals */ if (!in[17].link) { @@ -117,9 +107,48 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *node, bNodeE GPU_link(mat, "set_rgb", GPU_uniform((float *)one), &sss_scale); } - GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT); + bool use_diffuse = socket_not_one(4) && socket_not_one(15); + bool use_subsurf = socket_not_zero(1) && use_diffuse; + bool use_refract = socket_not_one(4) && socket_not_zero(15); + bool use_clear = socket_not_zero(12); + + /* Due to the manual effort done per config, we only optimize the most common permutations. */ + char *node_name; + uint flag = 0; + if (!use_subsurf && use_diffuse && !use_refract && !use_clear) { + static char name[] = "node_bsdf_principled_dielectric"; + node_name = name; + flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY; + } + else if (!use_subsurf && !use_diffuse && !use_refract && !use_clear) { + static char name[] = "node_bsdf_principled_metallic"; + node_name = name; + flag = GPU_MATFLAG_GLOSSY; + } + else if (!use_subsurf && !use_diffuse && !use_refract && use_clear) { + static char name[] = "node_bsdf_principled_clearcoat"; + node_name = name; + flag = GPU_MATFLAG_GLOSSY; + } + else if (use_subsurf && use_diffuse && !use_refract && !use_clear) { + static char name[] = "node_bsdf_principled_subsurface"; + node_name = name; + flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS | GPU_MATFLAG_GLOSSY; + } + else if (!use_subsurf && !use_diffuse && use_refract && !use_clear && !socket_not_zero(4)) { + static char name[] = "node_bsdf_principled_glass"; + node_name = name; + flag = GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT; + } + else { + static char name[] = "node_bsdf_principled"; + node_name = name; + flag = GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY | GPU_MATFLAG_SSS | GPU_MATFLAG_REFRACT; + } + + GPU_material_flag_set(mat, flag); - return GPU_stack_link(mat, node, "node_bsdf_principled_clearcoat", in, out, GPU_builtin(GPU_VIEW_POSITION), + return GPU_stack_link(mat, node, node_name, in, out, GPU_builtin(GPU_VIEW_POSITION), GPU_uniform(&node->ssr_id), GPU_uniform(&node->sss_id), sss_scale); } diff --git a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.c b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.c index e05b0be1e62..6583dd0cec3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.c +++ b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.c @@ -67,6 +67,8 @@ static int node_shader_gpu_eevee_specular(GPUMaterial *mat, bNode *node, bNodeEx GPU_link(mat, "set_value", GPU_uniform(&one), &in[9].link); } + GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY); + return GPU_stack_link(mat, node, "node_eevee_specular", in, out, GPU_uniform(&node->ssr_id)); } |