Cycles: Replace Sheen model in the Principled BSDF #109949

Merged
Lukas Stockner merged 1 commits from LukasStockner/blender:sheen-principled into main 2023-07-27 02:17:52 +02:00
17 changed files with 161 additions and 242 deletions

View File

@ -136,7 +136,6 @@ set(SRC_KERNEL_CLOSURE_HEADERS
closure/emissive.h
closure/volume.h
closure/bsdf_principled_diffuse.h
closure/bsdf_principled_sheen.h
closure/bsdf_hair_principled.h
)

View File

@ -18,7 +18,6 @@
#include "kernel/closure/bsdf_hair.h"
#include "kernel/closure/bsdf_hair_principled.h"
#include "kernel/closure/bsdf_principled_diffuse.h"
#include "kernel/closure/bsdf_principled_sheen.h"
#include "kernel/closure/bssrdf.h"
#include "kernel/closure/volume.h"
// clang-format on
@ -210,11 +209,6 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg,
*sampled_roughness = one_float2();
*eta = 1.0f;
break;
case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID:
label = bsdf_principled_sheen_sample(sc, Ng, sd->wi, rand_xy, eval, wo, pdf);
*sampled_roughness = one_float2();
*eta = 1.0f;
break;
case CLOSURE_BSDF_SHEEN_ID:
label = bsdf_sheen_sample(sc, Ng, sd->wi, rand_xy, eval, wo, pdf);
*sampled_roughness = one_float2();
@ -351,10 +345,6 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg,
*roughness = one_float2();
*eta = 1.0f;
break;
case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID:
*roughness = one_float2();
*eta = 1.0f;
break;
case CLOSURE_BSDF_SHEEN_ID:
alpha = ((ccl_private SheenBsdf *)sc)->roughness;
*roughness = make_float2(alpha, alpha);
@ -439,7 +429,6 @@ ccl_device_inline int bsdf_label(const KernelGlobals kg,
case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID:
label = LABEL_REFLECT | LABEL_DIFFUSE;
break;
case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID:
case CLOSURE_BSDF_SHEEN_ID:
label = LABEL_REFLECT | LABEL_DIFFUSE;
break;
@ -534,9 +523,6 @@ ccl_device_inline
case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID:
eval = bsdf_principled_diffuse_eval(sc, sd->wi, wo, pdf);
break;
case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID:
eval = bsdf_principled_sheen_eval(sc, sd->wi, wo, pdf);
break;
case CLOSURE_BSDF_SHEEN_ID:
eval = bsdf_sheen_eval(sc, sd->wi, wo, pdf);
break;
@ -615,10 +601,6 @@ ccl_device_inline Spectrum bsdf_albedo(ccl_private const ShaderData *sd,
albedo *= bsdf_microfacet_estimate_fresnel(
sd, (ccl_private const MicrofacetBsdf *)sc, reflection, transmission);
}
else if (sc->type == CLOSURE_BSDF_PRINCIPLED_SHEEN_ID) {
kernel_assert(reflection);
albedo *= ((ccl_private const PrincipledSheenBsdf *)sc)->avg_value;
}
else if (sc->type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) {
/* TODO(lukas): Principled Hair could also be split into a glossy and a transmission component,
* similar to Glass BSDFs. */

View File

@ -1,111 +0,0 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
#pragma once
/* DISNEY PRINCIPLED SHEEN BRDF
*
* Shading model by Brent Burley (Disney): "Physically Based Shading at Disney" (2012)
*/
#include "kernel/closure/bsdf_util.h"
CCL_NAMESPACE_BEGIN
typedef struct PrincipledSheenBsdf {
SHADER_CLOSURE_BASE;
float avg_value;
} PrincipledSheenBsdf;
static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledSheenBsdf),
"PrincipledSheenBsdf is too large!");
ccl_device_inline float calculate_avg_principled_sheen_brdf(float3 N, float3 I)
{
/* To compute the average, we set the half-vector to the normal, resulting in
* NdotI = NdotL = NdotV = LdotH */
float NdotI = dot(N, I);
if (NdotI < 0.0f) {
return 0.0f;
}
return schlick_fresnel(NdotI) * NdotI;
}
ccl_device Spectrum
calculate_principled_sheen_brdf(float3 N, float3 V, float3 L, float3 H, ccl_private float *pdf)
{
float NdotL = dot(N, L);
float NdotV = dot(N, V);
if (NdotL < 0 || NdotV < 0) {
*pdf = 0.0f;
return zero_spectrum();
}
float LdotH = dot(L, H);
float value = schlick_fresnel(LdotH) * NdotL;
return make_spectrum(value);
}
ccl_device int bsdf_principled_sheen_setup(ccl_private const ShaderData *sd,
ccl_private PrincipledSheenBsdf *bsdf)
{
bsdf->type = CLOSURE_BSDF_PRINCIPLED_SHEEN_ID;
bsdf->avg_value = calculate_avg_principled_sheen_brdf(bsdf->N, sd->wi);
bsdf->sample_weight *= bsdf->avg_value;
return SD_BSDF | SD_BSDF_HAS_EVAL;
}
ccl_device Spectrum bsdf_principled_sheen_eval(ccl_private const ShaderClosure *sc,
const float3 wi,
const float3 wo,
ccl_private float *pdf)
{
ccl_private const PrincipledSheenBsdf *bsdf = (ccl_private const PrincipledSheenBsdf *)sc;
const float3 N = bsdf->N;
if (dot(N, wo) > 0.0f) {
const float3 V = wi;
const float3 L = wo;
const float3 H = normalize(L + V);
*pdf = fmaxf(dot(N, wo), 0.0f) * M_1_PI_F;
return calculate_principled_sheen_brdf(N, V, L, H, pdf);
}
else {
*pdf = 0.0f;
return zero_spectrum();
}
}
ccl_device int bsdf_principled_sheen_sample(ccl_private const ShaderClosure *sc,
float3 Ng,
float3 wi,
float2 rand,
ccl_private Spectrum *eval,
ccl_private float3 *wo,
ccl_private float *pdf)
{
ccl_private const PrincipledSheenBsdf *bsdf = (ccl_private const PrincipledSheenBsdf *)sc;
float3 N = bsdf->N;
sample_cos_hemisphere(N, rand, wo, pdf);
if (dot(Ng, *wo) > 0) {
float3 H = normalize(wi + *wo);
*eval = calculate_principled_sheen_brdf(N, wi, *wo, H, pdf);
}
else {
*eval = zero_spectrum();
*pdf = 0.0f;
}
return LABEL_REFLECT | LABEL_DIFFUSE;
}
CCL_NAMESPACE_END

