Blender  V3.3
shader_graph.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2011-2022 Blender Foundation */
3 
4 #include "scene/shader_graph.h"
5 #include "scene/attribute.h"
6 #include "scene/constant_fold.h"
7 #include "scene/scene.h"
8 #include "scene/shader.h"
9 #include "scene/shader_nodes.h"
10 
11 #include "util/algorithm.h"
12 #include "util/foreach.h"
13 #include "util/log.h"
14 #include "util/md5.h"
15 #include "util/queue.h"
16 
18 
19 namespace {
20 
22 {
23  foreach (const ShaderInput *in, node->inputs) {
24  if (in->link) {
25  return true;
26  }
27  }
28  return false;
29 }
30 
32 {
33  foreach (const ShaderInput *in, node->inputs) {
34  if (in->link) {
35  if (done.find(in->link->parent) == done.end()) {
36  return false;
37  }
38  }
39  }
40  return true;
41 }
42 
43 } /* namespace */
44 
45 /* Sockets */
46 
48 {
49  if (link) {
50  link->links.erase(remove(link->links.begin(), link->links.end(), this), link->links.end());
51  }
52  link = NULL;
53 }
54 
56 {
57  foreach (ShaderInput *sock, links) {
58  sock->link = NULL;
59  }
60 
61  links.clear();
62 }
63 
64 /* Node */
65 
67 {
68  name = type->name;
69  id = -1;
72 
74 }
75 
77 {
78  foreach (ShaderInput *socket, inputs)
79  delete socket;
80 
81  foreach (ShaderOutput *socket, outputs)
82  delete socket;
83 }
84 
86 {
87  foreach (const SocketType &socket, type->inputs) {
88  if (socket.flags & SocketType::LINKABLE) {
89  inputs.push_back(new ShaderInput(socket, this));
90  }
91  }
92 
93  foreach (const SocketType &socket, type->outputs) {
94  outputs.push_back(new ShaderOutput(socket, this));
95  }
96 }
97 
98 ShaderInput *ShaderNode::input(const char *name)
99 {
100  foreach (ShaderInput *socket, inputs) {
101  if (socket->name() == name)
102  return socket;
103  }
104 
105  return NULL;
106 }
107 
109 {
110  foreach (ShaderOutput *socket, outputs)
111  if (socket->name() == name)
112  return socket;
113 
114  return NULL;
115 }
116 
118 {
119  foreach (ShaderInput *socket, inputs) {
120  if (socket->name() == name)
121  return socket;
122  }
123 
124  return NULL;
125 }
126 
128 {
129  foreach (ShaderOutput *socket, outputs)
130  if (socket->name() == name)
131  return socket;
132 
133  return NULL;
134 }
135 
137 {
138  assert(input->link == NULL);
139  delete input;
140  inputs.erase(remove(inputs.begin(), inputs.end(), input), inputs.end());
141 }
142 
144 {
145  foreach (ShaderInput *input, inputs) {
146  if (!input->link) {
148  if (shader->has_surface_link())
150  if (shader->has_volume)
152  }
153  else if (input->flags() & SocketType::LINK_TEXTURE_UV) {
154  if (shader->has_surface_link())
155  attributes->add(ATTR_STD_UV);
156  }
157  }
158  }
159 }
160 
161 bool ShaderNode::equals(const ShaderNode &other)
162 {
163  if (type != other.type || bump != other.bump) {
164  return false;
165  }
166 
167  assert(inputs.size() == other.inputs.size());
168 
169  /* Compare unlinkable sockets */
170  foreach (const SocketType &socket, type->inputs) {
171  if (!(socket.flags & SocketType::LINKABLE)) {
172  if (!Node::equals_value(other, socket)) {
173  return false;
174  }
175  }
176  }
177 
178  /* Compare linkable input sockets */
179  for (int i = 0; i < inputs.size(); ++i) {
180  ShaderInput *input_a = inputs[i], *input_b = other.inputs[i];
181  if (input_a->link == NULL && input_b->link == NULL) {
182  /* Unconnected inputs are expected to have the same value. */
183  if (!Node::equals_value(other, input_a->socket_type)) {
184  return false;
185  }
186  }
187  else if (input_a->link != NULL && input_b->link != NULL) {
188  /* Expect links are to come from the same exact socket. */
189  if (input_a->link != input_b->link) {
190  return false;
191  }
192  }
193  else {
194  /* One socket has a link and another has not, inputs can't be
195  * considered equal.
196  */
197  return false;
198  }
199  }
200 
201  return true;
202 }
203 
204 /* Graph */
205 
207 {
208  finalized = false;
209  simplified = false;
210  num_node_ids = 0;
211  add(create_node<OutputNode>());
212 }
213 
215 {
216  clear_nodes();
217 }
218 
220 {
221  assert(!finalized);
222  simplified = false;
223 
224  node->id = num_node_ids++;
225  nodes.push_back(node);
226  return node;
227 }
228 
230 {
231  return (OutputNode *)nodes.front();
232 }
233 
235 {
236  assert(!finalized);
237  assert(from && to);
238 
239  if (to->link) {
240  fprintf(stderr, "Cycles shader graph connect: input already connected.\n");
241  return;
242  }
243 
244  if (from->type() != to->type()) {
245  /* can't do automatic conversion from closure */
246  if (from->type() == SocketType::CLOSURE) {
247  fprintf(stderr,
248  "Cycles shader graph connect: can only connect closure to closure "
249  "(%s.%s to %s.%s).\n",
250  from->parent->name.c_str(),
251  from->name().c_str(),
252  to->parent->name.c_str(),
253  to->name().c_str());
254  return;
255  }
256 
257  /* add automatic conversion node in case of type mismatch */
259  ShaderInput *convert_in;
260 
261  if (to->type() == SocketType::CLOSURE) {
262  EmissionNode *emission = create_node<EmissionNode>();
263  emission->set_color(one_float3());
264  emission->set_strength(1.0f);
265  convert = add(emission);
266  /* Connect float inputs to Strength to save an additional Value->Color conversion. */
267  if (from->type() == SocketType::FLOAT) {
268  convert_in = convert->input("Strength");
269  }
270  else {
271  convert_in = convert->input("Color");
272  }
273  }
274  else {
275  convert = add(create_node<ConvertNode>(from->type(), to->type(), true));
276  convert_in = convert->inputs[0];
277  }
278 
279  connect(from, convert_in);
280  connect(convert->outputs[0], to);
281  }
282  else {
283  /* types match, just connect */
284  to->link = from;
285  from->links.push_back(to);
286  }
287 }
288 
290 {
291  assert(!finalized);
292  simplified = false;
293 
294  from->disconnect();
295 }
296 
298 {
299  assert(!finalized);
300  assert(to->link);
301  simplified = false;
302 
303  to->disconnect();
304 }
305 
307 {
308  ShaderOutput *out = from->link;
309  if (out) {
310  disconnect(from);
311  connect(out, to);
312  }
313  to->parent->copy_value(to->socket_type, *(from->parent), from->socket_type);
314 }
315 
317 {
318  /* Copy because disconnect modifies this list. */
320 
321  foreach (ShaderInput *sock, outputs) {
322  disconnect(sock);
323  if (to)
324  connect(to, sock);
325  }
326 }
327 
329 {
330  simplified = false;
331 
332  /* Copy because disconnect modifies this list */
334 
335  /* Bypass node by moving all links from "from" to "to" */
336  foreach (ShaderInput *sock, node->inputs) {
337  if (sock->link)
338  disconnect(sock);
339  }
340 
341  foreach (ShaderInput *sock, outputs) {
342  disconnect(sock);
343  if (to)
344  connect(to, sock);
345  }
346 }
347 
349 {
350  if (!simplified) {
351  expand();
353  clean(scene);
355 
356  simplified = true;
357  }
358 }
359 
360 void ShaderGraph::finalize(Scene *scene, bool do_bump, bool do_simplify, bool bump_in_object_space)
361 {
362  /* before compiling, the shader graph may undergo a number of modifications.
363  * currently we set default geometry shader inputs, and create automatic bump
364  * from displacement. a graph can be finalized only once, and should not be
365  * modified afterwards. */
366 
367  if (!finalized) {
368  simplify(scene);
369 
370  if (do_bump)
371  bump_from_displacement(bump_in_object_space);
372 
373  ShaderInput *surface_in = output()->input("Surface");
374  ShaderInput *volume_in = output()->input("Volume");
375 
376  /* todo: make this work when surface and volume closures are tangled up */
377 
378  if (surface_in->link)
379  transform_multi_closure(surface_in->link->parent, NULL, false);
380  if (volume_in->link)
381  transform_multi_closure(volume_in->link->parent, NULL, true);
382 
383  finalized = true;
384  }
385  else if (do_simplify) {
387  }
388 }
389 
391 {
392  /* find all nodes that this input depends on directly and indirectly */
393  ShaderNode *node = (input->link) ? input->link->parent : NULL;
394 
395  if (node != NULL && dependencies.find(node) == dependencies.end()) {
396  foreach (ShaderInput *in, node->inputs)
397  find_dependencies(dependencies, in);
398 
399  dependencies.insert(node);
400  }
401 }
402 
404 {
405  foreach (ShaderNode *node, nodes) {
406  delete_node(node);
407  }
408  nodes.clear();
409 }
410 
412 {
413  /* copy a set of nodes, and the links between them. the assumption is
414  * made that all nodes that inputs are linked to are in the set too. */
415 
416  /* copy nodes */
417  foreach (ShaderNode *node, nodes) {
418  ShaderNode *nnode = node->clone(this);
419  nnodemap[node] = nnode;
420 
421  /* create new inputs and outputs to recreate links and ensure
422  * that we still point to valid SocketType if the NodeType
423  * changed in cloning, as it does for OSL nodes */
424  nnode->inputs.clear();
425  nnode->outputs.clear();
426  nnode->create_inputs_outputs(nnode->type);
427  }
428 
429  /* recreate links */
430  foreach (ShaderNode *node, nodes) {
431  foreach (ShaderInput *input, node->inputs) {
432  if (input->link) {
433  /* find new input and output */
434  ShaderNode *nfrom = nnodemap[input->link->parent];
435  ShaderNode *nto = nnodemap[input->parent];
436  ShaderOutput *noutput = nfrom->output(input->link->name());
437  ShaderInput *ninput = nto->input(input->name());
438 
439  /* connect */
440  connect(noutput, ninput);
441  }
442  }
443  }
444 }
445 
446 /* Graph simplification */
447 /* ******************** */
448 
449 /* Remove proxy nodes.
450  *
451  * These only exists temporarily when exporting groups, and we must remove them
452  * early so that node->attributes() and default links do not see them.
453  */
455 {
456  vector<bool> removed(num_node_ids, false);
457  bool any_node_removed = false;
458 
459  foreach (ShaderNode *node, nodes) {
460  if (node->special_type == SHADER_SPECIAL_TYPE_PROXY) {
461  ConvertNode *proxy = static_cast<ConvertNode *>(node);
462  ShaderInput *input = proxy->inputs[0];
463  ShaderOutput *output = proxy->outputs[0];
464 
465  /* bypass the proxy node */
466  if (input->link) {
467  relink(proxy, output, input->link);
468  }
469  else {
470  /* Copy because disconnect modifies this list */
471  vector<ShaderInput *> links(output->links);
472 
473  foreach (ShaderInput *to, links) {
474  /* Remove any auto-convert nodes too if they lead to
475  * sockets with an automatically set default value. */
476  ShaderNode *tonode = to->parent;
477 
479  bool all_links_removed = true;
480  vector<ShaderInput *> links = tonode->outputs[0]->links;
481 
482  foreach (ShaderInput *autoin, links) {
483  if (autoin->flags() & SocketType::DEFAULT_LINK_MASK)
484  disconnect(autoin);
485  else
486  all_links_removed = false;
487  }
488 
489  if (all_links_removed)
490  removed[tonode->id] = true;
491  }
492 
493  disconnect(to);
494 
495  /* transfer the default input value to the target socket */
496  tonode->copy_value(to->socket_type, *proxy, input->socket_type);
497  }
498  }
499 
500  removed[proxy->id] = true;
501  any_node_removed = true;
502  }
503  }
504 
505  /* remove nodes */
506  if (any_node_removed) {
507  list<ShaderNode *> newnodes;
508 
509  foreach (ShaderNode *node, nodes) {
510  if (!removed[node->id])
511  newnodes.push_back(node);
512  else
513  delete_node(node);
514  }
515 
516  nodes = newnodes;
517  }
518 }
519 
520 /* Constant folding.
521  *
522  * Try to constant fold some nodes, and pipe result directly to
523  * the input socket of connected nodes.
524  */
526 {
527  ShaderNodeSet done, scheduled;
528  queue<ShaderNode *> traverse_queue;
529 
530  bool has_displacement = (output()->input("Displacement")->link != NULL);
531 
532  /* Schedule nodes which doesn't have any dependencies. */
533  foreach (ShaderNode *node, nodes) {
535  traverse_queue.push(node);
536  scheduled.insert(node);
537  }
538  }
539 
540  while (!traverse_queue.empty()) {
541  ShaderNode *node = traverse_queue.front();
542  traverse_queue.pop();
543  done.insert(node);
544  foreach (ShaderOutput *output, node->outputs) {
545  if (output->links.size() == 0) {
546  continue;
547  }
548  /* Schedule node which was depending on the value,
549  * when possible. Do it before disconnect.
550  */
551  foreach (ShaderInput *input, output->links) {
552  if (scheduled.find(input->parent) != scheduled.end()) {
553  /* Node might not be optimized yet but scheduled already
554  * by other dependencies. No need to re-schedule it.
555  */
556  continue;
557  }
558  /* Schedule node if its inputs are fully done. */
559  if (check_node_inputs_traversed(input->parent, done)) {
560  traverse_queue.push(input->parent);
561  scheduled.insert(input->parent);
562  }
563  }
564  /* Optimize current node. */
565  ConstantFolder folder(this, node, output, scene);
566  node->constant_fold(folder);
567  }
568  }
569 
570  /* Folding might have removed all nodes connected to the displacement output
571  * even tho there is displacement to be applied, so add in a value node if
572  * that happens to ensure there is still a valid graph for displacement.
573  */
574  if (has_displacement && !output()->input("Displacement")->link) {
575  ColorNode *value = (ColorNode *)add(create_node<ColorNode>());
576  value->set_value(output()->get_displacement());
577 
578  connect(value->output("Color"), output()->input("Displacement"));
579  }
580 }
581 
582 /* Simplification. */
584 {
585  foreach (ShaderNode *node, nodes) {
586  node->simplify_settings(scene);
587  }
588 }
589 
590 /* Deduplicate nodes with same settings. */
592 {
593  /* NOTES:
594  * - Deduplication happens for nodes which has same exact settings and same
595  * exact input links configuration (either connected to same output or has
596  * the same exact default value).
597  * - Deduplication happens in the bottom-top manner, so we know for fact that
598  * all traversed nodes are either can not be deduplicated at all or were
599  * already deduplicated.
600  */
601 
602  ShaderNodeSet scheduled, done;
603  map<ustring, ShaderNodeSet> candidates;
604  queue<ShaderNode *> traverse_queue;
605  int num_deduplicated = 0;
606 
607  /* Schedule nodes which doesn't have any dependencies. */
608  foreach (ShaderNode *node, nodes) {
610  traverse_queue.push(node);
611  scheduled.insert(node);
612  }
613  }
614 
615  while (!traverse_queue.empty()) {
616  ShaderNode *node = traverse_queue.front();
617  traverse_queue.pop();
618  done.insert(node);
619  /* Schedule the nodes which were depending on the current node. */
620  bool has_output_links = false;
621  foreach (ShaderOutput *output, node->outputs) {
622  foreach (ShaderInput *input, output->links) {
623  has_output_links = true;
624  if (scheduled.find(input->parent) != scheduled.end()) {
625  /* Node might not be optimized yet but scheduled already
626  * by other dependencies. No need to re-schedule it.
627  */
628  continue;
629  }
630  /* Schedule node if its inputs are fully done. */
631  if (check_node_inputs_traversed(input->parent, done)) {
632  traverse_queue.push(input->parent);
633  scheduled.insert(input->parent);
634  }
635  }
636  }
637  /* Only need to care about nodes that are actually used */
638  if (!has_output_links) {
639  continue;
640  }
641  /* Try to merge this node with another one. */
642  ShaderNode *merge_with = NULL;
643  foreach (ShaderNode *other_node, candidates[node->type->name]) {
644  if (node != other_node && node->equals(*other_node)) {
645  merge_with = other_node;
646  break;
647  }
648  }
649  /* If found an equivalent, merge; otherwise keep node for later merges */
650  if (merge_with != NULL) {
651  for (int i = 0; i < node->outputs.size(); ++i) {
652  relink(node, node->outputs[i], merge_with->outputs[i]);
653  }
654  num_deduplicated++;
655  }
656  else {
657  candidates[node->type->name].insert(node);
658  }
659  }
660 
661  if (num_deduplicated > 0) {
662  VLOG_DEBUG << "Deduplicated " << num_deduplicated << " nodes.";
663  }
664 }
665 
666 /* Check whether volume output has meaningful nodes, otherwise
667  * disconnect the output.
668  */
670 {
671  /* Check whether we can optimize the whole volume graph out. */
672  ShaderInput *volume_in = output()->input("Volume");
673  if (volume_in->link == NULL) {
674  return;
675  }
676  bool has_valid_volume = false;
677  ShaderNodeSet scheduled;
678  queue<ShaderNode *> traverse_queue;
679  /* Schedule volume output. */
680  traverse_queue.push(volume_in->link->parent);
681  scheduled.insert(volume_in->link->parent);
682  /* Traverse down the tree. */
683  while (!traverse_queue.empty()) {
684  ShaderNode *node = traverse_queue.front();
685  traverse_queue.pop();
686  /* Node is fully valid for volume, can't optimize anything out. */
687  if (node->has_volume_support()) {
688  has_valid_volume = true;
689  break;
690  }
691  foreach (ShaderInput *input, node->inputs) {
692  if (input->link == NULL) {
693  continue;
694  }
695  if (scheduled.find(input->link->parent) != scheduled.end()) {
696  continue;
697  }
698  traverse_queue.push(input->link->parent);
699  scheduled.insert(input->link->parent);
700  }
701  }
702  if (!has_valid_volume) {
703  VLOG_DEBUG << "Disconnect meaningless volume output.";
704  disconnect(volume_in->link);
705  }
706 }
707 
709 {
710  visited[node->id] = true;
711  on_stack[node->id] = true;
712 
713  foreach (ShaderInput *input, node->inputs) {
714  if (input->link) {
715  ShaderNode *depnode = input->link->parent;
716 
717  if (on_stack[depnode->id]) {
718  /* break cycle */
719  disconnect(input);
720  fprintf(stderr, "Cycles shader graph: detected cycle in graph, connection removed.\n");
721  }
722  else if (!visited[depnode->id]) {
723  /* visit dependencies */
724  break_cycles(depnode, visited, on_stack);
725  }
726  }
727  }
728 
729  on_stack[node->id] = false;
730 }
731 
733 {
734  /* Compute hash of all nodes linked to displacement, to detect if we need
735  * to recompute displacement when shader nodes change. */
736  ShaderInput *displacement_in = output()->input("Displacement");
737 
738  if (!displacement_in->link) {
739  displacement_hash = "";
740  return;
741  }
742 
743  ShaderNodeSet nodes_displace;
744  find_dependencies(nodes_displace, displacement_in);
745 
746  MD5Hash md5;
747  foreach (ShaderNode *node, nodes_displace) {
748  node->hash(md5);
749  foreach (ShaderInput *input, node->inputs) {
750  int link_id = (input->link) ? input->link->parent->id : 0;
751  md5.append((uint8_t *)&link_id, sizeof(link_id));
752  md5.append((input->link) ? input->link->name().c_str() : "");
753  }
754 
755  if (node->special_type == SHADER_SPECIAL_TYPE_OSL) {
756  /* Hash takes into account socket values, to detect changes
757  * in the code of the node we need an exception. */
758  OSLNode *oslnode = static_cast<OSLNode *>(node);
759  md5.append(oslnode->bytecode_hash);
760  }
761  }
762 
763  displacement_hash = md5.get_hex();
764 }
765 
767 {
768  /* Graph simplification */
769 
770  /* NOTE: Remove proxy nodes was already done. */
775 
776  /* we do two things here: find cycles and break them, and remove unused
777  * nodes that don't feed into the output. how cycles are broken is
778  * undefined, they are invalid input, the important thing is to not crash */
779 
781  vector<bool> on_stack(num_node_ids, false);
782 
783  /* break cycles */
784  break_cycles(output(), visited, on_stack);
785  foreach (ShaderNode *node, nodes) {
786  if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
787  break_cycles(node, visited, on_stack);
788  }
789  }
790 
791  /* disconnect unused nodes */
792  foreach (ShaderNode *node, nodes) {
793  if (!visited[node->id]) {
794  foreach (ShaderInput *to, node->inputs) {
795  ShaderOutput *from = to->link;
796 
797  if (from) {
798  to->link = NULL;
799  from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end());
800  }
801  }
802  }
803  }
804 
805  /* remove unused nodes */
806  list<ShaderNode *> newnodes;
807 
808  foreach (ShaderNode *node, nodes) {
809  if (visited[node->id])
810  newnodes.push_back(node);
811  else
812  delete_node(node);
813  }
814 
815  nodes = newnodes;
816 }
817 
819 {
820  /* Call expand on all nodes, to generate additional nodes. */
821  foreach (ShaderNode *node, nodes) {
822  node->expand(this);
823  }
824 }
825 
827 {
828  /* nodes can specify default texture coordinates, for now we give
829  * everything the position by default, except for the sky texture */
830 
831  ShaderNode *geom = NULL;
832  ShaderNode *texco = NULL;
833 
834  foreach (ShaderNode *node, nodes) {
835  foreach (ShaderInput *input, node->inputs) {
836  if (!input->link && (!(input->flags() & SocketType::OSL_INTERNAL) || do_osl)) {
837  if (input->flags() & SocketType::LINK_TEXTURE_GENERATED) {
838  if (!texco)
839  texco = create_node<TextureCoordinateNode>();
840 
841  connect(texco->output("Generated"), input);
842  }
843  if (input->flags() & SocketType::LINK_TEXTURE_NORMAL) {
844  if (!texco)
845  texco = create_node<TextureCoordinateNode>();
846 
847  connect(texco->output("Normal"), input);
848  }
849  else if (input->flags() & SocketType::LINK_TEXTURE_UV) {
850  if (!texco)
851  texco = create_node<TextureCoordinateNode>();
852 
853  connect(texco->output("UV"), input);
854  }
855  else if (input->flags() & SocketType::LINK_INCOMING) {
856  if (!geom)
857  geom = create_node<GeometryNode>();
858 
859  connect(geom->output("Incoming"), input);
860  }
861  else if (input->flags() & SocketType::LINK_NORMAL) {
862  if (!geom)
863  geom = create_node<GeometryNode>();
864 
865  connect(geom->output("Normal"), input);
866  }
867  else if (input->flags() & SocketType::LINK_POSITION) {
868  if (!geom)
869  geom = create_node<GeometryNode>();
870 
871  connect(geom->output("Position"), input);
872  }
873  else if (input->flags() & SocketType::LINK_TANGENT) {
874  if (!geom)
875  geom = create_node<GeometryNode>();
876 
877  connect(geom->output("Tangent"), input);
878  }
879  }
880  }
881  }
882 
883  if (geom)
884  add(geom);
885  if (texco)
886  add(texco);
887 }
888 
890 {
891  /* We transverse the node graph looking for bump nodes, when we find them,
892  * like in bump_from_displacement(), we copy the sub-graph defined from "bump"
893  * input to the inputs "center","dx" and "dy" What is in "bump" input is moved
894  * to "center" input. */
895 
896  foreach (ShaderNode *node, nodes) {
897  if (node->special_type == SHADER_SPECIAL_TYPE_BUMP && node->input("Height")->link) {
898  ShaderInput *bump_input = node->input("Height");
899  ShaderNodeSet nodes_bump;
900 
901  /* Make 2 extra copies of the subgraph defined in Bump input. */
902  ShaderNodeMap nodes_dx;
903  ShaderNodeMap nodes_dy;
904 
905  /* Find dependencies for the given input. */
906  find_dependencies(nodes_bump, bump_input);
907 
908  copy_nodes(nodes_bump, nodes_dx);
909  copy_nodes(nodes_bump, nodes_dy);
910 
911  /* Mark nodes to indicate they are use for bump computation, so
912  * that any texture coordinates are shifted by dx/dy when sampling. */
913  foreach (ShaderNode *node, nodes_bump)
914  node->bump = SHADER_BUMP_CENTER;
915  foreach (NodePair &pair, nodes_dx)
916  pair.second->bump = SHADER_BUMP_DX;
917  foreach (NodePair &pair, nodes_dy)
918  pair.second->bump = SHADER_BUMP_DY;
919 
920  ShaderOutput *out = bump_input->link;
921  ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name());
922  ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name());
923 
924  connect(out_dx, node->input("SampleX"));
925  connect(out_dy, node->input("SampleY"));
926 
927  /* Add generated nodes. */
928  foreach (NodePair &pair, nodes_dx)
929  add(pair.second);
930  foreach (NodePair &pair, nodes_dy)
931  add(pair.second);
932 
933  /* Connect what is connected is bump to sample-center input. */
934  connect(out, node->input("SampleCenter"));
935 
936  /* Bump input is just for connectivity purpose for the graph input,
937  * we re-connected this input to sample-center, so lets disconnect it
938  * from bump input. */
939  disconnect(bump_input);
940  }
941  }
942 }
943 
944 void ShaderGraph::bump_from_displacement(bool use_object_space)
945 {
946  /* generate bump mapping automatically from displacement. bump mapping is
947  * done using a 3-tap filter, computing the displacement at the center,
948  * and two other positions shifted by ray differentials.
949  *
950  * since the input to displacement is a node graph, we need to ensure that
951  * all texture coordinates use are shift by the ray differentials. for this
952  * reason we make 3 copies of the node subgraph defining the displacement,
953  * with each different geometry and texture coordinate nodes that generate
954  * different shifted coordinates.
955  *
956  * these 3 displacement values are then fed into the bump node, which will
957  * output the perturbed normal. */
958 
959  ShaderInput *displacement_in = output()->input("Displacement");
960 
961  if (!displacement_in->link)
962  return;
963 
964  /* find dependencies for the given input */
965  ShaderNodeSet nodes_displace;
966  find_dependencies(nodes_displace, displacement_in);
967 
968  /* copy nodes for 3 bump samples */
969  ShaderNodeMap nodes_center;
970  ShaderNodeMap nodes_dx;
971  ShaderNodeMap nodes_dy;
972 
973  copy_nodes(nodes_displace, nodes_center);
974  copy_nodes(nodes_displace, nodes_dx);
975  copy_nodes(nodes_displace, nodes_dy);
976 
977  /* mark nodes to indicate they are use for bump computation, so
978  * that any texture coordinates are shifted by dx/dy when sampling */
979  foreach (NodePair &pair, nodes_center)
980  pair.second->bump = SHADER_BUMP_CENTER;
981  foreach (NodePair &pair, nodes_dx)
982  pair.second->bump = SHADER_BUMP_DX;
983  foreach (NodePair &pair, nodes_dy)
984  pair.second->bump = SHADER_BUMP_DY;
985 
986  /* add set normal node and connect the bump normal output to the set normal
987  * output, so it can finally set the shader normal, note we are only doing
988  * this for bump from displacement, this will be the only bump allowed to
989  * overwrite the shader normal */
990  ShaderNode *set_normal = add(create_node<SetNormalNode>());
991 
992  /* add bump node and connect copied graphs to it */
993  BumpNode *bump = (BumpNode *)add(create_node<BumpNode>());
994  bump->set_use_object_space(use_object_space);
995  bump->set_distance(1.0f);
996 
997  ShaderOutput *out = displacement_in->link;
998  ShaderOutput *out_center = nodes_center[out->parent]->output(out->name());
999  ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name());
1000  ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name());
1001 
1002  /* convert displacement vector to height */
1003  VectorMathNode *dot_center = (VectorMathNode *)add(create_node<VectorMathNode>());
1004  VectorMathNode *dot_dx = (VectorMathNode *)add(create_node<VectorMathNode>());
1005  VectorMathNode *dot_dy = (VectorMathNode *)add(create_node<VectorMathNode>());
1006 
1007  dot_center->set_math_type(NODE_VECTOR_MATH_DOT_PRODUCT);
1008  dot_dx->set_math_type(NODE_VECTOR_MATH_DOT_PRODUCT);
1009  dot_dy->set_math_type(NODE_VECTOR_MATH_DOT_PRODUCT);
1010 
1011  GeometryNode *geom = (GeometryNode *)add(create_node<GeometryNode>());
1012  connect(geom->output("Normal"), dot_center->input("Vector2"));
1013  connect(geom->output("Normal"), dot_dx->input("Vector2"));
1014  connect(geom->output("Normal"), dot_dy->input("Vector2"));
1015 
1016  connect(out_center, dot_center->input("Vector1"));
1017  connect(out_dx, dot_dx->input("Vector1"));
1018  connect(out_dy, dot_dy->input("Vector1"));
1019 
1020  connect(dot_center->output("Value"), bump->input("SampleCenter"));
1021  connect(dot_dx->output("Value"), bump->input("SampleX"));
1022  connect(dot_dy->output("Value"), bump->input("SampleY"));
1023 
1024  /* connect the bump out to the set normal in: */
1025  connect(bump->output("Normal"), set_normal->input("Direction"));
1026 
1027  /* connect to output node */
1028  connect(set_normal->output("Normal"), output()->input("Normal"));
1029 
1030  /* finally, add the copied nodes to the graph. we can't do this earlier
1031  * because we would create dependency cycles in the above loop */
1032  foreach (NodePair &pair, nodes_center)
1033  add(pair.second);
1034  foreach (NodePair &pair, nodes_dx)
1035  add(pair.second);
1036  foreach (NodePair &pair, nodes_dy)
1037  add(pair.second);
1038 }
1039 
1041 {
1042  /* for SVM in multi closure mode, this transforms the shader mix/add part of
1043  * the graph into nodes that feed weights into closure nodes. this is too
1044  * avoid building a closure tree and then flattening it, and instead write it
1045  * directly to an array */
1046 
1047  if (node->special_type == SHADER_SPECIAL_TYPE_COMBINE_CLOSURE) {
1048  ShaderInput *fin = node->input("Fac");
1049  ShaderInput *cl1in = node->input("Closure1");
1050  ShaderInput *cl2in = node->input("Closure2");
1051  ShaderOutput *weight1_out, *weight2_out;
1052 
1053  if (fin) {
1054  /* mix closure: add node to mix closure weights */
1055  MixClosureWeightNode *mix_node = create_node<MixClosureWeightNode>();
1056  add(mix_node);
1057  ShaderInput *fac_in = mix_node->input("Fac");
1058  ShaderInput *weight_in = mix_node->input("Weight");
1059 
1060  if (fin->link)
1061  connect(fin->link, fac_in);
1062  else
1063  mix_node->set_fac(node->get_float(fin->socket_type));
1064 
1065  if (weight_out)
1066  connect(weight_out, weight_in);
1067 
1068  weight1_out = mix_node->output("Weight1");
1069  weight2_out = mix_node->output("Weight2");
1070  }
1071  else {
1072  /* add closure: just pass on any weights */
1073  weight1_out = weight_out;
1074  weight2_out = weight_out;
1075  }
1076 
1077  if (cl1in->link)
1078  transform_multi_closure(cl1in->link->parent, weight1_out, volume);
1079  if (cl2in->link)
1080  transform_multi_closure(cl2in->link->parent, weight2_out, volume);
1081  }
1082  else {
1083  ShaderInput *weight_in = node->input((volume) ? "VolumeMixWeight" : "SurfaceMixWeight");
1084 
1085  /* not a closure node? */
1086  if (!weight_in)
1087  return;
1088 
1089  /* already has a weight connected to it? add weights */
1090  float weight_value = node->get_float(weight_in->socket_type);
1091  if (weight_in->link || weight_value != 0.0f) {
1092  MathNode *math_node = create_node<MathNode>();
1093  add(math_node);
1094 
1095  if (weight_in->link)
1096  connect(weight_in->link, math_node->input("Value1"));
1097  else
1098  math_node->set_value1(weight_value);
1099 
1100  if (weight_out)
1101  connect(weight_out, math_node->input("Value2"));
1102  else
1103  math_node->set_value2(1.0f);
1104 
1105  weight_out = math_node->output("Value");
1106  if (weight_in->link)
1107  disconnect(weight_in);
1108  }
1109 
1110  /* connected to closure mix weight */
1111  if (weight_out)
1112  connect(weight_out, weight_in);
1113  else
1114  node->set(weight_in->socket_type, weight_value + 1.0f);
1115  }
1116 }
1117 
1119 {
1120  int num_closures = 0;
1121  foreach (ShaderNode *node, nodes) {
1122  ClosureType closure_type = node->get_closure_type();
1123  if (closure_type == CLOSURE_NONE_ID) {
1124  continue;
1125  }
1126  else if (CLOSURE_IS_BSSRDF(closure_type)) {
1127  num_closures += 3;
1128  }
1129  else if (CLOSURE_IS_GLASS(closure_type)) {
1130  num_closures += 2;
1131  }
1132  else if (CLOSURE_IS_BSDF_MULTISCATTER(closure_type)) {
1133  num_closures += 2;
1134  }
1135  else if (CLOSURE_IS_PRINCIPLED(closure_type)) {
1136  num_closures += 8;
1137  }
1138  else if (CLOSURE_IS_VOLUME(closure_type)) {
1139  /* TODO(sergey): Verify this is still needed, since we have special minimized volume storage
1140  * for the volume steps. */
1141  num_closures += MAX_VOLUME_STACK_SIZE;
1142  }
1143  else if (closure_type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) {
1144  num_closures += 4;
1145  }
1146  else {
1147  ++num_closures;
1148  }
1149  }
1150  return num_closures;
1151 }
1152 
1153 void ShaderGraph::dump_graph(const char *filename)
1154 {
1155  FILE *fd = fopen(filename, "w");
1156 
1157  if (fd == NULL) {
1158  printf("Error opening file for dumping the graph: %s\n", filename);
1159  return;
1160  }
1161 
1162  fprintf(fd, "digraph shader_graph {\n");
1163  fprintf(fd, "ranksep=1.5\n");
1164  fprintf(fd, "rankdir=LR\n");
1165  fprintf(fd, "splines=false\n");
1166 
1167  foreach (ShaderNode *node, nodes) {
1168  fprintf(fd, "// NODE: %p\n", node);
1169  fprintf(fd, "\"%p\" [shape=record,label=\"{", node);
1170  if (node->inputs.size()) {
1171  fprintf(fd, "{");
1172  foreach (ShaderInput *socket, node->inputs) {
1173  if (socket != node->inputs[0]) {
1174  fprintf(fd, "|");
1175  }
1176  fprintf(fd, "<IN_%p>%s", socket, socket->name().c_str());
1177  }
1178  fprintf(fd, "}|");
1179  }
1180  fprintf(fd, "%s", node->name.c_str());
1181  if (node->bump == SHADER_BUMP_CENTER) {
1182  fprintf(fd, " (bump:center)");
1183  }
1184  else if (node->bump == SHADER_BUMP_DX) {
1185  fprintf(fd, " (bump:dx)");
1186  }
1187  else if (node->bump == SHADER_BUMP_DY) {
1188  fprintf(fd, " (bump:dy)");
1189  }
1190  if (node->outputs.size()) {
1191  fprintf(fd, "|{");
1192  foreach (ShaderOutput *socket, node->outputs) {
1193  if (socket != node->outputs[0]) {
1194  fprintf(fd, "|");
1195  }
1196  fprintf(fd, "<OUT_%p>%s", socket, socket->name().c_str());
1197  }
1198  fprintf(fd, "}");
1199  }
1200  fprintf(fd, "}\"]");
1201  }
1202 
1203  foreach (ShaderNode *node, nodes) {
1204  foreach (ShaderOutput *output, node->outputs) {
1205  foreach (ShaderInput *input, output->links) {
1206  fprintf(fd,
1207  "// CONNECTION: OUT_%p->IN_%p (%s:%s)\n",
1208  output,
1209  input,
1210  output->name().c_str(),
1211  input->name().c_str());
1212  fprintf(fd,
1213  "\"%p\":\"OUT_%p\":e -> \"%p\":\"IN_%p\":w [label=\"\"]\n",
1214  output->parent,
1215  output,
1216  input->parent,
1217  input);
1218  }
1219  }
1220  }
1221 
1222  fprintf(fd, "}\n");
1223  fclose(fd);
1224 }
1225 
@ NODE_VECTOR_MATH_DOT_PRODUCT
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Definition: md5.h:20
string get_hex()
Definition: md5.cpp:348
void append(const uint8_t *data, int size)
Definition: md5.cpp:256
string bytecode_hash
void find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input)
string displacement_hash
Definition: shader_graph.h:303
list< ShaderNode * > nodes
Definition: shader_graph.h:299
OutputNode * output()
void verify_volume_output()
void simplify(Scene *scene)
void disconnect(ShaderOutput *from)
void delete_node(T *node)
Definition: shader_graph.h:342
size_t num_node_ids
Definition: shader_graph.h:300
void break_cycles(ShaderNode *node, vector< bool > &visited, vector< bool > &on_stack)
void copy_nodes(ShaderNodeSet &nodes, ShaderNodeMap &nnodemap)
void clean(Scene *scene)
pair< ShaderNode *const, ShaderNode * > NodePair
Definition: shader_graph.h:349
void compute_displacement_hash()
void default_inputs(bool do_osl)
void connect(ShaderOutput *from, ShaderInput *to)
void relink(ShaderInput *from, ShaderInput *to)
void clear_nodes()
void constant_fold(Scene *scene)
void transform_multi_closure(ShaderNode *node, ShaderOutput *weight_out, bool volume)
void deduplicate_nodes()
void remove_proxy_nodes()
void simplify_settings(Scene *scene)
void bump_from_displacement(bool use_object_space)
int get_num_closures()
void finalize(Scene *scene, bool do_bump=false, bool do_simplify=false, bool bump_in_object_space=false)
ShaderNode * add(ShaderNode *node)
void refine_bump_nodes()
void dump_graph(const char *filename)
ShaderOutput * link
Definition: shader_graph.h:103
void disconnect()
ShaderNode * parent
Definition: shader_graph.h:102
SocketType::Type type()
Definition: shader_graph.h:85
ustring name()
Definition: shader_graph.h:77
const SocketType & socket_type
Definition: shader_graph.h:101
virtual bool use_osl()
Definition: scene/shader.h:178
ShaderInput * input(const char *name)
vector< ShaderOutput * > outputs
Definition: shader_graph.h:215
void remove_input(ShaderInput *input)
ShaderNodeSpecialType special_type
Definition: shader_graph.h:220
vector< ShaderInput * > inputs
Definition: shader_graph.h:214
virtual ~ShaderNode()
virtual bool equals(const ShaderNode &other)
ShaderNode(const NodeType *type)
void create_inputs_outputs(const NodeType *type)
ShaderBump bump
Definition: shader_graph.h:218
ShaderOutput * output(const char *name)
virtual void attributes(Shader *shader, AttributeRequestSet *attributes)
ustring name()
Definition: shader_graph.h:122
vector< ShaderInput * > links
Definition: shader_graph.h:135
void disconnect()
ShaderNode * parent
Definition: shader_graph.h:134
bool has_surface_link() const
Definition: scene/shader.h:147
bool has_volume
Definition: scene/shader.h:107
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
OperationNode * node
StackEntry * from
Scene scene
Set< ComponentNode * > visited
ccl_global KernelShaderEvalInput * input
#define CLOSURE_IS_GLASS(type)
#define CLOSURE_IS_VOLUME(type)
#define CLOSURE_IS_PRINCIPLED(type)
ClosureType
@ CLOSURE_BSDF_HAIR_PRINCIPLED_ID
@ CLOSURE_NONE_ID
#define CLOSURE_IS_BSSRDF(type)
#define CLOSURE_IS_BSDF_MULTISCATTER(type)
#define MAX_VOLUME_STACK_SIZE
Definition: kernel/types.h:692
@ ATTR_STD_GENERATED_TRANSFORM
Definition: kernel/types.h:621
@ ATTR_STD_UV
Definition: kernel/types.h:616
@ ATTR_STD_GENERATED
Definition: kernel/types.h:620
#define VLOG_DEBUG
Definition: log.h:86
ccl_device_inline float3 one_float3()
Definition: math_float3.h:89
bool check_node_inputs_traversed(const ShaderNode *node, const ShaderNodeSet &done)
bool check_node_inputs_has_links(const ShaderNode *node)
uint convert(uint c, uint inbits, uint outbits)
Definition: PixelFormat.h:45
bool remove(void *owner, const AttributeIDRef &attribute_id)
struct blender::gpu::ShaderInput ShaderInput
static const pxr::TfToken out("out", pxr::TfToken::Immortal)
static bNodeSocketTemplate outputs[]
@ SHADER_SPECIAL_TYPE_PROXY
Definition: shader_graph.h:48
@ SHADER_SPECIAL_TYPE_OUTPUT_AOV
Definition: shader_graph.h:57
@ SHADER_SPECIAL_TYPE_COMBINE_CLOSURE
Definition: shader_graph.h:54
@ SHADER_SPECIAL_TYPE_BUMP
Definition: shader_graph.h:56
@ SHADER_SPECIAL_TYPE_AUTOCONVERT
Definition: shader_graph.h:49
@ SHADER_SPECIAL_TYPE_NONE
Definition: shader_graph.h:47
@ SHADER_SPECIAL_TYPE_OSL
Definition: shader_graph.h:51
set< ShaderNode *, ShaderNodeIDComparator > ShaderNodeSet
Definition: shader_graph.h:289
@ SHADER_BUMP_CENTER
Definition: shader_graph.h:39
@ SHADER_BUMP_DX
Definition: shader_graph.h:39
@ SHADER_BUMP_DY
Definition: shader_graph.h:39
@ SHADER_BUMP_NONE
Definition: shader_graph.h:39
map< ShaderNode *, ShaderNode *, ShaderNodeIDComparator > ShaderNodeMap
Definition: shader_graph.h:290
unsigned char uint8_t
Definition: stdint.h:78
vector< SocketType, std::allocator< SocketType > > inputs
Definition: node_type.h:118
ustring name
Definition: node_type.h:115
vector< SocketType, std::allocator< SocketType > > outputs
Definition: node_type.h:119
const NodeType * type
Definition: graph/node.h:175
void set_value(const SocketType &input, const Node &other, const SocketType &other_input)
Definition: graph/node.cpp:388
void copy_value(const SocketType &input, const Node &other, const SocketType &other_input)
Definition: graph/node.cpp:321
ustring name
Definition: graph/node.h:174
bool equals_value(const Node &other, const SocketType &input) const
Definition: graph/node.cpp:485
ShaderManager * shader_manager
Definition: scene.h:224
@ LINK_TEXTURE_UV
Definition: node_type.h:64
@ LINK_NORMAL
Definition: node_type.h:66
@ LINK_TEXTURE_GENERATED
Definition: node_type.h:62
@ OSL_INTERNAL
Definition: node_type.h:59
@ LINK_TANGENT
Definition: node_type.h:68
@ LINK_INCOMING
Definition: node_type.h:65
@ LINK_TEXTURE_NORMAL
Definition: node_type.h:63
@ DEFAULT_LINK_MASK
Definition: node_type.h:69
@ LINK_POSITION
Definition: node_type.h:67
int flags
Definition: node_type.h:78