WIP: Shader: Add Artistic Conductor Fresnel type to Metallic BSDF #126871

Draft
Alaska wants to merge 3 commits from Alaska/blender:add-artisitc-conductor into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
11 changed files with 108 additions and 10 deletions
Showing only changes of commit a7f921a39d - Show all commits

View File

@ -565,6 +565,9 @@ static ShaderNode *add_node(Scene *scene,
}
switch (b_metallic_node.fresnel_type()) {
case BL::ShaderNodeBsdfMetallic::fresnel_type_ARTISTIC_CONDUCTOR:
metal->set_fresnel_type(CLOSURE_BSDF_ARTISTIC_CONDUCTOR);
break;
case BL::ShaderNodeBsdfMetallic::fresnel_type_PHYSICAL_CONDUCTOR:
metal->set_fresnel_type(CLOSURE_BSDF_PHYSICAL_CONDUCTOR);
break;

View File

@ -103,6 +103,42 @@ ccl_device Spectrum fresnel_conductor(float cosi, const Spectrum eta, const Spec
return (Rparl2 + Rperp2) * 0.5f;
}
/* Equations to map color to complex IOR, from "Artist Friendly Metallic Fresnel",
* Ole Gulbrandsen,2014 https://jcgt.org/published/0003/04/03/paper.pdf */
ccl_device float3 conductor_ior_from_color(float3 r, const float3 edge_tint)
{
r = clamp(r, zero_float3(), make_float3(0.99f));
const float3 r_sqrt = sqrt(r);
const float3 one = one_float3();
const float3 n_min = (one - r) / (one + r);
const float3 n_max = (one + r_sqrt) / (one - r_sqrt);
return mix(n_max, n_min, edge_tint);
}
ccl_device float3 conductor_extinction_from_color(float3 r, const float3 eta)
{
r = clamp(r, zero_float3(), make_float3(0.99f));
const float3 one = one_float3();
const float3 np1 = eta + one;
const float3 nm1 = eta - one;
float3 k2 = ((r * np1 * np1) - (nm1 * nm1)) / (one - r);
k2 = max(k2, zero_float3());
return sqrt(k2);
}
ccl_device void complex_ior_from_base_edge(const float3 reflectivity,
const float3 edge_tint,
ccl_private float3 *eta,
ccl_private float3 *k)
{
*eta = conductor_ior_from_color(reflectivity, edge_tint);
*k = conductor_extinction_from_color(reflectivity, *eta);
}
ccl_device float ior_from_F0(float f0)
{
const float sqrt_f0 = sqrtf(clamp(f0, 0.0f, 0.99f));

View File

@ -37,6 +37,32 @@ color fresnel_conductor(float cosi, color eta, color k)
return (Rparl2 + Rperp2) * 0.5;
}
/* Equations to map color to complex IOR, from "Artist Friendly Metallic Fresnel",
* Ole Gulbrandsen,2014 https://jcgt.org/published/0003/04/03/paper.pdf */
vector conductor_ior_from_color(color reflectivity, color edge_tint)
{
vector r = clamp(reflectivity, 0.0, 0.99);
vector r_sqrt = sqrt(r);
vector one = 1.0;
vector n_min = (one - r) / (one + r);
vector n_max = (one + r_sqrt) / (one - r_sqrt);
return mix(n_max, n_min, edge_tint);
}
vector conductor_extinction_from_color(color reflectivity, vector n)
{
vector r = clamp(reflectivity, 0.0, 0.99);
vector np1 = n + 1.0;
vector nm1 = n - 1.0;
vector k2 = ((r * np1 * np1) - (nm1 * nm1)) / (1.0 - r);
k2 = max(k2, 0.0);
return sqrt(k2);
}
float F0_from_ior(float eta)
{
float f0 = (eta - 1.0) / (eta + 1.0);

View File

@ -32,13 +32,23 @@ shader node_metallic_bsdf(color BaseColor = color(0.617, 0.577, 0.540),
T = rotate(T, Rotation * M_2PI, point(0.0, 0.0, 0.0), Normal);
}
color F0 = clamp(BaseColor, color(0.0), color(1.0));
color F82 = clamp(EdgeTint, color(0.0), color(1.0));
if (fresnel_type == "f82") {
color F0 = clamp(BaseColor, color(0.0), color(1.0));
color F82 = clamp(EdgeTint, color(0.0), color(1.0));
BSDF = microfacet_f82_tint(distribution, Normal, T, alpha_x, alpha_y, F0, F82);
}
else {
BSDF = conductor_bsdf(
Normal, T, alpha_x, alpha_y, max(IOR, 0.0), max(Extinction, 0.0), distribution);
vector n, k;
if (fresnel_type == "physical_conductor") {
n = max(IOR, 0.0);
k = max(Extinction, 0.0);
}
else {
n = conductor_ior_from_color(F0, F82);
k = conductor_extinction_from_color(F0, n);
}
BSDF = conductor_bsdf(Normal, T, alpha_x, alpha_y, n, k, distribution);
}
}

View File

@ -480,7 +480,8 @@ ccl_device
break;
}
case CLOSURE_BSDF_PHYSICAL_CONDUCTOR:
case CLOSURE_BSDF_F82_CONDUCTOR: {
case CLOSURE_BSDF_F82_CONDUCTOR:
case CLOSURE_BSDF_ARTISTIC_CONDUCTOR: {
#ifdef __CAUSTICS_TRICKS__
if (!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE))
break;
@ -525,12 +526,20 @@ ccl_device
const bool is_multiggx = (distribution == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
if (type == CLOSURE_BSDF_PHYSICAL_CONDUCTOR) {
if (type == CLOSURE_BSDF_PHYSICAL_CONDUCTOR || type == CLOSURE_BSDF_ARTISTIC_CONDUCTOR) {
ccl_private FresnelConductor *fresnel = (ccl_private FresnelConductor *)
closure_alloc_extra(sd, sizeof(FresnelConductor));
const float3 n = max(stack_load_float3(stack, base_ior_offset), zero_float3());
const float3 k = max(stack_load_float3(stack, edge_tint_k_offset), zero_float3());
float3 n, k;
if (type == CLOSURE_BSDF_PHYSICAL_CONDUCTOR) {
n = max(stack_load_float3(stack, base_ior_offset), zero_float3());
k = max(stack_load_float3(stack, edge_tint_k_offset), zero_float3());
}
else {
const float3 color = saturate(stack_load_float3(stack, base_ior_offset));
const float3 tint = saturate(stack_load_float3(stack, edge_tint_k_offset));
complex_ior_from_base_edge(color, tint, &n, &k);
}
fresnel->n = rgb_to_spectrum(n);
fresnel->k = rgb_to_spectrum(k);

View File

@ -432,6 +432,7 @@ typedef enum ClosureType {
/* Glossy */
CLOSURE_BSDF_PHYSICAL_CONDUCTOR, /* virtual closure */
CLOSURE_BSDF_ARTISTIC_CONDUCTOR, /* virtual closure */
CLOSURE_BSDF_F82_CONDUCTOR, /* virtual closure */
CLOSURE_BSDF_MICROFACET_GGX_ID,
CLOSURE_BSDF_MICROFACET_BECKMANN_ID,

View File

@ -1199,6 +1199,7 @@ int ShaderGraph::get_num_closures()
num_closures += MAX_VOLUME_STACK_SIZE;
}
else if (closure_type == CLOSURE_BSDF_PHYSICAL_CONDUCTOR ||
closure_type == CLOSURE_BSDF_ARTISTIC_CONDUCTOR ||
closure_type == CLOSURE_BSDF_F82_CONDUCTOR ||
closure_type == CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID ||
closure_type == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID ||

View File

@ -2460,8 +2460,9 @@ NODE_DEFINE(MetallicBsdfNode)
static NodeEnum fresnel_type_enum;
fresnel_type_enum.insert("f82", CLOSURE_BSDF_F82_CONDUCTOR);
fresnel_type_enum.insert("artist_conductor", CLOSURE_BSDF_ARTISTIC_CONDUCTOR);
fresnel_type_enum.insert("physical_conductor", CLOSURE_BSDF_PHYSICAL_CONDUCTOR);
SOCKET_ENUM(fresnel_type, "fresnel_type", fresnel_type_enum, CLOSURE_BSDF_F82_CONDUCTOR);
SOCKET_ENUM(fresnel_type, "fresnel_type", fresnel_type_enum, CLOSURE_BSDF_ARTISTIC_CONDUCTOR);
SOCKET_IN_COLOR(edge_tint, "Edge Tint", make_float3(0.695f, 0.726f, 0.770f));

View File

@ -347,6 +347,11 @@ ccl_device_inline float3 mix(const float3 a, const float3 b, float t)
return a + t * (b - a);
}
ccl_device_inline float3 mix(const float3 a, const float3 b, float3 t)
{
return a + t * (b - a);
}
ccl_device_inline float3 rcp(const float3 a)
{
# ifdef __KERNEL_SSE__

View File

@ -2114,7 +2114,8 @@ enum {
/* Conductive fresnel types */
enum {
SHD_PHYSICAL_CONDUCTOR = 0,
SHD_CONDUCTOR_F82 = 1,
SHD_ARTISTIC_CONDUCTOR = 1,
SHD_CONDUCTOR_F82 = 2,
};
/* glossy distributions */

View File

@ -4134,6 +4134,11 @@ static const EnumPropertyItem node_metallic_fresnel_type_items[] = {
0,
"Physical Conductor",
"Fresnel conductor based on the complex refractive index per color channel"},
{SHD_ARTISTIC_CONDUCTOR,
"ARTISTIC_CONDUCTOR",
0,
"Artistic Conductor",
"Fresnel conductor with artist friendly color inputs"},
{SHD_CONDUCTOR_F82,
"F82",
0,