View File

@ -21,7 +21,6 @@
#include "kernel/closure/bsdf_hair.h"
#include "kernel/closure/bsdf_hair_principled.h"
#include "kernel/closure/bsdf_principled_diffuse.h"
#include "kernel/closure/bsdf_principled_sheen.h"
#include "kernel/closure/volume.h"
#include "kernel/closure/bsdf_diffuse_ramp.h"
#include "kernel/closure/bsdf_phong_ramp.h"
@ -651,29 +650,6 @@ ccl_device void osl_closure_principled_diffuse_setup(
sd->flag |= bsdf_principled_diffuse_setup(bsdf);
}
ccl_device void osl_closure_principled_sheen_setup(
KernelGlobals kg,
ccl_private ShaderData *sd,
uint32_t path_flag,
float3 weight,
ccl_private const PrincipledSheenClosure *closure)
{
if (osl_closure_skip(kg, sd, path_flag, LABEL_DIFFUSE)) {
return;
}
ccl_private PrincipledSheenBsdf *bsdf = (ccl_private PrincipledSheenBsdf *)bsdf_alloc(
sd, sizeof(PrincipledSheenBsdf), rgb_to_spectrum(weight));
if (!bsdf) {
return;
}
bsdf->N = closure->N;
bsdf->avg_value = 0.0f;
sd->flag |= bsdf_principled_sheen_setup(sd, bsdf);
}
/* Variable cone emissive closure
*
* This primitive emits in a cone having a configurable penumbra area where the light decays to 0

View File

@ -137,10 +137,6 @@ OSL_CLOSURE_STRUCT_BEGIN(PrincipledDiffuse, principled_diffuse)
OSL_CLOSURE_STRUCT_MEMBER(PrincipledDiffuse, FLOAT, float, roughness, NULL)
OSL_CLOSURE_STRUCT_END(PrincipledDiffuse, principled_diffuse)
OSL_CLOSURE_STRUCT_BEGIN(PrincipledSheen, principled_sheen)
OSL_CLOSURE_STRUCT_MEMBER(PrincipledSheen, VECTOR, packed_float3, N, NULL)
OSL_CLOSURE_STRUCT_END(PrincipledSheen, principled_sheen)
OSL_CLOSURE_STRUCT_BEGIN(GenericEmissive, emission)
OSL_CLOSURE_STRUCT_END(GenericEmissive, emission)

View File

@ -19,7 +19,8 @@ shader node_principled_bsdf(string distribution = "multi_ggx",
float Anisotropic = 0.0,
float AnisotropicRotation = 0.0,
float Sheen = 0.0,
float SheenTint = 0.5,
float SheenRoughness = 0.5,
color SheenTint = 0.5,
float Clearcoat = 0.0,
float ClearcoatRoughness = 0.03,
float IOR = 1.45,
@ -64,9 +65,7 @@ shader node_principled_bsdf(string distribution = "multi_ggx",
}
if (Sheen > 1e-5) {
color sheen_color = mix(color(1.0), m_ctint, SheenTint);
BSDF += sheen_color * Sheen * principled_sheen(Normal);
BSDF += SheenTint * Sheen * sheen(Normal, SheenRoughness);
}
BSDF *= diffuse_weight;

View File

@ -26,7 +26,6 @@ closure color ashikhmin_velvet(normal N, float sigma) BUILTIN;
closure color sheen(normal N, float roughness) BUILTIN;
closure color ambient_occlusion() BUILTIN;
closure color principled_diffuse(normal N, float roughness) BUILTIN;
closure color principled_sheen(normal N) BUILTIN;
/* Needed to pass along the color for multi-scattering saturation adjustment,
* otherwise could be replaced by microfacet() */

