Cycles: Rework Principled BSDF Emission #111155

Merged
Lukas Stockner merged 7 commits from LukasStockner/blender:emission-principled into main 2023-09-13 03:05:35 +02:00
8 changed files with 126 additions and 57 deletions

View File

@ -28,6 +28,9 @@ shader node_principled_bsdf(string distribution = "multi_ggx",
color CoatTint = color(1.0, 1.0, 1.0),
float IOR = 1.45,
float Transmission = 0.0,
color Emission = 1.0,
float EmissionStrength = 0.0,
float Alpha = 1.0,
normal Normal = N,
normal CoatNormal = N,
normal Tangent = normalize(dPdu),
@ -99,6 +102,10 @@ shader node_principled_bsdf(string distribution = "multi_ggx",
BSDF = mix(BSDF, MetallicBSDF, clamp(Metallic, 0.0, 1.0));
}
if (EmissionStrength > 0.0 && Emission != color(0.0)) {
BSDF += EmissionStrength * Emission * emission();
}
if (Coat > 1e-5) {
float coat_ior = max(CoatIOR, 1.0);
if (CoatTint != color(1.0)) {
@ -117,4 +124,6 @@ shader node_principled_bsdf(string distribution = "multi_ggx",
closure color SheenBSDF = sheen(Normal, SheenRoughness);
BSDF = layer(SheenTint * Sheen * SheenBSDF, BSDF);
}
BSDF = mix(transparent(), BSDF, Alpha);
}

View File

@ -22,6 +22,7 @@ ccl_device_inline int svm_node_closure_bsdf_skip(KernelGlobals kg, int offset, u
read_node(kg, &offset);
read_node(kg, &offset);
read_node(kg, &offset);
read_node(kg, &offset);
}
return offset;
@ -53,6 +54,12 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
return svm_node_closure_bsdf_skip(kg, offset, type);
}
}
else IF_KERNEL_NODES_FEATURE(EMISSION) {
if (type != CLOSURE_BSDF_PRINCIPLED_ID) {
/* Only principled BSDF can have emission. */
return svm_node_closure_bsdf_skip(kg, offset, type);
}
}
else {
return svm_node_closure_bsdf_skip(kg, offset, type);
}
@ -70,7 +77,8 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
uint specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset,
sheen_offset, sheen_tint_offset, sheen_roughness_offset, coat_offset,
coat_roughness_offset, coat_ior_offset, eta_offset, transmission_offset,
anisotropic_rotation_offset, coat_tint_offset, coat_normal_offset, dummy;
anisotropic_rotation_offset, coat_tint_offset, coat_normal_offset, dummy,
alpha_offset, emission_strength_offset, emission_offset;
uint4 data_node2 = read_node(kg, &offset);
float3 T = stack_load_float3(stack, data_node.y);
@ -129,6 +137,20 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
sd->N;
coat_normal = maybe_ensure_valid_specular_reflection(sd, coat_normal);
uint4 data_alpha_emission = read_node(kg, &offset);
svm_unpack_node_uchar4(data_alpha_emission.x,
&alpha_offset,
&emission_strength_offset,
&emission_offset,
&dummy);
float alpha = stack_valid(alpha_offset) ? stack_load_float(stack, alpha_offset) :
__uint_as_float(data_alpha_emission.y);
float3 emission = stack_load_float3(stack, emission_offset);
/* Emission strength */
emission *= stack_valid(emission_strength_offset) ?
stack_load_float(stack, emission_strength_offset) :
__uint_as_float(data_alpha_emission.z);
Spectrum weight = closure_weight * mix_weight;
float alpha_x = sqr(roughness), alpha_y = sqr(roughness);
@ -151,6 +173,12 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
const bool glass_caustics = true;
#endif
/* Before any actual shader components, apply transparency. */
if (alpha < 1.0f) {
bsdf_transparent_setup(sd, weight * (1.0f - alpha), path_flag);
weight *= alpha;
}
/* First layer: Sheen */
if (sheen > CLOSURE_WEIGHT_CUTOFF) {
ccl_private SheenBsdf *bsdf = (ccl_private SheenBsdf *)bsdf_alloc(
@ -217,6 +245,11 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
weight *= power(rgb_to_spectrum(coat_tint), coat * optical_depth);
}
/* Emission (attenuated by sheen and coat) */
if (!is_zero(emission)) {
emission_setup(sd, rgb_to_spectrum(emission) * weight);
}
/* Metallic component */
if (reflective_caustics && metallic > CLOSURE_WEIGHT_CUTOFF) {
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(

View File

@ -133,11 +133,18 @@ static float3 output_estimate_emission(ShaderOutput *output, bool &is_constant)
return zero_float3();
}
else if (node->type == EmissionNode::get_node_type() ||
node->type == BackgroundNode::get_node_type())
node->type == BackgroundNode::get_node_type() ||
node->type == PrincipledBsdfNode::get_node_type())
{
const bool is_principled = (node->type == PrincipledBsdfNode::get_node_type());
/* Emission and Background node. */
ShaderInput *color_in = node->input("Color");
ShaderInput *strength_in = node->input("Strength");
ShaderInput *color_in = node->input(is_principled ? "Emission" : "Color");
ShaderInput *strength_in = node->input(is_principled ? "Emission Strength" : "Strength");
if (is_principled) {
/* Too many parameters (coat, sheen, alpha) influence Emission for the Principled BSDF. */
is_constant = false;
}
float3 estimate = one_float3();

View File

@ -2681,8 +2681,8 @@ NODE_DEFINE(PrincipledBsdfNode)
SOCKET_IN_FLOAT(ior, "IOR", 0.0f);
SOCKET_IN_FLOAT(transmission, "Transmission", 0.0f);
SOCKET_IN_FLOAT(anisotropic_rotation, "Anisotropic Rotation", 0.0f);
SOCKET_IN_COLOR(emission, "Emission", zero_float3());
SOCKET_IN_FLOAT(emission_strength, "Emission Strength", 1.0f);
SOCKET_IN_COLOR(emission, "Emission", one_float3());
SOCKET_IN_FLOAT(emission_strength, "Emission Strength", 0.0f);
SOCKET_IN_FLOAT(alpha, "Alpha", 1.0f);
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
SOCKET_IN_NORMAL(coat_normal, "Coat Normal", zero_float3(), SocketType::LINK_NORMAL);
@ -2700,60 +2700,33 @@ PrincipledBsdfNode::PrincipledBsdfNode() : BsdfBaseNode(get_node_type())
distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
}
void PrincipledBsdfNode::expand(ShaderGraph *graph)
void PrincipledBsdfNode::simplify_settings(Scene * /* scene */)
{
ShaderOutput *principled_out = output("BSDF");
ShaderInput *emission_in = input("Emission");
ShaderInput *emission_strength_in = input("Emission Strength");
if ((emission_in->link || emission != zero_float3()) &&
(emission_strength_in->link || emission_strength != 0.0f))
{
/* Create add closure and emission, and relink inputs. */
AddClosureNode *add = graph->create_node<AddClosureNode>();
EmissionNode *emission_node = graph->create_node<EmissionNode>();
ShaderOutput *new_out = add->output("Closure");
graph->add(add);
graph->add(emission_node);
graph->relink(emission_strength_in, emission_node->input("Strength"));
graph->relink(emission_in, emission_node->input("Color"));
graph->relink(principled_out, new_out);
graph->connect(emission_node->output("Emission"), add->input("Closure1"));
graph->connect(principled_out, add->input("Closure2"));
principled_out = new_out;
}
else {
/* Disconnect unused links if the other value is zero, required before
* we remove the input from the node entirely. */
if (!has_surface_emission()) {
/* Emission will be zero, so optimize away any connected emission input. */
ShaderInput *emission_in = input("Emission");
ShaderInput *strength_in = input("Emission Strength");
if (emission_in->link) {
emission_in->disconnect();
}
if (emission_strength_in->link) {
emission_strength_in->disconnect();
if (strength_in->link) {
strength_in->disconnect();
}
}
}
bool PrincipledBsdfNode::has_surface_transparent()
{
ShaderInput *alpha_in = input("Alpha");
if (alpha_in->link || alpha != 1.0f) {
/* Create mix and transparent BSDF for alpha transparency. */
MixClosureNode *mix = graph->create_node<MixClosureNode>();
TransparentBsdfNode *transparent = graph->create_node<TransparentBsdfNode>();
return (alpha_in->link != NULL || alpha < (1.0f - CLOSURE_WEIGHT_CUTOFF));
}
graph->add(mix);
graph->add(transparent);
graph->relink(alpha_in, mix->input("Fac"));
graph->relink(principled_out, mix->output("Closure"));
graph->connect(transparent->output("BSDF"), mix->input("Closure1"));
graph->connect(principled_out, mix->input("Closure2"));
}
remove_input(emission_in);
remove_input(emission_strength_in);
remove_input(alpha_in);
bool PrincipledBsdfNode::has_surface_emission()
{
ShaderInput *emission_in = input("Emission");
ShaderInput *emission_strength_in = input("Emission Strength");
return (emission_in->link != NULL || reduce_max(emission) > CLOSURE_WEIGHT_CUTOFF) &&
(emission_strength_in->link != NULL || emission_strength > CLOSURE_WEIGHT_CUTOFF);
}
bool PrincipledBsdfNode::has_surface_bssrdf()
@ -2781,6 +2754,9 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler)
ShaderInput *p_metallic = input("Metallic");
ShaderInput *p_subsurface = input("Subsurface");
ShaderInput *emission_strength_in = input("Emission Strength");
ShaderInput *alpha_in = input("Alpha");
float3 weight = one_float3();
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, weight);
@ -2806,6 +2782,9 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler)
int subsurface_scale_offset = compiler.stack_assign(input("Subsurface Scale"));
int subsurface_ior_offset = compiler.stack_assign(input("Subsurface IOR"));
int subsurface_anisotropy_offset = compiler.stack_assign(input("Subsurface Anisotropy"));
int alpha_offset = compiler.stack_assign_if_linked(alpha_in);
int emission_strength_offset = compiler.stack_assign_if_linked(emission_strength_in);
int emission_offset = compiler.stack_assign(input("Emission"));
compiler.add_node(NODE_CLOSURE_BSDF,
compiler.encode_uchar4(closure,
@ -2843,6 +2822,13 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler)
subsurface_radius_offset,
subsurface_scale_offset,
subsurface_anisotropy_offset);
compiler.add_node(
compiler.encode_uchar4(
alpha_offset, emission_strength_offset, emission_offset, SVM_STACK_INVALID),
__float_as_int(get_float(alpha_in->socket_type)),
__float_as_int(get_float(emission_strength_in->socket_type)),
SVM_STACK_INVALID);
}
void PrincipledBsdfNode::compile(OSLCompiler &compiler)

