Shader: Add Metallic BSDF Node

Add Metallic BSDF Node to the shader editor.

This node can primarily be used to create more realistic looking
metallic materials than the existing Glossy BSDF node.

This commit does not add any new closures to Cycles, it simply exposes
existing closures that were previous hard to access on their own.

- Exposes the F82 fresnel type that is currently used by the
metallic component of the Principled BSDF. Results should match
between the Metallic BSDF and Principled BSDF when using the same
settings.
- Exposes the Physical Conductor fresnel type that was previously
limited to custom OSL scripts. The Conductor fresnel type accepts
IOR and Extinction coefficients to define the appearance of the
material based off real life measurements.

EEVEE only supports the F82 fresnel type with internal code to convert
the the physical conductor inputs in to a colour format for F82,
which can lead to noticeable rendering differences with
some configurations.

Pull Request: https://projects.blender.org/blender/blender/pulls/114958
This commit is contained in:
Alaska
2024-08-27 17:20:46 +02:00
committed by Sergey Sharybin
parent e3311e48c0
commit 6ccb33e9fe
20 changed files with 585 additions and 1 deletions

View File

@@ -548,6 +548,32 @@ static ShaderNode *add_node(Scene *scene,
node = subsurface;
}
else if (b_node.is_a(&RNA_ShaderNodeBsdfMetallic)) {
BL::ShaderNodeBsdfMetallic b_metallic_node(b_node);
MetallicBsdfNode *metal = graph->create_node<MetallicBsdfNode>();
switch (b_metallic_node.distribution()) {
case BL::ShaderNodeBsdfMetallic::distribution_BECKMANN:
metal->set_distribution(CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
break;
case BL::ShaderNodeBsdfMetallic::distribution_GGX:
metal->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_ID);
break;
case BL::ShaderNodeBsdfMetallic::distribution_MULTI_GGX:
metal->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
break;
}
switch (b_metallic_node.fresnel_type()) {
case BL::ShaderNodeBsdfMetallic::fresnel_type_PHYSICAL_CONDUCTOR:
metal->set_fresnel_type(CLOSURE_BSDF_PHYSICAL_CONDUCTOR);
break;
case BL::ShaderNodeBsdfMetallic::fresnel_type_F82:
metal->set_fresnel_type(CLOSURE_BSDF_F82_CONDUCTOR);
break;
}
node = metal;
}
else if (b_node.is_a(&RNA_ShaderNodeBsdfAnisotropic)) {
BL::ShaderNodeBsdfAnisotropic b_glossy_node(b_node);
GlossyBsdfNode *glossy = graph->create_node<GlossyBsdfNode>();

View File

@@ -56,6 +56,7 @@ set(SRC_OSL
node_map_range.osl
node_mapping.osl
node_math.osl
node_metallic_bsdf.osl
node_mix.osl
node_mix_closure.osl
node_mix_color.osl

View File

@@ -0,0 +1,44 @@
/* SPDX-FileCopyrightText: 2024 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
#include "node_fresnel.h"
#include "stdcycles.h"
shader node_metallic_bsdf(color BaseColor = color(0.617, 0.577, 0.540),
color EdgeTint = color(0.695, 0.726, 0.770),
vector IOR = vector(2.757, 2.513, 2.231),
vector Extinction = vector(3.867, 3.404, 3.009),
string distribution = "multi_ggx",
string fresnel_type = "f82",
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);
}
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);
}
}

View File

@@ -479,6 +479,77 @@ ccl_device
bsdf_transparent_setup(sd, weight, path_flag);
break;
}
case CLOSURE_BSDF_PHYSICAL_CONDUCTOR:
case CLOSURE_BSDF_F82_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_offset, edge_tint_k_offset, rotation_offset, tangent_offset;
svm_unpack_node_uchar4(
node.z, &base_ior_offset, &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_PHYSICAL_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());
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_offset));
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_RAY_PORTAL_ID: {
Spectrum weight = closure_weight * mix_weight;
float3 position = stack_load_float3(stack, data_node.y);

View File

@@ -431,6 +431,8 @@ typedef enum ClosureType {
CLOSURE_BSDF_TRANSLUCENT_ID,
/* Glossy */
CLOSURE_BSDF_PHYSICAL_CONDUCTOR, /* virtual closure */
CLOSURE_BSDF_F82_CONDUCTOR, /* virtual closure */
CLOSURE_BSDF_MICROFACET_GGX_ID,
CLOSURE_BSDF_MICROFACET_BECKMANN_ID,
CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID, /* virtual closure */

View File

@@ -1198,7 +1198,9 @@ 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_PHYSICAL_CONDUCTOR ||
closure_type == CLOSURE_BSDF_F82_CONDUCTOR ||
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

@@ -2441,6 +2441,121 @@ void BsdfNode::compile(OSLCompiler & /*compiler*/)
assert(0);
}
/* Metallic BSDF Closure */
NODE_DEFINE(MetallicBsdfNode)
{
NodeType *type = NodeType::add("metallic_bsdf", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Base Color", make_float3(0.617f, 0.577f, 0.540f));
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_F82_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_IN_COLOR(edge_tint, "Edge Tint", make_float3(0.695f, 0.726f, 0.770f));
SOCKET_IN_VECTOR(ior, "IOR", make_float3(2.757f, 2.513f, 2.231f));
SOCKET_IN_VECTOR(k, "Extinction", make_float3(3.867f, 3.404f, 3.009f));
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;
}
MetallicBsdfNode::MetallicBsdfNode() : BsdfNode(get_node_type())
{
closure = CLOSURE_BSDF_PHYSICAL_CONDUCTOR;
}
bool MetallicBsdfNode::is_isotropic()
{
ShaderInput *anisotropy_input = input("Anisotropy");
/* Keep in sync with the thresholds in OSL's node_conductor_bsdf and SVM's
* svm_node_metallic_bsdf. */
return (!anisotropy_input->link && fabsf(anisotropy) <= 1e-4f);
}
void MetallicBsdfNode::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 MetallicBsdfNode::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 MetallicBsdfNode::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_PHYSICAL_CONDUCTOR ?
compiler.stack_assign(ior_in) :
compiler.stack_assign(base_color_in);
int edge_tint_k_offset = fresnel_type == CLOSURE_BSDF_PHYSICAL_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 MetallicBsdfNode::compile(OSLCompiler &compiler)
{
compiler.parameter(this, "distribution");
compiler.parameter(this, "fresnel_type");
compiler.add(this, "node_metallic_bsdf");
}
/* Glossy BSDF Closure */
NODE_DEFINE(GlossyBsdfNode)

View File

@@ -604,6 +604,35 @@ class SheenBsdfNode : public BsdfNode {
}
};
class MetallicBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(MetallicBsdfNode)
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

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

View File

@@ -997,6 +997,7 @@ void node_tree_remove_layer_n(bNodeTree *ntree, Scene *scene, int layer_index);
#define SH_NODE_MIX 713
#define SH_NODE_BSDF_RAY_PORTAL 714
#define SH_NODE_TEX_GABOR 715
#define SH_NODE_BSDF_METALLIC 716
/** \} */

View File

@@ -572,6 +572,7 @@ set(GLSL_SRC
shaders/material/gpu_shader_material_light_path.glsl
shaders/material/gpu_shader_material_mapping.glsl
shaders/material/gpu_shader_material_map_range.glsl
shaders/material/gpu_shader_material_metallic.glsl
shaders/material/gpu_shader_material_mix_color.glsl
shaders/material/gpu_shader_material_mix_shader.glsl
shaders/material/gpu_shader_material_noise.glsl

View File

@@ -0,0 +1,63 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
vec3 fresnel_conductor(float cosi, vec3 eta, vec3 k)
{
vec3 cosi_sqr = vec3(cosi * cosi);
vec3 one = vec3(1.0);
vec3 tmp_f = (eta * eta) + (k * k);
vec3 tmp_two_eta_cosi = 2.0 * eta * vec3(cosi);
vec3 tmp = tmp_f * cosi_sqr;
vec3 Rparl2 = (tmp - tmp_two_eta_cosi + one) / (tmp + tmp_two_eta_cosi + one);
vec3 Rperp2 = (tmp_f - tmp_two_eta_cosi + cosi_sqr) / (tmp_f + tmp_two_eta_cosi + cosi_sqr);
return (Rparl2 + Rperp2) * 0.5;
}
void node_bsdf_metallic(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)
{
vec3 F0 = base_color.rgb;
vec3 F82 = edge_tint.rgb;
if (use_complex_ior != 0.0) {
/* Compute incidence at 0 and 82 degrees from conductor Fresnel. */
F0 = fresnel_conductor(1.0, ior, extinction);
F82 = fresnel_conductor(1.0 / 7.0, ior, extinction);
}
/* Clamp to match Cycles */
F0 = saturate(F0);
F82 = saturate(F82);
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 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

@@ -2111,6 +2111,12 @@ enum {
CMP_NODE_CHANNEL_MATTE_CS_YCC = 4,
};
/* Conductive fresnel types */
enum {
SHD_PHYSICAL_CONDUCTOR = 0,
SHD_CONDUCTOR_F82 = 1,
};
/* glossy distributions */
enum {
SHD_GLOSSY_BECKMANN = 0,

View File

@@ -4116,6 +4116,33 @@ static const EnumPropertyItem node_ycc_items[] = {
{0, nullptr, 0, nullptr, nullptr},
};
static const EnumPropertyItem node_metallic_distribution_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_metallic_fresnel_type_items[] = {
{SHD_PHYSICAL_CONDUCTOR,
"PHYSICAL_CONDUCTOR",
0,
"Physical Conductor",
"Fresnel conductor based on the complex refractive index per color channel"},
{SHD_CONDUCTOR_F82,
"F82",
0,
"F82 Tint",
"An approximation of the Fresnel conductor curve based on the colors at perpendicular and "
"near-grazing (roughly 82°) angles"},
{0, nullptr, 0, nullptr, nullptr},
};
static const EnumPropertyItem node_glossy_items[] = {
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
@@ -5655,6 +5682,23 @@ static void def_sh_tex_pointdensity(StructRNA *srna)
RNA_def_function_output(func, parm);
}
static void def_metallic(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_metallic_distribution_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_metallic_fresnel_type_items);
RNA_def_property_ui_text(prop, "Fresnel Type", "Fresnel method used to tint the metal");
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_METALLIC, def_metallic, "BSDF_METALLIC", BsdfMetallic, "Metallic BSDF", "Metallic reflection with microfacet distribution, and metallic fresnel")
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 OpenPBR model")
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

@@ -36,6 +36,7 @@ set(SRC
nodes/node_shader_bsdf_glossy.cc
nodes/node_shader_bsdf_hair.cc
nodes/node_shader_bsdf_hair_principled.cc
nodes/node_shader_bsdf_metallic.cc
nodes/node_shader_bsdf_principled.cc
nodes/node_shader_bsdf_ray_portal.cc
nodes/node_shader_bsdf_refraction.cc

View File

@@ -24,6 +24,7 @@ void register_shader_nodes()
register_node_type_sh_bsdf_glossy();
register_node_type_sh_bsdf_hair_principled();
register_node_type_sh_bsdf_hair();
register_node_type_sh_bsdf_metallic();
register_node_type_sh_bsdf_principled();
register_node_type_sh_bsdf_ray_portal();
register_node_type_sh_bsdf_refraction();

View File

@@ -20,6 +20,7 @@ void register_node_type_sh_bsdf_glass();
void register_node_type_sh_bsdf_glossy();
void register_node_type_sh_bsdf_hair_principled();
void register_node_type_sh_bsdf_hair();
void register_node_type_sh_bsdf_metallic();
void register_node_type_sh_bsdf_principled();
void register_node_type_sh_bsdf_ray_portal();
void register_node_type_sh_bsdf_refraction();

View File

@@ -927,6 +927,7 @@ static void ntree_shader_weight_tree_invert(bNodeTree *ntree, bNode *output_node
break;
}
case SH_NODE_BACKGROUND:
case SH_NODE_BSDF_METALLIC:
case SH_NODE_BSDF_DIFFUSE:
case SH_NODE_BSDF_GLASS:
case SH_NODE_BSDF_GLOSSY:
@@ -985,6 +986,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_METALLIC:
case SH_NODE_BSDF_DIFFUSE:
case SH_NODE_BSDF_GLASS:
case SH_NODE_BSDF_GLOSSY:

View File

@@ -0,0 +1,168 @@
/* SPDX-FileCopyrightText: 2024 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_metallic_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>("Base Color")
.default_value({0.617f, 0.577f, 0.540f, 1.0f})
.description("Color of the material");
b.add_input<decl::Color>("Edge Tint")
.default_value({0.695f, 0.726f, 0.770f, 1.0f})
.description(
"Tint reflection at near-grazing incidence to simulate complex index of refraction");
b.add_input<decl::Vector>("IOR")
.default_value({2.757f, 2.513f, 2.231f})
.min(0.0f)
.max(100.0f)
.description("Real part of the conductor's refractive index, often called n");
b.add_input<decl::Vector>("Extinction")
.default_value({3.867f, 3.404f, 3.009f})
.min(0.0f)
.max(100.0f)
.description("Imaginary part of the conductor's refractive index, often called k");
b.add_input<decl::Float>("Roughness")
.default_value(0.5f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR)
.description(
"Microfacet roughness of the surface (0.0 is a perfect mirror reflection, 1.0 is "
"completely rough)");
;
b.add_input<decl::Float>("Anisotropy")
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR)
.description(
"Amount of anisotropy for reflection. Higher values give elongated highlights along the "
"tangent direction");
b.add_input<decl::Float>("Rotation")
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR)
.description("Rotates the direction of anisotropy, with 1.0 going full circle");
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_metallic(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_metallic(bNodeTree * /*ntree*/, bNode *node)
{
node->custom1 = SHD_GLOSSY_MULTI_GGX;
node->custom2 = SHD_CONDUCTOR_F82;
}
static int node_shader_gpu_bsdf_metallic(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_PHYSICAL_CONDUCTOR) ? 1.0f : 0.0f;
return GPU_stack_link(mat,
node,
"node_bsdf_metallic",
in,
out,
GPU_constant(&use_multi_scatter),
GPU_constant(&use_complex_ior));
}
static void node_shader_update_metallic(bNodeTree *ntree, bNode *node)
{
const bool is_physical = (node->custom2 == SHD_PHYSICAL_CONDUCTOR);
bke::node_set_socket_availability(
ntree, bke::node_find_socket(node, SOCK_IN, "Base Color"), !is_physical);
bke::node_set_socket_availability(
ntree, bke::node_find_socket(node, SOCK_IN, "Edge Tint"), !is_physical);
bke::node_set_socket_availability(
ntree, bke::node_find_socket(node, SOCK_IN, "IOR"), is_physical);
bke::node_set_socket_availability(
ntree, bke::node_find_socket(node, SOCK_IN, "Extinction"), is_physical);
}
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);
NodeItem ior_out, extinction_out;
if (node_->custom2 == SHD_PHYSICAL_CONDUCTOR) {
ior_out = get_input_value("IOR", NodeItem::Type::Color3);
extinction_out = get_input_value("Extinction", NodeItem::Type::Color3);
}
else {
NodeItem artistic_ior = create_node("artistic_ior",
NodeItem::Type::Multioutput,
{{"reflectivity", color}, {"edge_color", edge_tint}});
ior_out = artistic_ior.add_output("ior", NodeItem::Type::Color3);
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_metallic_cc
/* node type definition */
void register_node_type_sh_bsdf_metallic()
{
namespace file_ns = blender::nodes::node_shader_bsdf_metallic_cc;
static blender::bke::bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BSDF_METALLIC, "Metallic 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_metallic;
blender::bke::node_type_size_preset(&ntype, blender::bke::eNodeSizePreset::Large);
ntype.initfunc = file_ns::node_shader_init_metallic;
ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_metallic;
ntype.updatefunc = file_ns::node_shader_update_metallic;
ntype.materialx_fn = file_ns::node_shader_materialx;
blender::bke::node_register_type(&ntype);
}