36 if (done.find(
in->link->parent) == done.end()) {
73 :
Node(other.type), bump(other.bump), special_type(other.special_type)
96 if (socket->name() ==
name) {
107 if (socket->name() ==
name) {
118 if (socket->name() ==
name) {
129 if (socket->name() ==
name) {
185 if (input_a->
link ==
nullptr && input_b->
link ==
nullptr) {
191 else if (input_a->
link !=
nullptr && input_b->
link !=
nullptr) {
193 if (input_a->
link != input_b->
link) {
228 node->set_owner(
this);
244 fprintf(stderr,
"Cycles shader graph connect: input already connected.\n");
252 "Cycles shader graph connect: can only connect closure to closure "
253 "(%s.%s to %s.%s).\n",
254 from->parent->name.c_str(),
255 from->name().c_str(),
269 emission->set_strength(1.0f);
273 convert_in = convert->input(
"Strength");
276 convert_in = convert->input(
"Color");
281 convert_in = convert->inputs[0];
285 connect(convert->outputs[0], to);
387 if (surface_in->
link) {
390 if (volume_in->
link) {
403 if (
node !=
nullptr && dependencies.find(
node) == dependencies.end()) {
408 dependencies.insert(
node);
425 nnodemap[
node] = nnode;
456 bool any_node_removed =
false;
478 bool all_links_removed =
true;
486 all_links_removed =
false;
490 if (all_links_removed) {
491 removed[tonode->
id] =
true;
502 removed[proxy->
id] =
true;
503 any_node_removed =
true;
508 if (any_node_removed) {
511 for (
size_t i = 0; i <
nodes.
size(); i++) {
513 if (!removed[
node->id]) {
518 nodes = std::move(newnodes);
531 queue<ShaderNode *> traverse_queue;
533 const bool has_displacement = (
output()->
input(
"Displacement")->
link !=
nullptr);
537 if (!check_node_inputs_has_links(
node)) {
538 traverse_queue.push(
node);
539 scheduled.insert(
node);
543 while (!traverse_queue.empty()) {
545 traverse_queue.pop();
548 if (
output->links.empty()) {
555 if (scheduled.find(
input->parent) != scheduled.end()) {
562 if (check_node_inputs_traversed(
input->parent, done)) {
563 traverse_queue.push(
input->parent);
564 scheduled.insert(
input->parent);
569 node->constant_fold(folder);
577 if (has_displacement && !
output()->
input(
"Displacement")->link) {
607 map<ustring, ShaderNodeSet> candidates;
608 queue<ShaderNode *> traverse_queue;
609 int num_deduplicated = 0;
613 if (!check_node_inputs_has_links(
node)) {
614 traverse_queue.push(
node);
615 scheduled.insert(
node);
619 while (!traverse_queue.empty()) {
621 traverse_queue.pop();
624 bool has_output_links =
false;
627 has_output_links =
true;
628 if (scheduled.find(
input->parent) != scheduled.end()) {
635 if (check_node_inputs_traversed(
input->parent, done)) {
636 traverse_queue.push(
input->parent);
637 scheduled.insert(
input->parent);
642 if (!has_output_links) {
648 if (
node != other_node &&
node->equals(*other_node)) {
649 merge_with = other_node;
654 if (merge_with !=
nullptr) {
655 for (
int i = 0; i <
node->outputs.size(); ++i) {
661 candidates[
node->type->name].insert(
node);
665 if (num_deduplicated > 0) {
666 VLOG_DEBUG <<
"Deduplicated " << num_deduplicated <<
" nodes.";
677 if (volume_in->
link ==
nullptr) {
680 bool has_valid_volume =
false;
682 queue<ShaderNode *> traverse_queue;
687 while (!traverse_queue.empty()) {
689 traverse_queue.pop();
691 if (
node->has_volume_support()) {
692 has_valid_volume =
true;
696 if (
input->link ==
nullptr) {
699 if (scheduled.find(
input->link->parent) != scheduled.end()) {
702 traverse_queue.push(
input->link->parent);
703 scheduled.insert(
input->link->parent);
706 if (!has_valid_volume) {
707 VLOG_DEBUG <<
"Disconnect meaningless volume output.";
715 on_stack[
node->id] =
true;
721 if (on_stack[depnode->
id]) {
724 fprintf(stderr,
"Cycles shader graph: detected cycle in graph, connection removed.\n");
733 on_stack[
node->id] =
false;
742 if (!displacement_in->
link) {
754 int link_id = (
input->link) ?
input->link->parent->id : 0;
812 for (
size_t i = 0; i <
nodes.
size(); i++) {
819 nodes = std::move(newnodes);
827 for (
size_t i = 0; i <
nodes.
size(); i++) {
842 for (
size_t i = 0; i <
nodes.
size(); i++) {
872 if (!normal_transform) {
945 node->bump_filter_width = bump->get_filter_width();
947 for (
const NodePair &pair : nodes_dx) {
949 pair.second->bump_filter_width = bump->get_filter_width();
951 for (
const NodePair &pair : nodes_dy) {
953 pair.second->bump_filter_width = bump->get_filter_width();
991 if (!displacement_in->
link) {
1001 bump->set_use_object_space(use_object_space);
1002 bump->set_distance(1.0f);
1015 for (
const NodePair &pair : nodes_center) {
1017 pair.second->bump_filter_width = bump->get_filter_width();
1019 for (
const NodePair &pair : nodes_dx) {
1021 pair.second->bump_filter_width = bump->get_filter_width();
1023 for (
const NodePair &pair : nodes_dy) {
1025 pair.second->bump_filter_width = bump->get_filter_width();
1098 connect(weight_out, weight_in);
1101 weight1_out = mix_node->
output(
"Weight1");
1102 weight2_out = mix_node->
output(
"Weight2");
1106 weight1_out = weight_out;
1107 weight2_out = weight_out;
1118 ShaderInput *weight_in =
node->input((volume) ?
"VolumeMixWeight" :
"SurfaceMixWeight");
1127 if (weight_in->
link || weight_value != 0.0f) {
1130 if (weight_in->
link) {
1134 math_node->set_value1(weight_value);
1141 math_node->set_value2(1.0f);
1144 weight_out = math_node->
output(
"Value");
1145 if (weight_in->
link) {
1152 connect(weight_out, weight_in);
1162 int num_closures = 0;
1195 return num_closures;
1200 FILE *fd = fopen(filename,
"w");
1202 if (fd ==
nullptr) {
1203 printf(
"Error opening file for dumping the graph: %s\n", filename);
1207 fprintf(fd,
"digraph shader_graph {\n");
1208 fprintf(fd,
"ranksep=1.5\n");
1209 fprintf(fd,
"rankdir=LR\n");
1210 fprintf(fd,
"splines=false\n");
1213 fprintf(fd,
"// NODE: %p\n",
node);
1214 fprintf(fd,
"\"%p\" [shape=record,label=\"{",
node);
1215 if (!
node->inputs.empty()) {
1218 if (socket !=
node->inputs[0]) {
1221 fprintf(fd,
"<IN_%p>%s", socket, socket->name().c_str());
1225 fprintf(fd,
"%s",
node->name.c_str());
1227 fprintf(fd,
" (bump:center)");
1230 fprintf(fd,
" (bump:dx)");
1233 fprintf(fd,
" (bump:dy)");
1235 if (!
node->outputs.empty()) {
1238 if (socket !=
node->outputs[0]) {
1241 fprintf(fd,
"<OUT_%p>%s", socket, socket->name().c_str());
1245 fprintf(fd,
"}\"]");
1252 "// CONNECTION: OUT_%p->IN_%p (%s:%s)\n",
1256 input->name().c_str());
1258 "\"%p\":\"OUT_%p\":e -> \"%p\":\"IN_%p\":w [label=\"\"]\n",
@ NODE_VECTOR_MATH_DOT_PRODUCT
bool from_auto_conversion
void append(const uint8_t *data, const int nbytes)
void find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input)
unique_ptr_vector< ShaderNode > nodes
void verify_volume_output()
void simplify(Scene *scene)
T * create_node(Args &&...args)
void add_node(unique_ptr< ShaderNode > &&node)
void disconnect(ShaderOutput *from)
void break_cycles(ShaderNode *node, vector< bool > &visited, vector< bool > &on_stack)
void copy_nodes(ShaderNodeSet &nodes, ShaderNodeMap &nnodemap)
void finalize(Scene *scene, bool do_bump=false, bool bump_in_object_space=false)
void compute_displacement_hash()
void default_inputs(bool do_osl)
void connect(ShaderOutput *from, ShaderInput *to)
void relink(ShaderInput *from, ShaderInput *to)
void constant_fold(Scene *scene)
void transform_multi_closure(ShaderNode *node, ShaderOutput *weight_out, bool volume)
void remove_proxy_nodes()
void simplify_settings(Scene *scene)
void bump_from_displacement(bool use_object_space)
pair< ShaderNode *const, ShaderNode * > NodePair
void dump_graph(const char *filename)
ShaderInput * input(const char *name)
void remove_input(ShaderInput *input)
ShaderNodeSpecialType special_type
virtual ShaderNode * clone(ShaderGraph *graph) const =0
virtual bool equals(const ShaderNode &other)
ShaderNode(const NodeType *type)
void create_inputs_outputs(const NodeType *type)
unique_ptr_vector< ShaderInput > inputs
ShaderOutput * output(const char *name)
virtual void attributes(Shader *shader, AttributeRequestSet *attributes)
unique_ptr_vector< ShaderOutput > outputs
vector< ShaderInput * > links
bool has_surface_link() const
void push_back(unique_ptr< T > &&value)
void erase(const T *value)
unique_ptr< T > steal(const size_t i)
Set< ComponentNode * > visited
#define CCL_NAMESPACE_END
#define assert(assertion)
#define CLOSURE_IS_VOLUME(type)
@ NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT
@ NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD
#define CLOSURE_IS_PRINCIPLED(type)
@ CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID
@ CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID
@ CLOSURE_BSDF_PHYSICAL_CONDUCTOR
@ CLOSURE_BSDF_HAIR_HUANG_ID
@ CLOSURE_BSDF_F82_CONDUCTOR
@ CLOSURE_BSDF_HAIR_CHIANG_ID
#define CLOSURE_IS_BSSRDF(type)
@ NODE_VECTOR_TRANSFORM_TYPE_NORMAL
#define CLOSURE_IS_BSDF_MULTISCATTER(type)
#define MAX_VOLUME_STACK_SIZE
@ ATTR_STD_GENERATED_TRANSFORM
ccl_device_inline float3 one_float3()
bool check_node_inputs_traversed(const ShaderNode *node, const ShaderNodeSet &done)
bool check_node_inputs_has_links(const ShaderNode *node)
static blender::bke::bNodeSocketTemplate outputs[]
@ SHADER_SPECIAL_TYPE_PROXY
@ SHADER_SPECIAL_TYPE_OUTPUT_AOV
@ SHADER_SPECIAL_TYPE_COMBINE_CLOSURE
@ SHADER_SPECIAL_TYPE_BUMP
@ SHADER_SPECIAL_TYPE_AUTOCONVERT
@ SHADER_SPECIAL_TYPE_OSL
set< ShaderNode *, ShaderNodeIDComparator > ShaderNodeSet
map< ShaderNode *, ShaderNode *, ShaderNodeIDComparator > ShaderNodeMap
vector< SocketType, std::allocator< SocketType > > inputs
vector< SocketType, std::allocator< SocketType > > outputs
void copy_value(const SocketType &socket, const Node &other, const SocketType &other_socket)
bool equals_value(const Node &other, const SocketType &socket) const
unique_ptr< ShaderManager > shader_manager