View File

@ -94,7 +94,8 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
float specular_tint = stack_load_float(stack, specular_tint_offset);
float anisotropic = stack_load_float(stack, anisotropic_offset);
float sheen = stack_load_float(stack, sheen_offset);
float sheen_tint = stack_load_float(stack, sheen_tint_offset);
float3 sheen_tint = stack_load_float3(stack, sheen_tint_offset);
float sheen_roughness = stack_load_float(stack, data_node2.w);
float clearcoat = stack_load_float(stack, clearcoat_offset);
float clearcoat_roughness = stack_load_float(stack, clearcoat_roughness_offset);
float transmission = stack_load_float(stack, transmission_offset);
@ -220,23 +221,17 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
/* sheen */
if (diffuse_weight > CLOSURE_WEIGHT_CUTOFF && sheen > CLOSURE_WEIGHT_CUTOFF) {
float m_cdlum = linear_rgb_to_gray(kg, base_color);
float3 m_ctint = m_cdlum > 0.0f ? base_color / m_cdlum :
one_float3(); // normalize lum. to isolate hue+sat
Spectrum sheen_weight = weight * sheen * rgb_to_spectrum(sheen_tint) * diffuse_weight;
/* color of the sheen component */
float3 sheen_color = make_float3(1.0f - sheen_tint) + m_ctint * sheen_tint;
Spectrum sheen_weight = weight * sheen * rgb_to_spectrum(sheen_color) * diffuse_weight;
ccl_private PrincipledSheenBsdf *bsdf = (ccl_private PrincipledSheenBsdf *)bsdf_alloc(
sd, sizeof(PrincipledSheenBsdf), sheen_weight);
ccl_private SheenBsdf *bsdf = (ccl_private SheenBsdf *)bsdf_alloc(
sd, sizeof(SheenBsdf), sheen_weight);
if (bsdf) {
bsdf->N = N;
bsdf->roughness = sheen_roughness;
/* setup bsdf */
sd->flag |= bsdf_principled_sheen_setup(sd, bsdf);
sd->flag |= bsdf_sheen_setup(kg, sd, bsdf);
}
}

