Shader: Add Conductor BSDF Node #114958
|
@ -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>();
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue