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.
This commit is contained in:
Brecht Van Lommel
2012-11-26 21:59:41 +00:00
parent eab58bf994
commit ceed3ef640
7 changed files with 315 additions and 222 deletions

View File

@@ -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