View File

@ -415,7 +415,6 @@ typedef enum ClosureType {
CLOSURE_BSDF_OREN_NAYAR_ID,
CLOSURE_BSDF_DIFFUSE_RAMP_ID,
CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID,
CLOSURE_BSDF_PRINCIPLED_SHEEN_ID,
CLOSURE_BSDF_SHEEN_ID,
CLOSURE_BSDF_DIFFUSE_TOON_ID,
CLOSURE_BSDF_TRANSLUCENT_ID,

View File

@ -2661,7 +2661,8 @@ NODE_DEFINE(PrincipledBsdfNode)
SOCKET_IN_FLOAT(specular_tint, "Specular Tint", 0.0f);
SOCKET_IN_FLOAT(anisotropic, "Anisotropic", 0.0f);
SOCKET_IN_FLOAT(sheen, "Sheen", 0.0f);
SOCKET_IN_FLOAT(sheen_tint, "Sheen Tint", 0.0f);
SOCKET_IN_FLOAT(sheen_roughness, "Sheen Roughness", 0.5f);
SOCKET_IN_COLOR(sheen_tint, "Sheen Tint", one_float3());
SOCKET_IN_FLOAT(clearcoat, "Clearcoat", 0.0f);
SOCKET_IN_FLOAT(clearcoat_roughness, "Clearcoat Roughness", 0.03f);
SOCKET_IN_FLOAT(ior, "IOR", 0.0f);
@ -2771,6 +2772,7 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler,
ShaderInput *p_specular_tint,
ShaderInput *p_anisotropic,
ShaderInput *p_sheen,
ShaderInput *p_sheen_roughness,
ShaderInput *p_sheen_tint,
ShaderInput *p_clearcoat,
ShaderInput *p_clearcoat_roughness,
@ -2796,6 +2798,7 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler,
int specular_tint_offset = compiler.stack_assign(p_specular_tint);
int anisotropic_offset = compiler.stack_assign(p_anisotropic);
int sheen_offset = compiler.stack_assign(p_sheen);
int sheen_roughness_offset = compiler.stack_assign(p_sheen_roughness);
int sheen_tint_offset = compiler.stack_assign(p_sheen_tint);
int clearcoat_offset = compiler.stack_assign(p_clearcoat);
int clearcoat_roughness_offset = compiler.stack_assign(p_clearcoat_roughness);
@ -2827,7 +2830,7 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler,
ior_offset, transmission_offset, anisotropic_rotation_offset, SVM_STACK_INVALID),
distribution,
subsurface_method,
SVM_STACK_INVALID);
sheen_roughness_offset);
float3 bc_default = get_float3(base_color_in->socket_type);
@ -2864,6 +2867,7 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler)
input("Specular Tint"),
input("Anisotropic"),
input("Sheen"),
input("Sheen Roughness"),
input("Sheen Tint"),
input("Clearcoat"),
input("Clearcoat Roughness"),

View File

