Blender V2.61 - r43446

graph.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright 2011, Blender Foundation.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 #include "attribute.h"
00020 #include "graph.h"
00021 #include "nodes.h"
00022 
00023 #include "util_algorithm.h"
00024 #include "util_debug.h"
00025 #include "util_foreach.h"
00026 
00027 CCL_NAMESPACE_BEGIN
00028 
00029 /* Input and Output */
00030 
00031 ShaderInput::ShaderInput(ShaderNode *parent_, const char *name_, ShaderSocketType type_)
00032 {
00033     parent = parent_;
00034     name = name_;
00035     type = type_;
00036     link = NULL;
00037     value = make_float3(0, 0, 0);
00038     stack_offset = SVM_STACK_INVALID;
00039     default_value = NONE;
00040     osl_only = false;
00041 }
00042 
00043 ShaderOutput::ShaderOutput(ShaderNode *parent_, const char *name_, ShaderSocketType type_)
00044 {
00045     parent = parent_;
00046     name = name_;
00047     type = type_;
00048     stack_offset = SVM_STACK_INVALID;
00049 }
00050 
00051 /* Node */
00052 
00053 ShaderNode::ShaderNode(const char *name_)
00054 {
00055     name = name_;
00056     id = -1;
00057     bump = SHADER_BUMP_NONE;
00058 }
00059 
00060 ShaderNode::~ShaderNode()
00061 {
00062     foreach(ShaderInput *socket, inputs)
00063         delete socket;
00064 
00065     foreach(ShaderOutput *socket, outputs)
00066         delete socket;
00067 }
00068 
00069 ShaderInput *ShaderNode::input(const char *name)
00070 {
00071     foreach(ShaderInput *socket, inputs)
00072         if(strcmp(socket->name, name) == 0)
00073             return socket;
00074 
00075     return NULL;
00076 }
00077 
00078 ShaderOutput *ShaderNode::output(const char *name)
00079 {
00080     foreach(ShaderOutput *socket, outputs)
00081         if(strcmp(socket->name, name) == 0)
00082             return socket;
00083 
00084     return NULL;
00085 }
00086 
00087 ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, float value)
00088 {
00089     ShaderInput *input = new ShaderInput(this, name, type);
00090     input->value.x = value;
00091     inputs.push_back(input);
00092     return input;
00093 }
00094 
00095 ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, float3 value)
00096 {
00097     ShaderInput *input = new ShaderInput(this, name, type);
00098     input->value = value;
00099     inputs.push_back(input);
00100     return input;
00101 }
00102 
00103 ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, ShaderInput::DefaultValue value, bool osl_only)
00104 {
00105     ShaderInput *input = add_input(name, type);
00106     input->default_value = value;
00107     input->osl_only = osl_only;
00108     return input;
00109 }
00110 
00111 ShaderOutput *ShaderNode::add_output(const char *name, ShaderSocketType type)
00112 {
00113     ShaderOutput *output = new ShaderOutput(this, name, type);
00114     outputs.push_back(output);
00115     return output;
00116 }
00117 
00118 void ShaderNode::attributes(AttributeRequestSet *attributes)
00119 {
00120     foreach(ShaderInput *input, inputs) {
00121         if(!input->link) {
00122             if(input->default_value == ShaderInput::TEXTURE_GENERATED)
00123                 attributes->add(Attribute::STD_GENERATED);
00124             else if(input->default_value == ShaderInput::TEXTURE_UV)
00125                 attributes->add(Attribute::STD_UV);
00126         }
00127     }
00128 }
00129 
00130 /* Graph */
00131 
00132 ShaderGraph::ShaderGraph()
00133 {
00134     finalized = false;
00135     add(new OutputNode());
00136 }
00137 
00138 ShaderGraph::~ShaderGraph()
00139 {
00140     foreach(ShaderNode *node, nodes)
00141         delete node;
00142 }
00143 
00144 ShaderNode *ShaderGraph::add(ShaderNode *node)
00145 {
00146     assert(!finalized);
00147     node->id = nodes.size();
00148     nodes.push_back(node);
00149     return node;
00150 }
00151 
00152 ShaderNode *ShaderGraph::output()
00153 {
00154     return nodes.front();
00155 }
00156 
00157 ShaderGraph *ShaderGraph::copy()
00158 {
00159     ShaderGraph *newgraph = new ShaderGraph();
00160 
00161     /* copy nodes */
00162     set<ShaderNode*> nodes_all;
00163     foreach(ShaderNode *node, nodes)
00164         nodes_all.insert(node);
00165 
00166     map<ShaderNode*, ShaderNode*> nodes_copy;
00167     copy_nodes(nodes_all, nodes_copy);
00168 
00169     /* add nodes (in same order, so output is still first) */
00170     newgraph->nodes.clear();
00171     foreach(ShaderNode *node, nodes)
00172         newgraph->add(nodes_copy[node]);
00173 
00174     return newgraph;
00175 }
00176 
00177 void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to)
00178 {
00179     assert(!finalized);
00180     assert(from && to);
00181 
00182     if(to->link) {
00183         fprintf(stderr, "ShaderGraph connect: input already connected.\n");
00184         return;
00185     }
00186 
00187     if(from->type != to->type) {
00188         /* for closures we can't do automatic conversion */
00189         if(from->type == SHADER_SOCKET_CLOSURE || to->type == SHADER_SOCKET_CLOSURE) {
00190             fprintf(stderr, "ShaderGraph connect: can only connect closure to closure.\n");
00191             return;
00192         }
00193 
00194         /* add automatic conversion node in case of type mismatch */
00195         ShaderNode *convert = add(new ConvertNode(from->type, to->type));
00196 
00197         connect(from, convert->inputs[0]);
00198         connect(convert->outputs[0], to);
00199     }
00200     else {
00201         /* types match, just connect */
00202         to->link = from;
00203         from->links.push_back(to);
00204     }
00205 }
00206 
00207 void ShaderGraph::disconnect(ShaderInput *to)
00208 {
00209     assert(!finalized);
00210     assert(to->link);
00211 
00212     ShaderOutput *from = to->link;
00213 
00214     to->link = NULL;
00215     from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end());
00216 }
00217 
00218 void ShaderGraph::finalize(bool do_bump, bool do_osl)
00219 {
00220     /* before compiling, the shader graph may undergo a number of modifications.
00221      * currently we set default geometry shader inputs, and create automatic bump
00222      * from displacement. a graph can be finalized only once, and should not be
00223      * modified afterwards. */
00224 
00225     if(!finalized) {
00226         clean();
00227         default_inputs(do_osl);
00228         if(do_bump)
00229             bump_from_displacement();
00230 
00231         finalized = true;
00232     }
00233 }
00234 
00235 void ShaderGraph::find_dependencies(set<ShaderNode*>& dependencies, ShaderInput *input)
00236 {
00237     /* find all nodes that this input dependes on directly and indirectly */
00238     ShaderNode *node = (input->link)? input->link->parent: NULL;
00239 
00240     if(node) {
00241         foreach(ShaderInput *in, node->inputs)
00242             find_dependencies(dependencies, in);
00243 
00244         dependencies.insert(node);
00245     }
00246 }
00247 
00248 void ShaderGraph::copy_nodes(set<ShaderNode*>& nodes, map<ShaderNode*, ShaderNode*>& nnodemap)
00249 {
00250     /* copy a set of nodes, and the links between them. the assumption is
00251      * made that all nodes that inputs are linked to are in the set too. */
00252 
00253     /* copy nodes */
00254     foreach(ShaderNode *node, nodes) {
00255         ShaderNode *nnode = node->clone();
00256         nnodemap[node] = nnode;
00257 
00258         nnode->inputs.clear();
00259         nnode->outputs.clear();
00260 
00261         foreach(ShaderInput *input, node->inputs) {
00262             ShaderInput *ninput = new ShaderInput(*input);
00263             nnode->inputs.push_back(ninput);
00264 
00265             ninput->parent = nnode;
00266             ninput->link = NULL;
00267         }
00268 
00269         foreach(ShaderOutput *output, node->outputs) {
00270             ShaderOutput *noutput = new ShaderOutput(*output);
00271             nnode->outputs.push_back(noutput);
00272 
00273             noutput->parent = nnode;
00274             noutput->links.clear();
00275         }
00276     }
00277 
00278     /* recreate links */
00279     foreach(ShaderNode *node, nodes) {
00280         foreach(ShaderInput *input, node->inputs) {
00281             if(input->link) {
00282                 /* find new input and output */
00283                 ShaderNode *nfrom = nnodemap[input->link->parent];
00284                 ShaderNode *nto = nnodemap[input->parent];
00285                 ShaderOutput *noutput = nfrom->output(input->link->name);
00286                 ShaderInput *ninput = nto->input(input->name);
00287 
00288                 /* connect */
00289                 connect(noutput, ninput);
00290             }
00291         }
00292     }
00293 }
00294 
00295 void ShaderGraph::remove_proxy_nodes(vector<bool>& removed)
00296 {
00297     foreach(ShaderNode *node, nodes) {
00298         ProxyNode *proxy = dynamic_cast<ProxyNode*>(node);
00299         if (proxy) {
00300             ShaderInput *input = proxy->inputs[0];
00301             ShaderOutput *output = proxy->outputs[0];
00302             
00303             /* temp. copy of the output links list.
00304              * output->links is modified when we disconnect!
00305              */
00306             vector<ShaderInput*> links(output->links);
00307             ShaderOutput *from = input->link;
00308             
00309             /* bypass the proxy node */
00310             if (from) {
00311                 disconnect(input);
00312                 foreach(ShaderInput *to, links) {
00313                     disconnect(to);
00314                     connect(from, to);
00315                 }
00316             }
00317             else {
00318                 foreach(ShaderInput *to, links) {
00319                     disconnect(to);
00320                     
00321                     /* transfer the default input value to the target socket */
00322                     to->set(input->value);
00323                 }
00324             }
00325             
00326             removed[proxy->id] = true;
00327         }
00328     }
00329 }
00330 
00331 void ShaderGraph::break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack)
00332 {
00333     visited[node->id] = true;
00334     on_stack[node->id] = true;
00335 
00336     foreach(ShaderInput *input, node->inputs) {
00337         if(input->link) {
00338             ShaderNode *depnode = input->link->parent;
00339 
00340             if(on_stack[depnode->id]) {
00341                 /* break cycle */
00342                 disconnect(input);
00343                 fprintf(stderr, "ShaderGraph: detected cycle in graph, connection removed.\n");
00344             }
00345             else if(!visited[depnode->id]) {
00346                 /* visit dependencies */
00347                 break_cycles(depnode, visited, on_stack);
00348             }
00349         }
00350     }
00351 
00352     on_stack[node->id] = false;
00353 }
00354 
00355 void ShaderGraph::clean()
00356 {
00357     /* we do two things here: find cycles and break them, and remove unused
00358        nodes that don't feed into the output. how cycles are broken is
00359        undefined, they are invalid input, the important thing is to not crash */
00360 
00361     vector<bool> removed(nodes.size(), false);
00362     vector<bool> visited(nodes.size(), false);
00363     vector<bool> on_stack(nodes.size(), false);
00364     
00365     list<ShaderNode*> newnodes;
00366     
00367     /* remove proxy nodes */
00368     remove_proxy_nodes(removed);
00369     
00370     foreach(ShaderNode *node, nodes) {
00371         if(!removed[node->id])
00372             newnodes.push_back(node);
00373         else
00374             delete node;
00375     }
00376     nodes = newnodes;
00377     newnodes.clear();
00378 
00379     /* break cycles */
00380     break_cycles(output(), visited, on_stack);
00381 
00382     /* remove unused nodes */
00383     foreach(ShaderNode *node, nodes) {
00384         if(visited[node->id])
00385             newnodes.push_back(node);
00386         else
00387             delete node;
00388     }
00389     
00390     nodes = newnodes;
00391 }
00392 
00393 void ShaderGraph::default_inputs(bool do_osl)
00394 {
00395     /* nodes can specify default texture coordinates, for now we give
00396      * everything the position by default, except for the sky texture */
00397 
00398     ShaderNode *geom = NULL;
00399     ShaderNode *texco = NULL;
00400 
00401     foreach(ShaderNode *node, nodes) {
00402         foreach(ShaderInput *input, node->inputs) {
00403             if(!input->link && !(input->osl_only && !do_osl)) {
00404                 if(input->default_value == ShaderInput::TEXTURE_GENERATED) {
00405                     if(!texco)
00406                         texco = new TextureCoordinateNode();
00407 
00408                     connect(texco->output("Generated"), input);
00409                 }
00410                 else if(input->default_value == ShaderInput::TEXTURE_UV) {
00411                     if(!texco)
00412                         texco = new TextureCoordinateNode();
00413 
00414                     connect(texco->output("UV"), input);
00415                 }
00416                 else if(input->default_value == ShaderInput::INCOMING) {
00417                     if(!geom)
00418                         geom = new GeometryNode();
00419 
00420                     connect(geom->output("Incoming"), input);
00421                 }
00422                 else if(input->default_value == ShaderInput::NORMAL) {
00423                     if(!geom)
00424                         geom = new GeometryNode();
00425 
00426                     connect(geom->output("Normal"), input);
00427                 }
00428                 else if(input->default_value == ShaderInput::POSITION) {
00429                     if(!geom)
00430                         geom = new GeometryNode();
00431 
00432                     connect(geom->output("Position"), input);
00433                 }
00434             }
00435         }
00436     }
00437 
00438     if(geom)
00439         add(geom);
00440     if(texco)
00441         add(texco);
00442 }
00443 
00444 void ShaderGraph::bump_from_displacement()
00445 {
00446     /* generate bump mapping automatically from displacement. bump mapping is
00447      * done using a 3-tap filter, computing the displacement at the center,
00448      * and two other positions shifted by ray differentials.
00449      *
00450      * since the input to displacement is a node graph, we need to ensure that
00451      * all texture coordinates use are shift by the ray differentials. for this
00452      * reason we make 3 copies of the node subgraph defining the displacement,
00453      * with each different geometry and texture coordinate nodes that generate
00454      * different shifted coordinates.
00455      *
00456      * these 3 displacement values are then fed into the bump node, which will
00457      * modify the normal. */
00458 
00459     ShaderInput *displacement_in = output()->input("Displacement");
00460 
00461     if(!displacement_in->link)
00462         return;
00463     
00464     /* find dependencies for the given input */
00465     set<ShaderNode*> nodes_displace;
00466     find_dependencies(nodes_displace, displacement_in);
00467 
00468     /* copy nodes for 3 bump samples */
00469     map<ShaderNode*, ShaderNode*> nodes_center;
00470     map<ShaderNode*, ShaderNode*> nodes_dx;
00471     map<ShaderNode*, ShaderNode*> nodes_dy;
00472 
00473     copy_nodes(nodes_displace, nodes_center);
00474     copy_nodes(nodes_displace, nodes_dx);
00475     copy_nodes(nodes_displace, nodes_dy);
00476 
00477     /* mark nodes to indicate they are use for bump computation, so
00478        that any texture coordinates are shifted by dx/dy when sampling */
00479     foreach(NodePair& pair, nodes_center)
00480         pair.second->bump = SHADER_BUMP_CENTER;
00481     foreach(NodePair& pair, nodes_dx)
00482         pair.second->bump = SHADER_BUMP_DX;
00483     foreach(NodePair& pair, nodes_dy)
00484         pair.second->bump = SHADER_BUMP_DY;
00485 
00486     /* add bump node and connect copied graphs to it */
00487     ShaderNode *bump = add(new BumpNode());
00488 
00489     ShaderOutput *out = displacement_in->link;
00490     ShaderOutput *out_center = nodes_center[out->parent]->output(out->name);
00491     ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name);
00492     ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name);
00493 
00494     connect(out_center, bump->input("SampleCenter"));
00495     connect(out_dx, bump->input("SampleX"));
00496     connect(out_dy, bump->input("SampleY"));
00497 
00498     /* connect bump output to normal input nodes that aren't set yet. actually
00499        this will only set the normal input to the geometry node that we created
00500        and connected to all other normal inputs already. */
00501     foreach(ShaderNode *node, nodes)
00502         foreach(ShaderInput *input, node->inputs)
00503             if(!input->link && input->default_value == ShaderInput::NORMAL)
00504                 connect(bump->output("Normal"), input);
00505     
00506     /* finally, add the copied nodes to the graph. we can't do this earlier
00507        because we would create dependency cycles in the above loop */
00508     foreach(NodePair& pair, nodes_center)
00509         add(pair.second);
00510     foreach(NodePair& pair, nodes_dx)
00511         add(pair.second);
00512     foreach(NodePair& pair, nodes_dy)
00513         add(pair.second);
00514 }
00515 
00516 CCL_NAMESPACE_END
00517