Shader: Add Conductor BSDF Node #114958

Open
Alaska wants to merge 14 commits from Alaska/blender:metallic-bsdf into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
23 changed files with 669 additions and 1 deletions

View File

@ -548,6 +548,35 @@ static ShaderNode *add_node(Scene *scene,
node = subsurface;
}
else if (b_node.is_a(&RNA_ShaderNodeBsdfConductor)) {
BL::ShaderNodeBsdfConductor b_conductor_node(b_node);
ConductorBsdfNode *conductor = graph->create_node<ConductorBsdfNode>();
switch (b_conductor_node.distribution()) {
case BL::ShaderNodeBsdfConductor::distribution_BECKMANN:
conductor->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
break;
case BL::ShaderNodeBsdfConductor::distribution_GGX:
conductor->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_ID);
break;
case BL::ShaderNodeBsdfConductor::distribution_MULTI_GGX:
conductor->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
break;
}
switch (b_conductor_node.fresnel_type()) {
case BL::ShaderNodeBsdfConductor::fresnel_type_ARTISTIC_CONDUCTOR:
conductor->set_fresnel_type(CLOSURE_BSDF_ARTISTIC_CONDUCTOR);
break;
case BL::ShaderNodeBsdfConductor::fresnel_type_CONDUCTOR:
conductor->set_fresnel_type(CLOSURE_BSDF_CONDUCTOR);
break;
case BL::ShaderNodeBsdfConductor::fresnel_type_F82:
conductor->set_fresnel_type(CLOSURE_BSDF_CONDUCTOR_F82);
break;
}
node = conductor;
}
else if (b_node.is_a(&RNA_ShaderNodeBsdfAnisotropic)) {
BL::ShaderNodeBsdfAnisotropic b_glossy_node(b_node);
GlossyBsdfNode *glossy = graph->create_node<GlossyBsdfNode>();

View File

@ -74,6 +74,43 @@ ccl_device Spectrum fresnel_conductor(float cosi, const Spectrum eta, const Spec
return (Rparl2 + Rperp2) * 0.5f;
}
ccl_device float3 conductor_ior_from_color(float3 r, const float3 edge_tint)
{
r = clamp(r, zero_float3(), make_float3(0.99));
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.99));
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)
{
/* Equations from "Artist Friendly Metallic Fresnel", Ole Gulbrandsen, 2014
* https://jcgt.org/published/0003/04/03/paper.pdf */
*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

@ -20,6 +20,7 @@ set(SRC_OSL
node_combine_rgb.osl
node_combine_hsv.osl
node_combine_xyz.osl
node_conductor_bsdf.osl
node_convert_from_color.osl
node_convert_from_float.osl
node_convert_from_int.osl

View File

@ -0,0 +1,54 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
#include "node_fresnel.h"
#include "stdcycles.h"
shader node_conductor_bsdf(color BaseColor = 1.0,
color EdgeTint = 1.0,
vector IOR = vector(0.183, 0.421, 1.373),
vector Extinction = vector(3.424, 2.346, 1.770),
string distribution = "multi_ggx",
string fresnel_type = "conductor",
float Roughness = 0.5,
float Anisotropy = 0.0,
float Rotation = 0.0,
normal Normal = N,
normal Tangent = 0.0,
output closure color BSDF = 0)
{
float r2 = clamp(Roughness, 0.0, 1.0);
r2 *= r2;
float alpha_x = r2, alpha_y = r2;
/* Handle anisotropy. */
vector T = Tangent;
if (Anisotropy > 0.0) {
float aspect = sqrt(1.0 - clamp(Anisotropy, 0.0, 1.0) * 0.9);
alpha_x /= aspect;
alpha_y *= aspect;
if (Rotation != 0.0)
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") {
BSDF = microfacet_f82_tint(distribution, Normal, T, alpha_x, alpha_y, F0, F82);
}
else {
vector n, k;
if (fresnel_type == "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

@ -37,6 +37,36 @@ color fresnel_conductor(float cosi, color eta, color k)
return (Rparl2 + Rperp2) * 0.5;
}
vector conductor_ior_from_color(color reflectivity, color edge_tint)
{
/* "Artist Friendly Metallic Fresnel", Ole Gulbrandsen, 2014
* https://jcgt.org/published/0003/04/03/paper.pdf */
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)
{
/* "Artist Friendly Metallic Fresnel", Ole Gulbrandsen, 2014
* https://jcgt.org/published/0003/04/03/paper.pdf */
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

@ -454,6 +454,85 @@ ccl_device
bsdf_transparent_setup(sd, weight, path_flag);
break;
}
case CLOSURE_BSDF_CONDUCTOR:
case CLOSURE_BSDF_CONDUCTOR_F82:
case CLOSURE_BSDF_ARTISTIC_CONDUCTOR: {
#ifdef __CAUSTICS_TRICKS__
if (!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE))
break;
#endif
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(make_float3(mix_weight)));
if (!(bsdf == NULL)) {
uint base_ior_offest, edge_tint_k_offset, rotation_offset, tangent_offset;
svm_unpack_node_uchar4(
node.z, &base_ior_offest, &edge_tint_k_offset, &rotation_offset, &tangent_offset);
float3 valid_reflection_N = maybe_ensure_valid_specular_reflection(sd, N);
float3 T = stack_load_float3(stack, tangent_offset);
const float anisotropy = saturatef(param2);
const float roughness = saturatef(param1);
float alpha_x = sqr(roughness), alpha_y = sqr(roughness);
if (anisotropy > 0.0f) {
float aspect = sqrtf(1.0f - anisotropy * 0.9f);
alpha_x /= aspect;
alpha_y *= aspect;
float anisotropic_rotation = stack_load_float(stack, rotation_offset);
if (anisotropic_rotation != 0.0f)
T = rotate_around_axis(T, N, anisotropic_rotation * M_2PI_F);
}
bsdf->N = valid_reflection_N;
bsdf->ior = 1.0f;
bsdf->T = T;
bsdf->alpha_x = alpha_x;
bsdf->alpha_y = alpha_y;
ClosureType distribution = (ClosureType)node.w;
/* setup bsdf */
if (distribution == CLOSURE_BSDF_MICROFACET_BECKMANN_ID) {
sd->flag |= bsdf_microfacet_beckmann_setup(bsdf);
}
else {
sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
}
const bool is_multiggx = (distribution == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
if (type == CLOSURE_BSDF_CONDUCTOR || type == CLOSURE_BSDF_ARTISTIC_CONDUCTOR) {
ccl_private FresnelConductor *fresnel = (ccl_private FresnelConductor *)
closure_alloc_extra(sd, sizeof(FresnelConductor));
float3 n, k;
if (type == CLOSURE_BSDF_CONDUCTOR) {
n = max(stack_load_float3(stack, base_ior_offest), 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_offest));
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);
bsdf_microfacet_setup_fresnel_conductor(kg, bsdf, sd, fresnel, is_multiggx);
}
else {
ccl_private FresnelF82Tint *fresnel = (ccl_private FresnelF82Tint *)closure_alloc_extra(
sd, sizeof(FresnelF82Tint));
const float3 color = saturate(stack_load_float3(stack, base_ior_offest));
const float3 tint = saturate(stack_load_float3(stack, edge_tint_k_offset));
fresnel->f0 = rgb_to_spectrum(color);
const Spectrum f82 = rgb_to_spectrum(tint);
bsdf_microfacet_setup_fresnel_f82_tint(kg, bsdf, sd, fresnel, f82, is_multiggx);
}
}
break;
}
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:

View File

@ -426,6 +426,9 @@ typedef enum ClosureType {
CLOSURE_BSDF_TRANSLUCENT_ID,
/* Glossy */
CLOSURE_BSDF_CONDUCTOR, /* virtual closure */
CLOSURE_BSDF_ARTISTIC_CONDUCTOR, /* virtual closure */
CLOSURE_BSDF_CONDUCTOR_F82, /* virtual closure */
CLOSURE_BSDF_MICROFACET_GGX_ID,
CLOSURE_BSDF_MICROFACET_BECKMANN_ID,
CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID, /* virtual closure */

View File

@ -1197,7 +1197,10 @@ int ShaderGraph::get_num_closures()
* for the volume steps. */
num_closures += MAX_VOLUME_STACK_SIZE;
}
else if (closure_type == CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID ||
else if (closure_type == CLOSURE_BSDF_CONDUCTOR ||
closure_type == CLOSURE_BSDF_ARTISTIC_CONDUCTOR ||
closure_type == CLOSURE_BSDF_CONDUCTOR_F82 ||
closure_type == CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID ||
closure_type == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID ||
closure_type == CLOSURE_BSDF_HAIR_CHIANG_ID ||
closure_type == CLOSURE_BSDF_HAIR_HUANG_ID)

View File

@ -2327,6 +2327,122 @@ void BsdfNode::compile(OSLCompiler & /*compiler*/)
assert(0);
}
/* Conductor BSDF Closure */
NODE_DEFINE(ConductorBsdfNode)
{
NodeType *type = NodeType::add("Conductor_bsdf", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Base Color", make_float3(1.0f, 1.0f, 1.0f));
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
static NodeEnum distribution_enum;
distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
distribution_enum.insert("ggx", CLOSURE_BSDF_MICROFACET_GGX_ID);
distribution_enum.insert("multi_ggx", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
SOCKET_ENUM(
distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
static NodeEnum fresnel_type_enum;
fresnel_type_enum.insert("f82", CLOSURE_BSDF_CONDUCTOR_F82);
fresnel_type_enum.insert("artist_conductor", CLOSURE_BSDF_ARTISTIC_CONDUCTOR);
fresnel_type_enum.insert("conductor", CLOSURE_BSDF_CONDUCTOR);
SOCKET_ENUM(fresnel_type, "fresnel_type", fresnel_type_enum, CLOSURE_BSDF_ARTISTIC_CONDUCTOR);
SOCKET_IN_COLOR(edge_tint, "Edge Tint", make_float3(1.0f, 1.0f, 1.0f));
SOCKET_IN_VECTOR(ior, "IOR", make_float3(0.183f, 0.421f, 1.373f));
SOCKET_IN_VECTOR(k, "Extinction", make_float3(3.424f, 2.346f, 1.770f));
SOCKET_IN_VECTOR(tangent, "Tangent", zero_float3(), SocketType::LINK_TANGENT);
SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f);
SOCKET_IN_FLOAT(rotation, "Rotation", 0.0f);
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
return type;
}
ConductorBsdfNode::ConductorBsdfNode() : BsdfNode(get_node_type())
{
closure = CLOSURE_BSDF_CONDUCTOR;
}
bool ConductorBsdfNode::is_isotropic()
{
ShaderInput *anisotropy_input = input("Anisotropy");
/* Keep in sync with the thresholds in OSL's node_conductor_bsdf and SVM's svm_node_closure_bsdf.
*/
return (!anisotropy_input->link && fabsf(anisotropy) <= 1e-4f);
}
void ConductorBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if (shader->has_surface_link()) {
ShaderInput *tangent_in = input("Tangent");
if (!tangent_in->link && !is_isotropic()) {
attributes->add(ATTR_STD_GENERATED);
}
}
ShaderNode::attributes(shader, attributes);
}
void ConductorBsdfNode::simplify_settings(Scene * /* scene */)
{
/* If the anisotropy is close enough to zero, fall back to the isotropic case. */
ShaderInput *tangent_input = input("Tangent");
if (tangent_input->link && is_isotropic()) {
tangent_input->disconnect();
}
}
void ConductorBsdfNode::compile(SVMCompiler &compiler)
{
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, one_float3());
ShaderInput *base_color_in = input("Base Color");
ShaderInput *edge_tint_in = input("Edge Tint");
ShaderInput *ior_in = input("IOR");
ShaderInput *k_in = input("Extinction");
int base_color_ior_offset = fresnel_type == CLOSURE_BSDF_CONDUCTOR ?
compiler.stack_assign(ior_in) :
compiler.stack_assign(base_color_in);
int edge_tint_k_offset = fresnel_type == CLOSURE_BSDF_CONDUCTOR ?
compiler.stack_assign(k_in) :
compiler.stack_assign(edge_tint_in);
ShaderInput *anisotropy_in = input("Anisotropy");
ShaderInput *rotation_in = input("Rotation");
ShaderInput *roughness_in = input("Roughness");
ShaderInput *tangent_in = input("Tangent");
int normal_offset = compiler.stack_assign_if_linked(input("Normal"));
compiler.add_node(NODE_CLOSURE_BSDF,
compiler.encode_uchar4(fresnel_type,
compiler.stack_assign(roughness_in),
compiler.stack_assign(anisotropy_in),
compiler.closure_mix_weight_offset()),
compiler.encode_uchar4(base_color_ior_offset,
edge_tint_k_offset,
compiler.stack_assign(rotation_in),
compiler.stack_assign(tangent_in)),
distribution);
compiler.add_node(normal_offset);
}
void ConductorBsdfNode::compile(OSLCompiler &compiler)
{
compiler.parameter(this, "distribution");
compiler.parameter(this, "fresnel_type");
compiler.add(this, "node_conductor_bsdf");
}
/* Glossy BSDF Closure */
NODE_DEFINE(GlossyBsdfNode)

View File

@ -574,6 +574,35 @@ class SheenBsdfNode : public BsdfNode {
}
};
class ConductorBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(ConductorBsdfNode)
void simplify_settings(Scene *scene);
ClosureType get_closure_type()
{
return closure;
}
NODE_SOCKET_API(float3, edge_tint)
NODE_SOCKET_API(float3, ior)
NODE_SOCKET_API(float3, k)
NODE_SOCKET_API(float3, tangent)
NODE_SOCKET_API(float, roughness)
NODE_SOCKET_API(float, anisotropy)
NODE_SOCKET_API(float, rotation)
NODE_SOCKET_API(ClosureType, distribution)
NODE_SOCKET_API(ClosureType, fresnel_type)
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency()
{
return true;
}
bool is_isotropic();
};
class GlossyBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(GlossyBsdfNode)