@ -526,6 +526,7 @@ class PrincipledBsdfNode : public BsdfBaseNode {
ShaderInput *specular_tint,
ShaderInput *anisotropic,
ShaderInput *sheen,
ShaderInput *sheen_roughness,
ShaderInput *sheen_tint,
ShaderInput *clearcoat,
ShaderInput *clearcoat_roughness,
@ -545,7 +546,8 @@ class PrincipledBsdfNode : public BsdfBaseNode {
NODE_SOCKET_API(float, specular_tint)
NODE_SOCKET_API(float, anisotropic)
NODE_SOCKET_API(float, sheen)
NODE_SOCKET_API(float, sheen_tint)
NODE_SOCKET_API(float, sheen_roughness)
NODE_SOCKET_API(float3, sheen_tint)
NODE_SOCKET_API(float, clearcoat)
NODE_SOCKET_API(float, clearcoat_roughness)
NODE_SOCKET_API(float, ior)

View File

@ -1228,43 +1228,23 @@ static void displacement_principled_nodes(bNode *node)
}
}
static bool node_has_roughness(const bNode *node)
{
return ELEM(node->type,
SH_NODE_BSDF_GLASS,
SH_NODE_BSDF_GLOSSY_LEGACY,
SH_NODE_BSDF_GLOSSY,
SH_NODE_BSDF_REFRACTION);
}
static void square_roughness_node_insert(bNodeTree *ntree)
{
bool need_update = false;
/* Update default values */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node_has_roughness(node)) {
bNodeSocket *roughness_input = nodeFindSocket(node, SOCK_IN, "Roughness");
float *roughness_value = version_cycles_node_socket_float_value(roughness_input);
*roughness_value = sqrtf(max_ff(*roughness_value, 0.0f));
}
}
/* Iterate backwards from end so we don't encounter newly added links. */
LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
/* Detect link to replace. */
bNode *fromnode = link->fromnode;
bNodeSocket *fromsock = link->fromsock;
bNode *tonode = link->tonode;
bNodeSocket *tosock = link->tosock;
if (!(node_has_roughness(tonode) && STREQ(tosock->identifier, "Roughness"))) {
continue;
}
/* Replace links with sqrt node */
nodeRemLink(ntree, link);
auto check_node = [](const bNode *node) {
return ELEM(node->type,
SH_NODE_BSDF_GLASS,
SH_NODE_BSDF_GLOSSY_LEGACY,
SH_NODE_BSDF_GLOSSY,
SH_NODE_BSDF_REFRACTION);
};
auto update_input = [](const bNode *, bNodeSocket *input) {
float *value = version_cycles_node_socket_float_value(input);
*value = sqrtf(max_ff(*value, 0.0f));
};
auto update_input_link = [ntree](bNode *fromnode,
bNodeSocket *fromsock,
bNode *tonode,
bNodeSocket *tosock) {
/* Add sqrt node. */
bNode *node = nodeAddStaticNode(nullptr, ntree, SH_NODE_MATH);
node->custom1 = NODE_MATH_POWER;
@ -1275,13 +1255,9 @@ static void square_roughness_node_insert(bNodeTree *ntree)
*version_cycles_node_socket_float_value(static_cast<bNodeSocket *>(node->inputs.last)) = 0.5f;
nodeAddLink(ntree, fromnode, fromsock, node, static_cast<bNodeSocket *>(node->inputs.first));
nodeAddLink(ntree, node, static_cast<bNodeSocket *>(node->outputs.first), tonode, tosock);
};
need_update = true;
}
if (need_update) {
version_socket_update_is_used(ntree);
}
version_update_node_input(ntree, check_node, "Roughness", update_input, update_input_link);
}
static void mapping_node_order_flip(bNode *node)

View File

