36 if (done.find(in->link->parent) == done.end()) {
88 foreach (
const SocketType &socket, type->inputs) {
94 foreach (
const SocketType &socket, type->outputs) {
102 if (socket->
name() == name) {
113 if (socket->
name() == name) {
123 if (socket->
name() == name) {
134 if (socket->
name() == name) {
143 assert(input->link ==
NULL);
145 inputs.erase(remove(inputs.begin(), inputs.end(), input), inputs.end());
153 if (shader->has_surface_link()) {
156 if (shader->has_volume) {
161 if (shader->has_surface_link()) {
171 if (type != other.type ||
bump != other.bump) {
175 assert(inputs.size() == other.inputs.size());
178 foreach (
const SocketType &socket, type->inputs) {
187 for (
int i = 0; i < inputs.size(); ++i) {
188 ShaderInput *input_a = inputs[i], *input_b = other.inputs[i];
195 else if (input_a->
link !=
NULL && input_b->link !=
NULL) {
197 if (input_a->
link != input_b->link) {
233 nodes.push_back(node);
248 fprintf(stderr,
"Cycles shader graph connect: input already connected.\n");
252 if (from->type() != to->type()) {
256 "Cycles shader graph connect: can only connect closure to closure "
257 "(%s.%s to %s.%s).\n",
258 from->parent->name.c_str(),
259 from->name().c_str(),
260 to->parent->name.c_str(),
271 emission->from_auto_conversion =
true;
273 emission->set_strength(1.0f);
274 convert =
add(emission);
277 convert_in = convert->input(
"Strength");
280 convert_in = convert->input(
"Color");
285 convert_in = convert->inputs[0];
289 connect(convert->outputs[0], to);
294 from->links.push_back(to);
322 to->parent->copy_value(to->socket_type, *(from->parent), from->socket_type);
391 if (surface_in->
link) {
394 if (volume_in->
link) {
407 if (node !=
NULL && dependencies.find(node) == dependencies.end()) {
411 dependencies.insert(node);
431 nnodemap[
node] = nnode;
446 ShaderNode *nfrom = nnodemap[input->link->parent];
469 bool any_node_removed =
false;
479 relink(proxy, output, input->link);
491 bool all_links_removed =
true;
499 all_links_removed =
false;
503 if (all_links_removed) {
504 removed[tonode->
id] =
true;
511 tonode->
copy_value(to->socket_type, *proxy, input->socket_type);
515 removed[proxy->
id] =
true;
516 any_node_removed =
true;
521 if (any_node_removed) {
522 list<ShaderNode *> newnodes;
525 if (!removed[node->id]) {
526 newnodes.push_back(node);
545 queue<ShaderNode *> traverse_queue;
551 if (!check_node_inputs_has_links(node)) {
552 traverse_queue.push(node);
553 scheduled.insert(node);
557 while (!traverse_queue.empty()) {
559 traverse_queue.pop();
562 if (output->links.size() == 0) {
569 if (scheduled.find(input->parent) != scheduled.end()) {
576 if (check_node_inputs_traversed(input->parent, done)) {
577 traverse_queue.push(input->parent);
578 scheduled.insert(input->parent);
583 node->constant_fold(folder);
591 if (has_displacement && !
output()->input(
"Displacement")->link) {
595 connect(value->output(
"Color"), output()->input(
"Displacement"));
603 node->simplify_settings(scene);
620 map<ustring, ShaderNodeSet> candidates;
621 queue<ShaderNode *> traverse_queue;
622 int num_deduplicated = 0;
626 if (!check_node_inputs_has_links(node)) {
627 traverse_queue.push(node);
628 scheduled.insert(node);
632 while (!traverse_queue.empty()) {
634 traverse_queue.pop();
637 bool has_output_links =
false;
640 has_output_links =
true;
641 if (scheduled.find(input->parent) != scheduled.end()) {
648 if (check_node_inputs_traversed(input->parent, done)) {
649 traverse_queue.push(input->parent);
650 scheduled.insert(input->parent);
655 if (!has_output_links) {
660 foreach (
ShaderNode *other_node, candidates[node->type->name]) {
661 if (node != other_node && node->
equals(*other_node)) {
662 merge_with = other_node;
667 if (merge_with !=
NULL) {
668 for (
int i = 0; i < node->outputs.size(); ++i) {
674 candidates[node->type->name].insert(node);
678 if (num_deduplicated > 0) {
679 VLOG_DEBUG <<
"Deduplicated " << num_deduplicated <<
" nodes.";
693 bool has_valid_volume =
false;
695 queue<ShaderNode *> traverse_queue;
700 while (!traverse_queue.empty()) {
702 traverse_queue.pop();
704 if (node->has_volume_support()) {
705 has_valid_volume =
true;
709 if (input->link ==
NULL) {
712 if (scheduled.find(input->link->parent) != scheduled.end()) {
715 traverse_queue.push(input->link->parent);
716 scheduled.insert(input->link->parent);
719 if (!has_valid_volume) {
720 VLOG_DEBUG <<
"Disconnect meaningless volume output.";
728 on_stack[node->id] =
true;
734 if (on_stack[depnode->
id]) {
737 fprintf(stderr,
"Cycles shader graph: detected cycle in graph, connection removed.\n");
746 on_stack[node->id] =
false;
755 if (!displacement_in->
link) {
767 int link_id = (input->link) ? input->link->parent->id : 0;
769 md5.
append((input->link) ? input->link->name().c_str() :
"");
816 from->
links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end());
823 list<ShaderNode *> newnodes;
827 newnodes.push_back(node);
882 if (!normal_transform) {
930 if (normal_transform) {
931 add(normal_transform);
967 ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name());
968 ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name());
970 connect(out_dx, node->input(
"SampleX"));
971 connect(out_dy, node->input(
"SampleY"));
980 connect(out, node->input(
"SampleCenter"));
1007 if (!displacement_in->
link) {
1026 foreach (
NodePair &pair, nodes_center)
1041 bump->set_use_object_space(use_object_space);
1042 bump->set_distance(1.0f);
1045 ShaderOutput *out_center = nodes_center[out->parent]->output(out->name());
1046 ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name());
1047 ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name());
1076 connect(set_normal->
output(
"Normal"), output()->input(
"Normal"));
1080 foreach (
NodePair &pair, nodes_center)
1112 mix_node->set_fac(node->get_float(fin->
socket_type));
1116 connect(weight_out, weight_in);
1119 weight1_out = mix_node->
output(
"Weight1");
1120 weight2_out = mix_node->
output(
"Weight2");
1124 weight1_out = weight_out;
1125 weight2_out = weight_out;
1136 ShaderInput *weight_in = node->input((volume) ?
"VolumeMixWeight" :
"SurfaceMixWeight");
1144 float weight_value = node->get_float(weight_in->
socket_type);
1145 if (weight_in->
link || weight_value != 0.0f) {
1149 if (weight_in->
link) {
1153 math_node->set_value1(weight_value);
1160 math_node->set_value2(1.0f);
1163 weight_out = math_node->
output(
"Value");
1164 if (weight_in->
link) {
1171 connect(weight_out, weight_in);
1174 node->set(weight_in->
socket_type, weight_value + 1.0f);
1181 int num_closures = 0;
1183 ClosureType closure_type = node->get_closure_type();
1214 return num_closures;
1219 FILE *fd = fopen(filename,
"w");
1222 printf(
"Error opening file for dumping the graph: %s\n", filename);
1226 fprintf(fd,
"digraph shader_graph {\n");
1227 fprintf(fd,
"ranksep=1.5\n");
1228 fprintf(fd,
"rankdir=LR\n");
1229 fprintf(fd,
"splines=false\n");
1232 fprintf(fd,
"// NODE: %p\n", node);
1233 fprintf(fd,
"\"%p\" [shape=record,label=\"{", node);
1234 if (node->inputs.size()) {
1237 if (socket != node->inputs[0]) {
1240 fprintf(fd,
"<IN_%p>%s", socket, socket->
name().c_str());
1244 fprintf(fd,
"%s", node->name.c_str());
1246 fprintf(fd,
" (bump:center)");
1249 fprintf(fd,
" (bump:dx)");
1252 fprintf(fd,
" (bump:dy)");
1254 if (node->outputs.size()) {
1257 if (socket != node->outputs[0]) {
1260 fprintf(fd,
"<OUT_%p>%s", socket, socket->
name().c_str());
1264 fprintf(fd,
"}\"]");
1271 "// CONNECTION: OUT_%p->IN_%p (%s:%s)\n",
1274 output->name().c_str(),
1275 input->name().c_str());
1277 "\"%p\":\"OUT_%p\":e -> \"%p\":\"IN_%p\":w [label=\"\"]\n",
@ NODE_VECTOR_MATH_DOT_PRODUCT
void append(const uint8_t *data, int size)
void find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input)
void verify_volume_output()
void simplify(Scene *scene)
T * create_node(Args &&...args)
void disconnect(ShaderOutput *from)
void delete_node(T *node)
void break_cycles(ShaderNode *node, vector< bool > &visited, vector< bool > &on_stack)
void copy_nodes(ShaderNodeSet &nodes, ShaderNodeMap &nnodemap)
pair< ShaderNode *const, ShaderNode * > NodePair
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)
ShaderNode * add(ShaderNode *node)
void dump_graph(const char *filename)
ShaderInput * input(const char *name)
vector< ShaderOutput * > outputs
void remove_input(ShaderInput *input)
ShaderNodeSpecialType special_type
vector< ShaderInput * > inputs
virtual ShaderNode * clone(ShaderGraph *graph) const =0
virtual bool equals(const ShaderNode &other)
ShaderNode(const NodeType *type)
void create_inputs_outputs(const NodeType *type)
ShaderOutput * output(const char *name)
virtual void attributes(Shader *shader, AttributeRequestSet *attributes)
vector< ShaderInput * > links
Set< ComponentNode * > visited
#define CCL_NAMESPACE_END
#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)
@ 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_NONE
@ SHADER_SPECIAL_TYPE_OSL
set< ShaderNode *, ShaderNodeIDComparator > ShaderNodeSet
map< ShaderNode *, ShaderNode *, ShaderNodeIDComparator > ShaderNodeMap
void set_value(const SocketType &input, const Node &other, const SocketType &other_input)
void copy_value(const SocketType &input, const Node &other, const SocketType &other_input)
bool equals_value(const Node &other, const SocketType &input) const