36 if (done.find(
in->link->parent) == done.end()) {
51 link->links.erase(remove(
link->links.begin(),
link->links.end(),
this),
link->links.end());
84 inputs.push_back(make_unique<ShaderInput>(socket,
this));
89 outputs.push_back(make_unique<ShaderOutput>(socket,
this));
96 if (socket->name() ==
name) {
107 if (socket->name() ==
name) {
118 if (socket->name() ==
name) {
129 if (socket->name() ==
name) {
140 if (socket && socket->
link) {
190 for (
int i = 0;
i <
inputs.size(); ++
i) {
193 if (input_a->
link ==
nullptr && input_b->
link ==
nullptr) {
199 else if (input_a->
link !=
nullptr && input_b->
link !=
nullptr) {
201 if (input_a->
link != input_b->
link) {
236 node->set_owner(
this);
238 nodes.push_back(std::move(node));
252 LOG_WARNING <<
"Graph connect: input already connected.";
259 LOG_WARNING <<
"Shader graph connect: can only connect closure to closure ("
260 << from->
parent->
name.c_str() <<
"." << from->
name().c_str() <<
" to "
273 emission->set_strength(1.0f);
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);
391 if (surface_in->
link) {
394 if (volume_in->
link) {
407 if (node !=
nullptr && dependencies.find(node) == dependencies.end()) {
412 dependencies.insert(node);
429 nnodemap[node] = nnode;
460 bool any_node_removed =
false;
482 bool all_links_removed =
true;
490 all_links_removed =
false;
494 if (all_links_removed) {
495 removed[tonode->
id] =
true;
506 removed[proxy->
id] =
true;
507 any_node_removed =
true;
512 if (any_node_removed) {
515 for (
size_t i = 0;
i <
nodes.size();
i++) {
517 if (!removed[node->id]) {
522 nodes = std::move(newnodes);
535 queue<ShaderNode *> traverse_queue;
537 const bool has_displacement = (
output()->
input(
"Displacement")->
link !=
nullptr);
541 if (!check_node_inputs_has_links(node)) {
542 traverse_queue.push(node);
543 scheduled.insert(node);
547 while (!traverse_queue.empty()) {
549 traverse_queue.pop();
552 if (
output->links.empty()) {
559 if (scheduled.find(
input->parent) != scheduled.end()) {
566 if (check_node_inputs_traversed(
input->parent, done)) {
567 traverse_queue.push(
input->parent);
568 scheduled.insert(
input->parent);
581 if (has_displacement && !
output()->
input(
"Displacement")->link) {
593 node->simplify_settings(scene);
611 map<ustring, ShaderNodeSet> candidates;
612 queue<ShaderNode *> traverse_queue;
613 int num_deduplicated = 0;
617 if (!check_node_inputs_has_links(node)) {
618 traverse_queue.push(node);
619 scheduled.insert(node);
623 while (!traverse_queue.empty()) {
625 traverse_queue.pop();
628 bool has_output_links =
false;
631 has_output_links =
true;
632 if (scheduled.find(
input->parent) != scheduled.end()) {
639 if (check_node_inputs_traversed(
input->parent, done)) {
640 traverse_queue.push(
input->parent);
641 scheduled.insert(
input->parent);
646 if (!has_output_links) {
652 if (node != other_node && node->
equals(*other_node)) {
653 merge_with = other_node;
658 if (merge_with !=
nullptr) {
665 candidates[node->
type->
name].insert(node);
669 if (num_deduplicated > 0) {
670 LOG_TRACE <<
"Deduplicated " << num_deduplicated <<
" nodes.";
680 if (volume_in->
link ==
nullptr) {
684 bool has_valid_volume =
false;
686 using ShaderNodeAndNonLinear = std::pair<ShaderNode *, bool>;
687 set<ShaderNodeAndNonLinear, ShaderNodeIDAndBoolComparator> scheduled;
688 queue<ShaderNodeAndNonLinear> traverse_queue;
691 traverse_queue.emplace(volume_in->
link->
parent,
false);
692 scheduled.insert({volume_in->
link->
parent,
false});
695 while (!traverse_queue.empty()) {
696 auto [node, nonlinear] = traverse_queue.front();
697 traverse_queue.pop();
701 if (nonlinear && node->type == AttributeNode::get_node_type()) {
702 static_cast<AttributeNode *
>(node)->stochastic_sample =
false;
704 nonlinear = nonlinear || !node->is_linear_operation();
707 if (node->has_volume_support()) {
708 has_valid_volume =
true;
712 if (
input->link ==
nullptr) {
716 if (scheduled.find({input_node, nonlinear}) != scheduled.end()) {
719 traverse_queue.emplace(input_node, nonlinear);
720 scheduled.insert({input_node, nonlinear});
726 if (node->type == AttributeNode::get_node_type() &&
729 LOG_TRACE <<
"Volume attribute node " << node->name <<
" uses stochastic sampling";
734 if (!has_valid_volume) {
736 LOG_TRACE <<
"Disconnect meaningless volume output.";
743 visited[node->
id] =
true;
744 on_stack[node->
id] =
true;
750 if (on_stack[depnode->
id]) {
753 LOG_WARNING <<
"Shader graph: detected cycle in graph, connection removed.";
755 else if (!visited[depnode->
id]) {
762 on_stack[node->
id] =
false;
771 if (!displacement_in->
link) {
783 int link_id = (
input->link) ?
input->link->parent->id : 0;
784 md5.
append((uint8_t *)&link_id,
sizeof(link_id));
826 if (!visited[node->id]) {
841 for (
size_t i = 0;
i <
nodes.size();
i++) {
843 if (visited[node->id]) {
848 nodes = std::move(newnodes);
856 for (
size_t i = 0;
i <
nodes.size();
i++) {
871 for (
size_t i = 0;
i <
nodes.size();
i++) {
901 if (!normal_transform) {
952 for (
int i = 0;
i <
nodes.size();
i++) {
976 for (
const NodePair &pair : nodes_dx) {
978 pair.second->bump_filter_width = bump->get_filter_width();
980 for (
const NodePair &pair : nodes_dy) {
982 pair.second->bump_filter_width = bump->get_filter_width();
1020 if (!displacement_in->
link) {
1030 bump->set_use_object_space(use_object_space);
1031 bump->set_distance(1.0f);
1044 for (
const NodePair &pair : nodes_center) {
1046 pair.second->bump_filter_width = bump->get_filter_width();
1048 for (
const NodePair &pair : nodes_dx) {
1050 pair.second->bump_filter_width = bump->get_filter_width();
1052 for (
const NodePair &pair : nodes_dy) {
1054 pair.second->bump_filter_width = bump->get_filter_width();
1127 connect(weight_out, weight_in);
1130 weight1_out = mix_node->
output(
"Weight1");
1131 weight2_out = mix_node->
output(
"Weight2");
1135 weight1_out = weight_out;
1136 weight2_out = weight_out;
1147 ShaderInput *weight_in = node->
input((volume) ?
"VolumeMixWeight" :
"SurfaceMixWeight");
1156 if (weight_in->
link || weight_value != 0.0f) {
1159 if (weight_in->
link) {
1163 math_node->set_value1(weight_value);
1170 math_node->set_value2(1.0f);
1173 weight_out = math_node->
output(
"Value");
1174 if (weight_in->
link) {
1181 connect(weight_out, weight_in);
1191 int num_closures = 0;
1193 const ClosureType closure_type = node->get_closure_type();
1224 return num_closures;
1229 FILE *fd = fopen(filename,
"w");
1231 if (fd ==
nullptr) {
1232 LOG_ERROR <<
"Error opening file for dumping the graph: " << filename;
1236 fprintf(fd,
"digraph shader_graph {\n");
1237 fprintf(fd,
"ranksep=1.5\n");
1238 fprintf(fd,
"rankdir=LR\n");
1239 fprintf(fd,
"splines=false\n");
1242 fprintf(fd,
"// NODE: %p\n", node);
1243 fprintf(fd,
"\"%p\" [shape=record,label=\"{", node);
1244 if (!node->inputs.empty()) {
1247 if (socket != node->inputs[0]) {
1250 fprintf(fd,
"<IN_%p>%s", socket, socket->
name().c_str());
1254 fprintf(fd,
"%s", node->name.c_str());
1256 fprintf(fd,
" (bump:center)");
1259 fprintf(fd,
" (bump:dx)");
1262 fprintf(fd,
" (bump:dy)");
1264 if (!node->outputs.empty()) {
1267 if (socket != node->outputs[0]) {
1270 fprintf(fd,
"<OUT_%p>%s", socket, socket->
name().c_str());
1274 fprintf(fd,
"}\"]");
1281 "// CONNECTION: OUT_%p->IN_%p (%s:%s)\n",
1285 input->name().c_str());
1287 "\"%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 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 optimize_volume_output()
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)
void disconnect_unused_input(const char *name)
virtual void constant_fold(const ConstantFolder &)
virtual void expand(ShaderGraph *)
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
SocketType::Type type() const
bool has_surface_link() const
void push_back(unique_ptr< T > &&value)
#define CLOSURE_IS_VOLUME(type)
#define MAX_VOLUME_STACK_SIZE
#define CLOSURE_IS_PRINCIPLED(type)
#define CLOSURE_IS_BSSRDF(type)
#define CLOSURE_IS_BSDF_MULTISCATTER(type)
#define CCL_NAMESPACE_END
#define assert(assertion)
@ NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT
@ NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD
@ 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
@ NODE_VECTOR_TRANSFORM_TYPE_NORMAL
@ 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
float get_float(const SocketType &input) const
void set(const SocketType &input, bool value)
void set_value(const SocketType &socket, const Node &other, const SocketType &other_socket)
void copy_value(const SocketType &socket, const Node &other, const SocketType &other_socket)
bool equals_value(const Node &other, const SocketType &socket) const
Node(const NodeType *type, ustring name=ustring())
unique_ptr< ShaderManager > shader_manager