@ -25,6 +25,7 @@
#include "BLI_assert.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_set.hh"
#include "BLI_string_ref.hh"
@ -296,6 +297,49 @@ static void version_replace_velvet_sheen_node(bNodeTree *ntree)
}
}
/* Convert sheen inputs on the Principled BSDF. */
static void version_principled_bsdf_sheen(bNodeTree *ntree)
{
auto check_node = [](const bNode *node) {
return (node->type == SH_NODE_BSDF_PRINCIPLED) &&

Why does this check node != nullptr, but square_roughness_node_insert does not?

Maybe move that check to version_update_node_input.

Why does this check `node != nullptr`, but `square_roughness_node_insert` does not? Maybe move that check to `version_update_node_input`.

Might be used version_node_id, version_node_socket_name, version_node_input_socket_name, node_tree_relink_with_socket_id_map too

Might be used `version_node_id`, `version_node_socket_name`, `version_node_input_socket_name`, `node_tree_relink_with_socket_id_map` too

Might be used version_node_id, version_node_socket_name, version_node_input_socket_name, node_tree_relink_with_socket_id_map too

These look useful in general, but in this case there's some additional conversion going on (the type of the socket changes, as well as the default value in case of old files), so there would need to be custom logic anyways.

> Might be used `version_node_id`, `version_node_socket_name`, `version_node_input_socket_name`, `node_tree_relink_with_socket_id_map` too These look useful in general, but in this case there's some additional conversion going on (the type of the socket changes, as well as the default value in case of old files), so there would need to be custom logic anyways.

Why does this check node != nullptr, but square_roughness_node_insert does not?

For some reason tests/render/reports/T48790.blend contains a link with tonode==NULL. But yeah, it's better to handle it in version_update_node_input.

> Why does this check `node != nullptr`, but `square_roughness_node_insert` does not? For some reason `tests/render/reports/T48790.blend` contains a link with `tonode==NULL`. But yeah, it's better to handle it in `version_update_node_input`.

These look useful in general, but in this case there's some additional conversion going on (the type of the socket changes, as well as the default value in case of old files), so there would need to be custom logic anyways.

Changing the socket type and its value, is this the area of runtime declarations...?

> These look useful in general, but in this case there's some additional conversion going on (the type of the socket changes, as well as the default value in case of old files), so there would need to be custom logic anyways. Changing the socket type and its value, is this the area of runtime declarations...?

Changing the socket type and its value, is this the area of runtime declarations...?

Not sure about the details, but I don't think so, the type of the socket is fixed - it's just a one-time change from older to newer versions.

> Changing the socket type and its value, is this the area of runtime declarations...? Not sure about the details, but I don't think so, the type of the socket is fixed - it's just a one-time change from older to newer versions.
(nodeFindSocket(node, SOCK_IN, "Sheen Roughness") == nullptr);
};
auto update_input = [ntree](bNode *node, bNodeSocket *input) {
/* Change socket type to Color. */
nodeModifySocketTypeStatic(ntree, node, input, SOCK_RGBA, 0);
/* Account for the change in intensity between the old and new model.
* If the Sheen input is set to a fixed value, adjust it and set the tint to white.
* Otherwise, if it's connected, keep it as-is but set the tint to 0.2 instead. */
static float default_value_dim[] = {0.2f, 0.2f, 0.2f, 1.0f};
bNodeSocket *sheen = nodeFindSocket(node, SOCK_IN, "Sheen");
if (sheen != nullptr && sheen->link == nullptr) {
*version_cycles_node_socket_float_value(sheen) *= 0.2f;
static float default_value[] = {1.0f, 1.0f, 1.0f, 1.0f};
copy_v4_v4(version_cycles_node_socket_rgba_value(input), default_value);
}
else {
static float default_value[] = {0.2f, 0.2f, 0.2f, 1.0f};
copy_v4_v4(version_cycles_node_socket_rgba_value(input), default_value);
}
};
auto update_input_link = [](bNode *, bNodeSocket *, bNode *, bNodeSocket *) {
/* Don't replace the link here, tint works differently enough now to make conversion
* impractical. */
};
version_update_node_input(ntree, check_node, "Sheen Tint", update_input, update_input_link);
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (check_node(node)) {
bNodeSocket *input = nodeAddStaticSocket(
ntree, node, SOCK_IN, SOCK_FLOAT, PROP_FACTOR, "Sheen Roughness", "Sheen Roughness");
*version_cycles_node_socket_float_value(input) = 0.5f;
}
}
}
void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
{
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 1)) {
@ -450,6 +494,8 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
version_principled_transmission_roughness(ntree);
/* Convert legacy Velvet BSDF nodes into the new Sheen BSDF node. */
version_replace_velvet_sheen_node(ntree);
/* Convert sheen inputs on the Principled BSDF. */
version_principled_bsdf_sheen(ntree);
}
}
FOREACH_NODETREE_END;