View File

@ -514,9 +514,9 @@ class PrincipledBsdfNode : public BsdfBaseNode {
public:
SHADER_NODE_CLASS(PrincipledBsdfNode)
void expand(ShaderGraph *graph);
bool has_surface_bssrdf();
bool has_bssrdf_bump();
void simplify_settings(Scene *scene);
NODE_SOCKET_API(float3, base_color)
NODE_SOCKET_API(float3, subsurface_radius)
@ -555,6 +555,8 @@ class PrincipledBsdfNode : public BsdfBaseNode {
{
return true;
}
bool has_surface_transparent();
bool has_surface_emission();
};
class TranslucentBsdfNode : public BsdfNode {

View File

@ -660,6 +660,33 @@ static void version_principled_bsdf_subsurface(bNodeTree *ntree)
}
}
/* Convert emission inputs on the Principled BSDF. */
static void version_principled_bsdf_emission(bNodeTree *ntree)
{
/* Blender 3.x and before would default to Emission = 0.0, Emission Strength = 1.0.
* Now we default the other way around (1.0 and 0.0), but because the Strength input was added
* a bit later, a file that only has the Emission socket would now end up as (1.0, 0.0) instead
* of (1.0, 1.0).
* Therefore, set strength to 1.0 for those files.
*/
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type != SH_NODE_BSDF_PRINCIPLED) {
continue;
}
if (!nodeFindSocket(node, SOCK_IN, "Emission")) {
/* Old enough to have neither, new defaults are fine. */
continue;
}
if (nodeFindSocket(node, SOCK_IN, "Emission Strength")) {
/* New enough to have both, no need to do anything. */
continue;
}
bNodeSocket *sock = nodeAddStaticSocket(
ntree, node, SOCK_IN, SOCK_FLOAT, PROP_NONE, "Emission Strength", "Emission Strength");
*version_cycles_node_socket_float_value(sock) = 1.0f;
}
}
/* Replace old Principled Hair BSDF as a variant in the new Principled Hair BSDF. */
static void version_replace_principled_hair_model(bNodeTree *ntree)
{
@ -1178,6 +1205,8 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
version_principled_bsdf_coat(ntree);
/* Convert subsurface inputs on the Principled BSDF. */
version_principled_bsdf_subsurface(ntree);
/* Convert emission on the Principled BSDF. */
version_principled_bsdf_emission(ntree);
}
}
FOREACH_NODETREE_END;

