diff options
-rw-r--r-- | intern/cycles/render/graph.cpp | 61 | ||||
-rw-r--r-- | intern/cycles/render/graph.h | 2 | ||||
-rw-r--r-- | intern/cycles/render/shader.cpp | 6 |
3 files changed, 42 insertions, 27 deletions
diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index b026f07ce56..f081e2db7af 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -312,10 +312,14 @@ void ShaderGraph::copy_nodes(set<ShaderNode*>& nodes, map<ShaderNode*, ShaderNod } } -void ShaderGraph::remove_proxy_nodes(vector<bool>& removed) +void ShaderGraph::remove_unneeded_nodes() { + vector<bool> removed(nodes.size(), false); + bool any_node_removed = false; + + /* find and unlink proxy nodes */ foreach(ShaderNode *node, nodes) { - if (node->special_type == SHADER_SPECIAL_TYPE_PROXY) { + if(node->special_type == SHADER_SPECIAL_TYPE_PROXY) { ProxyNode *proxy = static_cast<ProxyNode*>(node); ShaderInput *input = proxy->inputs[0]; ShaderOutput *output = proxy->outputs[0]; @@ -327,7 +331,7 @@ void ShaderGraph::remove_proxy_nodes(vector<bool>& removed) ShaderOutput *from = input->link; /* bypass the proxy node */ - if (from) { + if(from) { disconnect(input); foreach(ShaderInput *to, links) { disconnect(to); @@ -345,6 +349,7 @@ void ShaderGraph::remove_proxy_nodes(vector<bool>& removed) } removed[proxy->id] = true; + any_node_removed = true; } /* remove useless mix closures nodes */ @@ -360,7 +365,7 @@ void ShaderGraph::remove_proxy_nodes(vector<bool>& removed) foreach(ShaderInput *input, inputs) { disconnect(input); - if (output) + if(output) connect(output, input); } } @@ -378,33 +383,47 @@ void ShaderGraph::remove_proxy_nodes(vector<bool>& removed) vector<ShaderInput*> inputs = mix->outputs[0]->links; foreach(ShaderInput *sock, mix->inputs) - if(sock->link) - disconnect(sock); + if(sock->link) + disconnect(sock); foreach(ShaderInput *input, inputs) { disconnect(input); - if (output) - connect(output, input); + if(output) + connect(output, input); } } /* Factor 1.0 */ - else if (mix->inputs[0]->value.x == 1.0f) { + else if(mix->inputs[0]->value.x == 1.0f) { ShaderOutput *output = mix->inputs[2]->link; vector<ShaderInput*> inputs = mix->outputs[0]->links; foreach(ShaderInput *sock, mix->inputs) - if(sock->link) - disconnect(sock); + if(sock->link) + disconnect(sock); foreach(ShaderInput *input, inputs) { disconnect(input); - if (output) + if(output) connect(output, input); } } } } } + + /* remove nodes */ + if (any_node_removed) { + list<ShaderNode*> newnodes; + + foreach(ShaderNode *node, nodes) { + if(!removed[node->id]) + newnodes.push_back(node); + else + delete node; + } + + nodes = newnodes; + } } void ShaderGraph::break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack) @@ -433,27 +452,17 @@ void ShaderGraph::break_cycles(ShaderNode *node, vector<bool>& visited, vector<b void ShaderGraph::clean() { + /* remove proxy and unnecessary mix nodes */ + remove_unneeded_nodes(); + /* we do two things here: find cycles and break them, and remove unused * nodes that don't feed into the output. how cycles are broken is * undefined, they are invalid input, the important thing is to not crash */ - vector<bool> removed(nodes.size(), false); vector<bool> visited(nodes.size(), false); vector<bool> on_stack(nodes.size(), false); list<ShaderNode*> newnodes; - - /* remove proxy nodes */ - remove_proxy_nodes(removed); - - foreach(ShaderNode *node, nodes) { - if(!removed[node->id]) - newnodes.push_back(node); - else - delete node; - } - nodes = newnodes; - newnodes.clear(); /* break cycles */ break_cycles(output(), visited, on_stack); @@ -464,7 +473,7 @@ void ShaderGraph::clean() foreach(ShaderInput *to, node->inputs) { ShaderOutput *from = to->link; - if (from) { + if(from) { to->link = NULL; from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end()); } diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index 46043cf85d2..8e91a9ddc07 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -239,6 +239,7 @@ public: void connect(ShaderOutput *from, ShaderInput *to); void disconnect(ShaderInput *to); + void remove_unneeded_nodes(); void finalize(bool do_bump = false, bool do_osl = false, bool do_multi_closure = false); protected: @@ -247,7 +248,6 @@ protected: void find_dependencies(set<ShaderNode*>& dependencies, ShaderInput *input); void copy_nodes(set<ShaderNode*>& nodes, map<ShaderNode*, ShaderNode*>& nnodemap); - void remove_proxy_nodes(vector<bool>& removed); void break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack); void clean(); void bump_from_displacement(); diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp index c7f39b4151a..b061e869e2f 100644 --- a/intern/cycles/render/shader.cpp +++ b/intern/cycles/render/shader.cpp @@ -66,6 +66,12 @@ Shader::~Shader() void Shader::set_graph(ShaderGraph *graph_) { + /* do this here already so that we can detect if mesh or object attributes + * are needed, since the node attribute callbacks check if their sockets + * are connected but proxy nodes should not count */ + if(graph_) + graph_->remove_unneeded_nodes(); + /* assign graph */ delete graph; delete graph_bump; |