View File

@ -403,3 +403,48 @@ IDProperty *version_cycles_visibility_properties_from_ID(ID *id)
IDProperty *idprop = IDP_GetProperties(id, false);
return (idprop) ? IDP_GetPropertyTypeFromGroup(idprop, "cycles_visibility", IDP_GROUP) : nullptr;
}
void version_update_node_input(
bNodeTree *ntree,
FunctionRef<bool(bNode *)> check_node,
const char *socket_identifier,
FunctionRef<void(bNode *, bNodeSocket *)> update_input,
FunctionRef<void(bNode *, bNodeSocket *, bNode *, bNodeSocket *)> update_input_link)
{
bool need_update = false;
/* Iterate backwards from end so we don't encounter newly added links. */
LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
/* Detect link to replace. */
bNode *fromnode = link->fromnode;
bNodeSocket *fromsock = link->fromsock;
bNode *tonode = link->tonode;
bNodeSocket *tosock = link->tosock;
if (!(tonode != nullptr && check_node(tonode) && STREQ(tosock->identifier, socket_identifier)))
{
continue;
}
/* Replace links with updated equivalent */
nodeRemLink(ntree, link);
update_input_link(fromnode, fromsock, tonode, tosock);
need_update = true;
}
/* Update sockets and/or their default values.
* Do this after the link update in case it changes the identifier. */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (check_node(node)) {
bNodeSocket *input = nodeFindSocket(node, SOCK_IN, socket_identifier);
if (input != nullptr) {
update_input(node, input);
}
}
}
if (need_update) {
version_socket_update_is_used(ntree);
}
}

View File

@ -9,7 +9,9 @@
#pragma once
#ifdef __cplusplus
# include "BLI_function_ref.hh"
# include "BLI_map.hh"
using blender::FunctionRef;
#endif
struct ARegion;
@ -149,4 +151,10 @@ void node_tree_relink_with_socket_id_map(bNodeTree &ntree,
bNode &old_node,
bNode &new_node,
const blender::Map<std::string, std::string> &map);
void version_update_node_input(
bNodeTree *ntree,
FunctionRef<bool(bNode *)> check_node,
const char *socket_identifier,
FunctionRef<void(bNode *, bNodeSocket *)> update_input,
FunctionRef<void(bNode *, bNodeSocket *, bNode *, bNodeSocket *)> update_input_link);
#endif

View File

