From ceed3ef640bb40e1232feeb409220fe19011bc43 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 26 Nov 2012 21:59:41 +0000 Subject: Fix #32907: failure rendering a complex node setup, hitting fixed max number of closures limit. Optimized the code now so it can handle more. Change SVM mix/add closure handling, now we transform the node graph so that the mix weights are fed into the closure nodes directly. --- intern/cycles/render/graph.cpp | 104 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 97 insertions(+), 7 deletions(-) (limited to 'intern/cycles/render/graph.cpp') diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index f71675dbda3..14b219383d0 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -37,7 +37,7 @@ ShaderInput::ShaderInput(ShaderNode *parent_, const char *name_, ShaderSocketTyp value = make_float3(0, 0, 0); stack_offset = SVM_STACK_INVALID; default_value = NONE; - osl_only = false; + usage = USE_ALL; } ShaderOutput::ShaderOutput(ShaderNode *parent_, const char *name_, ShaderSocketType type_) @@ -85,27 +85,29 @@ ShaderOutput *ShaderNode::output(const char *name) return NULL; } -ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, float value) +ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, float value, int usage) { ShaderInput *input = new ShaderInput(this, name, type); input->value.x = value; + input->usage = usage; inputs.push_back(input); return input; } -ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, float3 value) +ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, float3 value, int usage) { ShaderInput *input = new ShaderInput(this, name, type); input->value = value; + input->usage = usage; inputs.push_back(input); return input; } -ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, ShaderInput::DefaultValue value, bool osl_only) +ShaderInput *ShaderNode::add_input(const char *name, ShaderSocketType type, ShaderInput::DefaultValue value, int usage) { ShaderInput *input = add_input(name, type); input->default_value = value; - input->osl_only = osl_only; + input->usage = usage; return input; } @@ -219,7 +221,7 @@ void ShaderGraph::disconnect(ShaderInput *to) from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end()); } -void ShaderGraph::finalize(bool do_bump, bool do_osl) +void ShaderGraph::finalize(bool do_bump, bool do_osl, bool do_multi_transform) { /* before compiling, the shader graph may undergo a number of modifications. * currently we set default geometry shader inputs, and create automatic bump @@ -234,6 +236,18 @@ void ShaderGraph::finalize(bool do_bump, bool do_osl) if(do_bump) bump_from_displacement(); + if(do_multi_transform) { + ShaderInput *surface_in = output()->input("Surface"); + ShaderInput *volume_in = output()->input("Volume"); + + /* todo: make this work when surface and volume closures are tangled up */ + + if(surface_in->link) + transform_multi_closure(surface_in->link->parent, NULL, false); + if(volume_in->link) + transform_multi_closure(volume_in->link->parent, NULL, true); + } + finalized = true; } } @@ -440,7 +454,7 @@ void ShaderGraph::default_inputs(bool do_osl) foreach(ShaderNode *node, nodes) { foreach(ShaderInput *input, node->inputs) { - if(!input->link && !(input->osl_only && !do_osl)) { + if(!input->link && ((input->usage & ShaderInput::USE_SVM) || do_osl)) { if(input->default_value == ShaderInput::TEXTURE_GENERATED) { if(!texco) texco = new TextureCoordinateNode(); @@ -629,5 +643,81 @@ void ShaderGraph::bump_from_displacement() add(pair.second); } +void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight_out, bool volume) +{ + /* for SVM in multi closure mode, this transforms the shader mix/add part of + * the graph into nodes that feed weights into closure nodes. this is too + * avoid building a closure tree and then flattening it, and instead write it + * directly to an array */ + + if(node->name == ustring("mix_closure") || node->name == ustring("add_closure")) { + ShaderInput *fin = node->input("Fac"); + ShaderInput *cl1in = node->input("Closure1"); + ShaderInput *cl2in = node->input("Closure2"); + ShaderOutput *weight1_out, *weight2_out; + + if(fin) { + /* mix closure: add node to mix closure weights */ + ShaderNode *mix_node = add(new MixClosureWeightNode()); + ShaderInput *fac_in = mix_node->input("Fac"); + ShaderInput *weight_in = mix_node->input("Weight"); + + if(fin->link) + connect(fin->link, fac_in); + else + fac_in->value = fin->value; + + if(weight_out) + connect(weight_out, weight_in); + + weight1_out = mix_node->output("Weight1"); + weight2_out = mix_node->output("Weight2"); + } + else { + /* add closure: just pass on any weights */ + weight1_out = weight_out; + weight2_out = weight_out; + } + + if(cl1in->link) + transform_multi_closure(cl1in->link->parent, weight1_out, volume); + if(cl2in->link) + transform_multi_closure(cl2in->link->parent, weight2_out, volume); + } + else { + ShaderInput *weight_in = node->input((volume)? "VolumeMixWeight": "SurfaceMixWeight"); + + /* not a closure node? */ + if(!weight_in) + return; + + /* already has a weight connected to it? add weights */ + if(weight_in->link || weight_in->value.x != 0.0f) { + ShaderNode *math_node = add(new MathNode()); + ShaderInput *value1_in = math_node->input("Value1"); + ShaderInput *value2_in = math_node->input("Value2"); + + if(weight_in->link) + connect(weight_in->link, value1_in); + else + value1_in->value = weight_in->value; + + if(weight_out) + connect(weight_out, value2_in); + else + value2_in->value.x = 1.0f; + + weight_out = math_node->output("Value"); + disconnect(weight_in); + } + + /* connected to closure mix weight */ + if(weight_out) + connect(weight_out, weight_in); + else + weight_in->value.x += 1.0f; + } +} + CCL_NAMESPACE_END -- cgit v1.2.3