View File

@ -608,9 +608,12 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
for (bNode *node : ma->nodetree->all_nodes()) {
if (node->type == SH_NODE_BSDF_PRINCIPLED) {
bNodeSocket *roughness_socket = nodeFindSocket(node, SOCK_IN, "Roughness");
bNodeSocketValueFloat *roughness_data = static_cast<bNodeSocketValueFloat *>(
roughness_socket->default_value);
roughness_data->value = 0.5f;
*version_cycles_node_socket_float_value(roughness_socket) = 0.5f;
bNodeSocket *emission = nodeFindSocket(node, SOCK_IN, "Emission");
copy_v4_fl(version_cycles_node_socket_rgba_value(emission), 1.0f);
bNodeSocket *emission_strength = nodeFindSocket(node, SOCK_IN, "Emission Strength");
*version_cycles_node_socket_float_value(emission_strength) = 0.0f;
node->custom1 = SHD_GLOSSY_MULTI_GGX;
node->custom2 = SHD_SUBSURFACE_RANDOM_WALK;
BKE_ntree_update_tag_node_property(ma->nodetree, node);

View File

@ -143,9 +143,9 @@ static void node_declare(NodeDeclarationBuilder &b)
.max(1.0f)
.subtype(PROP_FACTOR);
#define SOCK_TRANSMISSION_ID 20
b.add_input<decl::Color>("Emission").default_value({0.0f, 0.0f, 0.0f, 1.0f});
b.add_input<decl::Color>("Emission").default_value({1.0f, 1.0f, 1.0f, 1.0f});
#define SOCK_EMISSION_ID 21
b.add_input<decl::Float>("Emission Strength").default_value(1.0).min(0.0f).max(1000000.0f);
b.add_input<decl::Float>("Emission Strength").default_value(0.0).min(0.0f).max(1000000.0f);
#define SOCK_EMISSION_STRENGTH_ID 22
b.add_input<decl::Float>("Alpha").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
#define SOCK_ALPHA_ID 23