@ -5,12 +5,14 @@ vec3 tint_from_color(vec3 color)
return (lum > 0.0) ? color / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
}
float principled_sheen(float NV)
float principled_sheen(float NV, float rough)
{
float f = 1.0 - NV;
/* Empirical approximation (manual curve fitting). Can be refined. */
float sheen = f * f * f * 0.077 + f * 0.01 + 0.00026;
return sheen;
/* Empirical approximation (manual curve fitting) to the sheen albedo. Can be refined. */
float den = 35.6694f * rough * rough - 24.4269f * rough * NV - 0.1405f * NV * NV +
6.1211f * rough + 0.28105f * NV - 0.1405f;
float num = 58.5299f * rough * rough - 85.0941f * rough * NV + 9.8955f * NV * NV +
1.9250f * rough + 74.2268f * NV - 0.2246f;
return saturate(den / num);
}
void node_bsdf_principled(vec4 base_color,
@ -26,7 +28,8 @@ void node_bsdf_principled(vec4 base_color,
float anisotropic,
float anisotropic_rotation,
float sheen,
float sheen_tint,
float sheen_roughness,
vec4 sheen_tint,
float clearcoat,
float clearcoat_roughness,
float ior,
@ -82,8 +85,7 @@ void node_bsdf_principled(vec4 base_color,
diffuse_data.weight = diffuse_weight * weight;
diffuse_data.color = mix(base_color.rgb, subsurface_color.rgb, subsurface);
/* Sheen Coarse approximation: We reuse the diffuse radiance and just scale it. */
vec3 sheen_color = mix(vec3(1.0), base_color_tint, sheen_tint);
diffuse_data.color += sheen * sheen_color * principled_sheen(NV);
diffuse_data.color += sheen * sheen_tint.rgb * principled_sheen(NV, sheen_roughness);
diffuse_data.N = N;
diffuse_data.sss_radius = subsurface_radius * subsurface;
diffuse_data.sss_id = uint(do_sss);

View File

@ -83,48 +83,50 @@ static void node_declare(NodeDeclarationBuilder &b)
#define SOCK_ANISOTROPIC_ROTATION_ID 11
b.add_input<decl::Float>("Sheen").default_value(0.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
#define SOCK_SHEEN_ID 12
b.add_input<decl::Float>("Sheen Tint")
b.add_input<decl::Float>("Sheen Roughness")
.default_value(0.5f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
#define SOCK_SHEEN_TINT_ID 13
#define SOCK_SHEEN_ROUGHNESS_ID 13
b.add_input<decl::Color>("Sheen Tint").default_value({1.0f, 1.0f, 1.0f, 1.0f});
#define SOCK_SHEEN_TINT_ID 14
b.add_input<decl::Float>("Clearcoat")
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
#define SOCK_CLEARCOAT_ID 14
#define SOCK_CLEARCOAT_ID 15
b.add_input<decl::Float>("Clearcoat Roughness")
.default_value(0.03f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
#define SOCK_CLEARCOAT_ROUGHNESS_ID 15
#define SOCK_CLEARCOAT_ROUGHNESS_ID 16
b.add_input<decl::Float>("IOR").default_value(1.45f).min(0.0f).max(1000.0f);
#define SOCK_IOR_ID 16
#define SOCK_IOR_ID 17
b.add_input<decl::Float>("Transmission")
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
#define SOCK_TRANSMISSION_ID 17
#define SOCK_TRANSMISSION_ID 18
b.add_input<decl::Color>("Emission").default_value({0.0f, 0.0f, 0.0f, 1.0f});
#define SOCK_EMISSION_ID 18
#define SOCK_EMISSION_ID 19
b.add_input<decl::Float>("Emission Strength").default_value(1.0).min(0.0f).max(1000000.0f);
#define SOCK_EMISSION_STRENGTH_ID 19
#define SOCK_EMISSION_STRENGTH_ID 20
b.add_input<decl::Float>("Alpha").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
#define SOCK_ALPHA_ID 20
#define SOCK_ALPHA_ID 21
b.add_input<decl::Vector>("Normal").hide_value();
#define SOCK_NORMAL_ID 21
#define SOCK_NORMAL_ID 22
b.add_input<decl::Vector>("Clearcoat Normal").hide_value();
#define SOCK_CLEARCOAT_NORMAL_ID 22
#define SOCK_CLEARCOAT_NORMAL_ID 23
b.add_input<decl::Vector>("Tangent").hide_value();
#define SOCK_TANGENT_ID 23
#define SOCK_TANGENT_ID 24
b.add_input<decl::Float>("Weight").unavailable();
#define SOCK_WEIGHT_ID 24
#define SOCK_WEIGHT_ID 25
b.add_output<decl::Shader>("BSDF");
#define SOCK_BSDF_ID 25
#define SOCK_BSDF_ID 26
}
static void node_shader_buts_principled(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)