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 106 additions and 8 deletions

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

@ -2461,6 +2461,7 @@ NODE_DEFINE(MetallicBsdfNode)
static NodeEnum fresnel_type_enum;
fresnel_type_enum.insert("f82", CLOSURE_BSDF_F82_CONDUCTOR);
fresnel_type_enum.insert("physical_conductor", CLOSURE_BSDF_PHYSICAL_CONDUCTOR);
fresnel_type_enum.insert("artist_conductor", CLOSURE_BSDF_ARTISTIC_CONDUCTOR);
SOCKET_ENUM(fresnel_type, "fresnel_type", fresnel_type_enum, CLOSURE_BSDF_F82_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

@ -2115,6 +2115,7 @@ enum {
enum {
SHD_PHYSICAL_CONDUCTOR = 0,
SHD_CONDUCTOR_F82 = 1,
SHD_ARTISTIC_CONDUCTOR = 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,