View File

@ -341,6 +341,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 make_float3(mix(a.x, b.x, t.x), mix(a.y, b.y, t.y), mix(a.z, b.z, t.z));
}
ccl_device_inline float3 rcp(const float3 a)
{
# ifdef __KERNEL_SSE__

View File

@ -137,6 +137,11 @@ class NODE_MT_category_shader_shader(Menu):
"ShaderNodeBackground",
poll=world_shader_nodes_poll(context),
)
node_add_menu.add_node_type(
layout,
"ShaderNodeBsdfConductor",
poll=object_shader_nodes_poll(context),
)
node_add_menu.add_node_type(
layout,
"ShaderNodeBsdfDiffuse",

View File

@ -974,6 +974,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define SH_NODE_COMBINE_COLOR 711
#define SH_NODE_SEPARATE_COLOR 712
#define SH_NODE_MIX 713
#define SH_NODE_BSDF_CONDUCTOR 714
/** \} */

View File

@ -506,6 +506,7 @@ set(GLSL_SRC
shaders/material/gpu_shader_material_combine_hsv.glsl
shaders/material/gpu_shader_material_combine_rgb.glsl
shaders/material/gpu_shader_material_combine_xyz.glsl
shaders/material/gpu_shader_material_conductor.glsl
shaders/material/gpu_shader_material_diffuse.glsl
shaders/material/gpu_shader_material_displacement.glsl
shaders/material/gpu_shader_material_eevee_specular.glsl

View File

@ -0,0 +1,63 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
vec4 fresnel_conductor(float cosi, const vec3 eta, const vec3 k)
{
const vec4 cosiv4 = vec4(cosi);
const vec4 etav4 = vec4(eta, 1.0);
const vec4 kv4 = vec4(k, 1.0);
const vec4 cosi2 = vec4(cosi * cosi);
const vec4 one = vec4(1.0);
const vec4 tmp_f = (etav4 * etav4) + (kv4 * kv4);
const vec4 tmp = tmp_f * cosi2;
const vec4 Rparl2 = (tmp - (2.0 * etav4 * cosiv4) + one) / (tmp + (2.0 * etav4 * cosiv4) + one);
const vec4 Rperp2 = (tmp_f - (2.0 * etav4 * cosiv4) + cosi2) /
(tmp_f + (2.0 * etav4 * cosiv4) + cosi2);
return (Rparl2 + Rperp2) * 0.5;
}
void node_bsdf_conductor(vec4 base_color,
vec4 edge_tint,
vec3 ior,
vec3 extinction,
float roughness,
float anisotropy,
float rotation,
vec3 N,
vec3 T,
float weight,
const float do_multiscatter,
const float use_complex_ior,
out Closure result)
{
if (use_complex_ior != 0.0) {
base_color = fresnel_conductor(1.0, ior, extinction);
edge_tint = fresnel_conductor(1.0 / 7.0, ior, extinction);
}
/* Clamp to match Cycles */
base_color = saturate(base_color);
edge_tint = saturate(edge_tint);
roughness = saturate(roughness);
/* Not used by EEVEE */
/* anisotropy = saturate(anisotropy); */
N = safe_normalize(N);
vec3 V = coordinate_incoming(g_data.P);
float NV = dot(N, V);
ClosureReflection reflection_data;
reflection_data.N = N;
reflection_data.roughness = roughness;
vec3 F0 = base_color.rgb;
vec3 F82 = edge_tint.rgb;
vec3 metallic_brdf;
brdf_f82_tint_lut(F0, F82, NV, roughness, do_multiscatter != 0.0, metallic_brdf);
reflection_data.color = metallic_brdf;
reflection_data.weight = weight;
result = closure_eval(reflection_data);
}

View File

@ -2032,6 +2032,13 @@ enum {
CMP_NODE_CHANNEL_MATTE_CS_YCC = 4,
};
/* Conductive fresnel types */
enum {
SHD_CONDUCTOR = 0,
SHD_ARTISTIC_CONDUCTOR = 1,
SHD_CONDUCTOR_F82 = 2,
};
/* glossy distributions */
enum {
SHD_GLOSSY_BECKMANN = 0,

View File

@ -4048,6 +4048,29 @@ static const EnumPropertyItem node_ycc_items[] = {
{0, nullptr, 0, nullptr, nullptr},
};
static const EnumPropertyItem node_conductor_distrobution_items[] = {
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
{SHD_GLOSSY_MULTI_GGX,
"MULTI_GGX",
0,
"Multiscatter GGX",
"GGX with additional correction to account for multiple scattering, preserve energy and "
"prevent unexpected darkening at high roughness"},
{0, nullptr, 0, nullptr, nullptr},
};
static const EnumPropertyItem node_conductor_fresnel_type_items[] = {
{SHD_CONDUCTOR, "CONDUCTOR", 0, "Conductor Fresnel", ""},
{SHD_ARTISTIC_CONDUCTOR,
"ARTISTIC_CONDUCTOR",
0,
"Conductor Fresnel - Artistic",
"Conductive Fresnel with artist friendly color inputs"},
{SHD_CONDUCTOR_F82, "F82", 0, "F82 Tint Fresnel", ""},
{0, nullptr, 0, nullptr, nullptr},
};
static const EnumPropertyItem node_glossy_items[] = {
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
@ -5473,6 +5496,23 @@ static void def_sh_tex_pointdensity(StructRNA *srna)
RNA_def_function_output(func, parm);
}
static void def_conductor(StructRNA *srna)
{
PropertyRNA *prop;
prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "custom1");
RNA_def_property_enum_items(prop, node_conductor_distrobution_items);
RNA_def_property_ui_text(prop, "Distribution", "Light scattering distribution on rough surface");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "fresnel_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "custom2");
RNA_def_property_enum_items(prop, node_conductor_fresnel_type_items);
RNA_def_property_ui_text(prop, "Fresnel Type", "PLACE HOLDER");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_glossy(StructRNA *srna)
{
PropertyRNA *prop;

View File

@ -61,6 +61,7 @@ DefNode(ShaderNode, SH_NODE_ATTRIBUTE, def_sh_attribute, "ATT
DefNode(ShaderNode, SH_NODE_AMBIENT_OCCLUSION, def_sh_ambient_occlusion,"AMBIENT_OCCLUSION", AmbientOcclusion, "Ambient Occlusion", "Compute how much the hemisphere above the shading point is occluded, for example to add weathering effects to corners.\nNote: For Cycles, this may slow down renders significantly")
DefNode(ShaderNode, SH_NODE_BACKGROUND, 0, "BACKGROUND", Background, "Background", "Add background light emission.\nNote: This node should only be used for the world surface output")
DefNode(ShaderNode, SH_NODE_HOLDOUT, 0, "HOLDOUT", Holdout, "Holdout", "Create a \"hole\" in the image with zero alpha transparency, which is useful for compositing.\nNote: the holdout shader can only create alpha when transparency is enabled in the film settings")
DefNode(ShaderNode, SH_NODE_BSDF_CONDUCTOR, def_conductor, "BSDF_CONDUCTOR", BsdfConductor, "Conductor BSDF", "Reflection with microfacet distribution, used for materials such as metal or mirrors")
DefNode(ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "Lambertian and Oren-Nayar diffuse reflection")
DefNode(ShaderNode, SH_NODE_BSDF_PRINCIPLED, def_principled, "BSDF_PRINCIPLED", BsdfPrincipled, "Principled BSDF", "Physically-based, easy-to-use shader for rendering surface materials, based on the Disney principled model also known as the \"PBR\" shader")
DefNode(ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfAnisotropic, "Glossy BSDF", "Reflection with microfacet distribution, used for materials such as metal or mirrors")

View File

@ -34,6 +34,7 @@ set(SRC
nodes/node_shader_bsdf_diffuse.cc
nodes/node_shader_bsdf_glass.cc
nodes/node_shader_bsdf_glossy.cc
nodes/node_shader_bsdf_conductor.cc
nodes/node_shader_bsdf_hair.cc
nodes/node_shader_bsdf_hair_principled.cc
nodes/node_shader_bsdf_principled.cc

View File

@ -19,6 +19,7 @@ void register_shader_nodes()
register_node_type_sh_bevel();
register_node_type_sh_blackbody();
register_node_type_sh_brightcontrast();
register_node_type_sh_bsdf_conductor();
register_node_type_sh_bsdf_diffuse();
register_node_type_sh_bsdf_glass();
register_node_type_sh_bsdf_glossy();

View File

@ -15,6 +15,7 @@ void register_node_type_sh_background();
void register_node_type_sh_bevel();
void register_node_type_sh_blackbody();
void register_node_type_sh_brightcontrast();
void register_node_type_sh_bsdf_conductor();
void register_node_type_sh_bsdf_diffuse();
void register_node_type_sh_bsdf_glass();
void register_node_type_sh_bsdf_glossy();

View File

@ -916,6 +916,7 @@ static void ntree_shader_weight_tree_invert(bNodeTree *ntree, bNode *output_node
break;
}
case SH_NODE_BACKGROUND:
case SH_NODE_BSDF_CONDUCTOR:
case SH_NODE_BSDF_DIFFUSE:
case SH_NODE_BSDF_GLASS:
case SH_NODE_BSDF_GLOSSY:
@ -973,6 +974,7 @@ static bool closure_node_filter(const bNode *node)
case SH_NODE_ADD_SHADER:
case SH_NODE_MIX_SHADER:
case SH_NODE_BACKGROUND:
case SH_NODE_BSDF_CONDUCTOR:
case SH_NODE_BSDF_DIFFUSE:
case SH_NODE_BSDF_GLASS:
case SH_NODE_BSDF_GLOSSY:

View File

@ -0,0 +1,159 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_shader_util.hh"
#include "UI_interface.hh"
#include "UI_resources.hh"
namespace blender::nodes::node_shader_bsdf_conductor_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>("Base Color").default_value({1.0f, 1.0f, 1.0f, 1.0f});
b.add_input<decl::Color>("Edge Tint").default_value({1.0f, 1.0f, 1.0f, 1.0f});
b.add_input<decl::Vector>("IOR")
.default_value({0.183f, 0.421f, 1.373f})
.min(0.0f)
.max(100.0f)
.description("PLACEHOLDER");
b.add_input<decl::Vector>("Extinction")
.default_value({3.424f, 2.346f, 1.770f})
.min(0.0f)
.max(100.0f)
.description("PLACE HOLDER");
b.add_input<decl::Float>("Roughness")
.default_value(0.5f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
b.add_input<decl::Float>("Anisotropy")
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
b.add_input<decl::Float>("Rotation")
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
b.add_input<decl::Vector>("Normal").hide_value();
b.add_input<decl::Vector>("Tangent").hide_value();
b.add_input<decl::Float>("Weight").unavailable();
b.add_output<decl::Shader>("BSDF");
}
static void node_shader_buts_conductor(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "distribution", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
uiItemR(layout, ptr, "fresnel_type", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
}
static void node_shader_init_conductor(bNodeTree * /*ntree*/, bNode *node)
{
node->custom1 = SHD_GLOSSY_MULTI_GGX;
node->custom2 = SHD_ARTISTIC_CONDUCTOR;
}
static int node_shader_gpu_bsdf_conductor(GPUMaterial *mat,
bNode *node,
bNodeExecData * /*execdata*/,
GPUNodeStack *in,
GPUNodeStack *out)
{
if (!in[7].link) {
GPU_link(mat, "world_normals_get", &in[7].link);
}
GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY);
float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
float use_complex_ior = (node->custom2 == SHD_CONDUCTOR) ? 1.0f : 0.0f;
return GPU_stack_link(mat,
node,
"node_bsdf_conductor",
in,
out,
GPU_constant(&use_multi_scatter),
GPU_constant(&use_complex_ior));
}
static void node_shader_update_conductor(bNodeTree *ntree, bNode *node)
{
const int fresnel_method = node->custom2;
bke::nodeSetSocketAvailability(
ntree, nodeFindSocket(node, SOCK_IN, "Base Color"), fresnel_method != SHD_CONDUCTOR);
bke::nodeSetSocketAvailability(
ntree, nodeFindSocket(node, SOCK_IN, "Edge Tint"), fresnel_method != SHD_CONDUCTOR);
bke::nodeSetSocketAvailability(
ntree, nodeFindSocket(node, SOCK_IN, "IOR"), fresnel_method == SHD_CONDUCTOR);
bke::nodeSetSocketAvailability(
ntree, nodeFindSocket(node, SOCK_IN, "Extinction"), fresnel_method == SHD_CONDUCTOR);
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
if (to_type_ != NodeItem::Type::BSDF) {
return empty();
}
NodeItem color = get_input_value("Base Color", NodeItem::Type::Color3);
NodeItem edge_tint = get_input_value("Edge Tint", NodeItem::Type::Color3);
NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Vector2);
NodeItem anisotropy = get_input_value("Anisotropy", NodeItem::Type::Color3);
NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3);
NodeItem tangent = get_input_link("Tangent", NodeItem::Type::Vector3);
/* TODO: Figure out how to switch between artisitic_ior and using
* the IOR and Extinction values directly.
* `node` is not defined here so we can't use `node->custom2` */
/* if (node->custom2 == SHD_CONDUCTOR) {
USE_IOR_AND_EXTINCTION;
}
else {
USE ARTISTIC_IOR;
}*/
NodeItem artistic_ior = create_node("artistic_ior",
NodeItem::Type::Multioutput,
{{"reflectivity", color}, {"edge_color", edge_tint}});
NodeItem ior_out = artistic_ior.add_output("ior", NodeItem::Type::Color3);
NodeItem extinction_out = artistic_ior.add_output("extinction", NodeItem::Type::Color3);
return create_node("conductor_bsdf",
NodeItem::Type::BSDF,
{{"normal", normal},
{"tangent", tangent},
{"ior", ior_out},
{"extinction", extinction_out},
{"roughness", roughness}});
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_bsdf_conductor_cc
/* node type definition */
void register_node_type_sh_bsdf_conductor()
{
namespace file_ns = blender::nodes::node_shader_bsdf_conductor_cc;
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BSDF_CONDUCTOR, "Conductor BSDF", NODE_CLASS_SHADER);
ntype.declare = file_ns::node_declare;
ntype.add_ui_poll = object_shader_nodes_poll;
ntype.draw_buttons = file_ns::node_shader_buts_conductor;
blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::LARGE);
ntype.initfunc = file_ns::node_shader_init_conductor;
ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_conductor;
ntype.updatefunc = file_ns::node_shader_update_conductor;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}