From ceed3ef640bb40e1232feeb409220fe19011bc43 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 26 Nov 2012 21:59:41 +0000 Subject: [PATCH] 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/kernel/svm/svm_closure.h | 219 ++++++++++++++----------- intern/cycles/render/graph.cpp | 104 +++++++++++- intern/cycles/render/graph.h | 17 +- intern/cycles/render/nodes.cpp | 59 ++++++- intern/cycles/render/nodes.h | 5 + intern/cycles/render/svm.cpp | 124 +++----------- intern/cycles/render/svm.h | 9 +- 7 files changed, 315 insertions(+), 222 deletions(-) diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h index a4f8546f62b..7140b4971ea 100644 --- a/intern/cycles/kernel/svm/svm_closure.h +++ b/intern/cycles/kernel/svm/svm_closure.h @@ -64,11 +64,22 @@ __device_inline ShaderClosure *svm_node_closure_get(ShaderData *sd) #endif } -__device_inline void svm_node_closure_set_mix_weight(ShaderClosure *sc, float mix_weight) +__device_inline ShaderClosure *svm_node_closure_get_weight(ShaderData *sd, float mix_weight) { #ifdef __MULTI_CLOSURE__ + ShaderClosure *sc = &sd->closure[sd->num_closure]; + sc->weight *= mix_weight; sc->sample_weight = fabsf(average(sc->weight)); + + if(sc->sample_weight > 1e-5f && sd->num_closure < MAX_CLOSURE) { + sd->num_closure++; + return sc; + } + + return NULL; +#else + return &sd->closure; #endif } @@ -101,33 +112,39 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st switch(type) { case CLOSURE_BSDF_DIFFUSE_ID: { - ShaderClosure *sc = svm_node_closure_get(sd); - sc->N = N; - svm_node_closure_set_mix_weight(sc, mix_weight); + ShaderClosure *sc = svm_node_closure_get_weight(sd, mix_weight); - float roughness = param1; + if(sc) { + sc->N = N; - if(roughness == 0.0f) { - sd->flag |= bsdf_diffuse_setup(sc); - } - else { - sc->data0 = roughness; - sd->flag |= bsdf_oren_nayar_setup(sc); + float roughness = param1; + + if(roughness == 0.0f) { + sd->flag |= bsdf_diffuse_setup(sc); + } + else { + sc->data0 = roughness; + sd->flag |= bsdf_oren_nayar_setup(sc); + } } break; } case CLOSURE_BSDF_TRANSLUCENT_ID: { - ShaderClosure *sc = svm_node_closure_get(sd); - sc->N = N; - svm_node_closure_set_mix_weight(sc, mix_weight); - sd->flag |= bsdf_translucent_setup(sc); + ShaderClosure *sc = svm_node_closure_get_weight(sd, mix_weight); + + if(sc) { + sc->N = N; + sd->flag |= bsdf_translucent_setup(sc); + } break; } case CLOSURE_BSDF_TRANSPARENT_ID: { - ShaderClosure *sc = svm_node_closure_get(sd); - sc->N = N; - svm_node_closure_set_mix_weight(sc, mix_weight); - sd->flag |= bsdf_transparent_setup(sc); + ShaderClosure *sc = svm_node_closure_get_weight(sd, mix_weight); + + if(sc) { + sc->N = N; + sd->flag |= bsdf_transparent_setup(sc); + } break; } case CLOSURE_BSDF_REFLECTION_ID: @@ -137,18 +154,20 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st if(kernel_data.integrator.no_caustics && (path_flag & PATH_RAY_DIFFUSE)) break; #endif - ShaderClosure *sc = svm_node_closure_get(sd); - sc->N = N; - sc->data0 = param1; - svm_node_closure_set_mix_weight(sc, mix_weight); + ShaderClosure *sc = svm_node_closure_get_weight(sd, mix_weight); - /* setup bsdf */ - if(type == CLOSURE_BSDF_REFLECTION_ID) - sd->flag |= bsdf_reflection_setup(sc); - else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_ID) - sd->flag |= bsdf_microfacet_beckmann_setup(sc); - else - sd->flag |= bsdf_microfacet_ggx_setup(sc); + if(sc) { + sc->N = N; + sc->data0 = param1; + + /* setup bsdf */ + if(type == CLOSURE_BSDF_REFLECTION_ID) + sd->flag |= bsdf_reflection_setup(sc); + else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_ID) + sd->flag |= bsdf_microfacet_beckmann_setup(sc); + else + sd->flag |= bsdf_microfacet_ggx_setup(sc); + } break; } @@ -159,21 +178,23 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st if(kernel_data.integrator.no_caustics && (path_flag & PATH_RAY_DIFFUSE)) break; #endif - ShaderClosure *sc = svm_node_closure_get(sd); - sc->N = N; - sc->data0 = param1; - svm_node_closure_set_mix_weight(sc, mix_weight); + ShaderClosure *sc = svm_node_closure_get_weight(sd, mix_weight); - float eta = fmaxf(param2, 1.0f + 1e-5f); - sc->data1 = (sd->flag & SD_BACKFACING)? 1.0f/eta: eta; + if(sc) { + sc->N = N; + sc->data0 = param1; - /* setup bsdf */ - if(type == CLOSURE_BSDF_REFRACTION_ID) - sd->flag |= bsdf_refraction_setup(sc); - else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID) - sd->flag |= bsdf_microfacet_beckmann_refraction_setup(sc); - else - sd->flag |= bsdf_microfacet_ggx_refraction_setup(sc); + float eta = fmaxf(param2, 1.0f + 1e-5f); + sc->data1 = (sd->flag & SD_BACKFACING)? 1.0f/eta: eta; + + /* setup bsdf */ + if(type == CLOSURE_BSDF_REFRACTION_ID) + sd->flag |= bsdf_refraction_setup(sc); + else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID) + sd->flag |= bsdf_microfacet_beckmann_refraction_setup(sc); + else + sd->flag |= bsdf_microfacet_ggx_refraction_setup(sc); + } break; } @@ -195,32 +216,36 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st #ifdef __MULTI_CLOSURE__ /* reflection */ - ShaderClosure *sc = svm_node_closure_get(sd); - sc->N = N; - + ShaderClosure *sc = &sd->closure[sd->num_closure]; float3 weight = sc->weight; float sample_weight = sc->sample_weight; - svm_node_closure_set_mix_weight(sc, mix_weight*fresnel); - svm_node_glass_setup(sd, sc, type, eta, roughness, false); + sc = svm_node_closure_get_weight(sd, mix_weight*fresnel); + + if(sc) { + sc->N = N; + svm_node_glass_setup(sd, sc, type, eta, roughness, false); + } /* refraction */ - sc = svm_node_closure_get(sd); - sc->N = N; - + sc = &sd->closure[sd->num_closure]; sc->weight = weight; sc->sample_weight = sample_weight; - svm_node_closure_set_mix_weight(sc, mix_weight*(1.0f - fresnel)); - svm_node_glass_setup(sd, sc, type, eta, roughness, true); + sc = svm_node_closure_get_weight(sd, mix_weight*(1.0f - fresnel)); + + if(sc) { + sc->N = N; + svm_node_glass_setup(sd, sc, type, eta, roughness, true); + } #else - ShaderClosure *sc = svm_node_closure_get(sd); - sc->N = N; + ShaderClosure *sc = svm_node_closure_get_weight(sd, mix_weight); - bool refract = (randb > fresnel); - - svm_node_closure_set_mix_weight(sc, mix_weight); - svm_node_glass_setup(sd, sc, type, eta, roughness, refract); + if(sc) { + sc->N = N; + bool refract = (randb > fresnel); + svm_node_glass_setup(sd, sc, type, eta, roughness, refract); + } #endif break; @@ -230,46 +255,50 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st if(kernel_data.integrator.no_caustics && (path_flag & PATH_RAY_DIFFUSE)) break; #endif - ShaderClosure *sc = svm_node_closure_get(sd); - sc->N = N; - svm_node_closure_set_mix_weight(sc, mix_weight); + ShaderClosure *sc = svm_node_closure_get_weight(sd, mix_weight); + + if(sc) { + sc->N = N; #ifdef __ANISOTROPIC__ - sc->T = stack_load_float3(stack, data_node.z); + sc->T = stack_load_float3(stack, data_node.z); - /* rotate tangent */ - float rotation = stack_load_float(stack, data_node.w); + /* rotate tangent */ + float rotation = stack_load_float(stack, data_node.w); - if(rotation != 0.0f) - sc->T = rotate_around_axis(sc->T, sc->N, rotation * 2.0f * M_PI_F); + if(rotation != 0.0f) + sc->T = rotate_around_axis(sc->T, sc->N, rotation * 2.0f * M_PI_F); - /* compute roughness */ - float roughness = param1; - float anisotropy = clamp(param2, -0.99f, 0.99f); + /* compute roughness */ + float roughness = param1; + float anisotropy = clamp(param2, -0.99f, 0.99f); - if(anisotropy < 0.0f) { - sc->data0 = roughness/(1.0f + anisotropy); - sc->data1 = roughness*(1.0f + anisotropy); - } - else { - sc->data0 = roughness*(1.0f - anisotropy); - sc->data1 = roughness/(1.0f - anisotropy); - } + if(anisotropy < 0.0f) { + sc->data0 = roughness/(1.0f + anisotropy); + sc->data1 = roughness*(1.0f + anisotropy); + } + else { + sc->data0 = roughness*(1.0f - anisotropy); + sc->data1 = roughness/(1.0f - anisotropy); + } - sd->flag |= bsdf_ward_setup(sc); + sd->flag |= bsdf_ward_setup(sc); #else - sd->flag |= bsdf_diffuse_setup(sc); + sd->flag |= bsdf_diffuse_setup(sc); #endif + } break; } case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: { - ShaderClosure *sc = svm_node_closure_get(sd); - sc->N = N; - svm_node_closure_set_mix_weight(sc, mix_weight); + ShaderClosure *sc = svm_node_closure_get_weight(sd, mix_weight); - /* sigma */ - sc->data0 = clamp(param1, 0.0f, 1.0f); - sd->flag |= bsdf_ashikhmin_velvet_setup(sc); + if(sc) { + sc->N = N; + + /* sigma */ + sc->data0 = clamp(param1, 0.0f, 1.0f); + sd->flag |= bsdf_ashikhmin_velvet_setup(sc); + } break; } default: @@ -298,19 +327,21 @@ __device void svm_node_closure_volume(KernelGlobals *kg, ShaderData *sd, float * switch(type) { case CLOSURE_VOLUME_TRANSPARENT_ID: { - ShaderClosure *sc = svm_node_closure_get(sd); - svm_node_closure_set_mix_weight(sc, mix_weight); + ShaderClosure *sc = svm_node_closure_get_weight(sd, mix_weight); - float density = param1; - sd->flag |= volume_transparent_setup(sc, density); + if(sc) { + float density = param1; + sd->flag |= volume_transparent_setup(sc, density); + } break; } case CLOSURE_VOLUME_ISOTROPIC_ID: { - ShaderClosure *sc = svm_node_closure_get(sd); - svm_node_closure_set_mix_weight(sc, mix_weight); + ShaderClosure *sc = svm_node_closure_get_weight(sd, mix_weight); - float density = param1; - sd->flag |= volume_isotropic_setup(sc, density); + if(sc) { + float density = param1; + sd->flag |= volume_isotropic_setup(sc, density); + } break; } default: 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 diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index 373c7e0eaab..b79167839ab 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -118,6 +118,12 @@ public: NONE }; + enum Usage { + USE_SVM = 1, + USE_OSL = 2, + USE_ALL = USE_SVM|USE_OSL + }; + ShaderInput(ShaderNode *parent, const char *name, ShaderSocketType type); void set(const float3& v) { value = v; } void set(float f) { value = make_float3(f, 0, 0); } @@ -134,7 +140,7 @@ public: ustring value_string; int stack_offset; /* for SVM compiler */ - bool osl_only; + int usage; }; /* Output @@ -167,9 +173,9 @@ public: ShaderInput *input(const char *name); ShaderOutput *output(const char *name); - ShaderInput *add_input(const char *name, ShaderSocketType type, float value=0.0f); - ShaderInput *add_input(const char *name, ShaderSocketType type, float3 value); - ShaderInput *add_input(const char *name, ShaderSocketType type, ShaderInput::DefaultValue value, bool osl_only=false); + ShaderInput *add_input(const char *name, ShaderSocketType type, float value=0.0f, int usage=ShaderInput::USE_ALL); + ShaderInput *add_input(const char *name, ShaderSocketType type, float3 value, int usage=ShaderInput::USE_ALL); + ShaderInput *add_input(const char *name, ShaderSocketType type, ShaderInput::DefaultValue value, int usage=ShaderInput::USE_ALL); ShaderOutput *add_output(const char *name, ShaderSocketType type); virtual ShaderNode *clone() const = 0; @@ -227,7 +233,7 @@ public: void connect(ShaderOutput *from, ShaderInput *to); void disconnect(ShaderInput *to); - void finalize(bool do_bump = false, bool do_osl = false); + void finalize(bool do_bump = false, bool do_osl = false, bool do_multi_closure = false); protected: typedef pair NodePair; @@ -241,6 +247,7 @@ protected: void bump_from_displacement(); void refine_bump_nodes(); void default_inputs(bool do_osl); + void transform_multi_closure(ShaderNode *node, ShaderOutput *weight_out, bool volume); }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 48a8565ed98..12bbc019644 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -1257,6 +1257,7 @@ BsdfNode::BsdfNode() add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL); + add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); add_output("BSDF", SHADER_SOCKET_CLOSURE); } @@ -1544,6 +1545,8 @@ EmissionNode::EmissionNode() add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); add_input("Strength", SHADER_SOCKET_FLOAT, 10.0f); + add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); + add_output("Emission", SHADER_SOCKET_CLOSURE); } @@ -1578,6 +1581,8 @@ BackgroundNode::BackgroundNode() { add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f); + add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); + add_output("Background", SHADER_SOCKET_CLOSURE); } @@ -1607,6 +1612,9 @@ void BackgroundNode::compile(OSLCompiler& compiler) HoldoutNode::HoldoutNode() : ShaderNode("holdout") { + add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); + add_input("VolumeMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); + add_output("Holdout", SHADER_SOCKET_CLOSURE); } @@ -1625,9 +1633,10 @@ void HoldoutNode::compile(OSLCompiler& compiler) AmbientOcclusionNode::AmbientOcclusionNode() : ShaderNode("ambient_occlusion") { - add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true); - + add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); + add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); + add_output("AO", SHADER_SOCKET_CLOSURE); } @@ -1659,6 +1668,7 @@ VolumeNode::VolumeNode() add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); add_input("Density", SHADER_SOCKET_FLOAT, 1.0f); + add_input("VolumeMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM); add_output("Volume", SHADER_SOCKET_CLOSURE); } @@ -1737,7 +1747,7 @@ void IsotropicVolumeNode::compile(OSLCompiler& compiler) GeometryNode::GeometryNode() : ShaderNode("geometry") { - add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true); + add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); add_output("Position", SHADER_SOCKET_POINT); add_output("Normal", SHADER_SOCKET_NORMAL); add_output("Tangent", SHADER_SOCKET_NORMAL); @@ -1825,7 +1835,7 @@ void GeometryNode::compile(OSLCompiler& compiler) TextureCoordinateNode::TextureCoordinateNode() : ShaderNode("texture_coordinate") { - add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true); + add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); add_output("Generated", SHADER_SOCKET_POINT); add_output("Normal", SHADER_SOCKET_NORMAL); add_output("UV", SHADER_SOCKET_POINT); @@ -2315,6 +2325,39 @@ void MixClosureNode::compile(OSLCompiler& compiler) compiler.add(this, "node_mix_closure"); } +/* Mix Closure */ + +MixClosureWeightNode::MixClosureWeightNode() +: ShaderNode("mix_closure_weight") +{ + add_input("Weight", SHADER_SOCKET_FLOAT, 1.0f); + add_input("Fac", SHADER_SOCKET_FLOAT, 1.0f); + add_output("Weight1", SHADER_SOCKET_FLOAT); + add_output("Weight2", SHADER_SOCKET_FLOAT); +} + +void MixClosureWeightNode::compile(SVMCompiler& compiler) +{ + ShaderInput *weight_in = input("Weight"); + ShaderInput *fac_in = input("Fac"); + ShaderOutput *weight1_out = output("Weight1"); + ShaderOutput *weight2_out = output("Weight2"); + + compiler.stack_assign(weight_in); + compiler.stack_assign(fac_in); + compiler.stack_assign(weight1_out); + compiler.stack_assign(weight2_out); + + compiler.add_node(NODE_MIX_CLOSURE, + compiler.encode_uchar4(fac_in->stack_offset, weight_in->stack_offset, + weight1_out->stack_offset, weight2_out->stack_offset)); +} + +void MixClosureWeightNode::compile(OSLCompiler& compiler) +{ + assert(0); +} + /* Invert */ InvertNode::InvertNode() @@ -2680,7 +2723,7 @@ void CameraNode::compile(OSLCompiler& compiler) FresnelNode::FresnelNode() : ShaderNode("Fresnel") { - add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true); + add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); add_input("IOR", SHADER_SOCKET_FLOAT, 1.45f); add_output("Fac", SHADER_SOCKET_FLOAT); } @@ -2705,7 +2748,7 @@ void FresnelNode::compile(OSLCompiler& compiler) LayerWeightNode::LayerWeightNode() : ShaderNode("LayerWeight") { - add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true); + add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); add_input("Blend", SHADER_SOCKET_FLOAT, 0.5f); add_output("Fresnel", SHADER_SOCKET_FLOAT); @@ -3080,7 +3123,7 @@ NormalMapNode::NormalMapNode() space = ustring("Tangent"); attribute = ustring(""); - add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true); + add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f); add_input("Color", SHADER_SOCKET_COLOR); @@ -3185,7 +3228,7 @@ TangentNode::TangentNode() axis = ustring("X"); attribute = ustring(""); - add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true); + add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL); add_output("Tangent", SHADER_SOCKET_NORMAL); } diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 3e89c2286ad..67733142dd1 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -351,6 +351,11 @@ public: SHADER_NODE_CLASS(MixClosureNode) }; +class MixClosureWeightNode : public ShaderNode { +public: + SHADER_NODE_CLASS(MixClosureWeightNode); +}; + class InvertNode : public ShaderNode { public: SHADER_NODE_CLASS(InvertNode) diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index 73904eac41d..50b3bb59ed4 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -487,106 +487,30 @@ void SVMCompiler::generate_closure(ShaderNode *node, set& done) } } -void SVMCompiler::count_closure_users(ShaderNode *node, map& closure_data) -{ - /* here we count the number of times each closure node is used, so that - * the last time we encounter it we can run the actually code with the - * weights from all other places added together */ - - if(node->name == ustring("mix_closure") || node->name == ustring("add_closure")) { - ShaderInput *cl1in = node->input("Closure1"); - ShaderInput *cl2in = node->input("Closure2"); - - if(cl1in->link) - count_closure_users(cl1in->link->parent, closure_data); - if(cl2in->link) - count_closure_users(cl2in->link->parent, closure_data); - } - else { - MultiClosureData data; - - if(closure_data.find(node) == closure_data.end()) { - data.stack_offset = SVM_STACK_INVALID; - data.users = 1; - } - else { - data = closure_data[node]; - data.users++; - } - - closure_data[node] = data; - } -} - -void SVMCompiler::generate_multi_closure(ShaderNode *node, set& done, - map& closure_data, uint in_offset) +void SVMCompiler::generate_multi_closure(ShaderNode *node, set& done) { /* todo: the weaks point here is that unlike the single closure sampling * we will evaluate all nodes even if they are used as input for closures * that are unused. it's not clear what would be the best way to skip such * nodes at runtime, especially if they are tangled up */ + + /* only generate once */ + if(done.find(node) != done.end()) + return; + + done.insert(node); if(node->name == ustring("mix_closure") || node->name == ustring("add_closure")) { - ShaderInput *fin = node->input("Fac"); + /* weighting is already taken care of in ShaderGraph::transform_multi_closure */ ShaderInput *cl1in = node->input("Closure1"); ShaderInput *cl2in = node->input("Closure2"); - uint out1_offset = SVM_STACK_INVALID; - uint out2_offset = SVM_STACK_INVALID; - - if(fin) { - /* mix closure */ - set dependencies; - find_dependencies(dependencies, done, fin); - generate_svm_nodes(dependencies, done); - - stack_assign(fin); - - if(cl1in->link) - out1_offset = stack_find_offset(SHADER_SOCKET_FLOAT); - if(cl2in->link) - out2_offset = stack_find_offset(SHADER_SOCKET_FLOAT); - - add_node(NODE_MIX_CLOSURE, - encode_uchar4(fin->stack_offset, in_offset, out1_offset, out2_offset)); - } - else { - /* add closure */ - out1_offset = in_offset; - out2_offset = in_offset; - } - if(cl1in->link) - generate_multi_closure(cl1in->link->parent, done, closure_data, out1_offset); - + generate_multi_closure(cl1in->link->parent, done); if(cl2in->link) - generate_multi_closure(cl2in->link->parent, done, closure_data, out2_offset); - - if(in_offset != SVM_STACK_INVALID) - stack_clear_offset(SHADER_SOCKET_FLOAT, in_offset); + generate_multi_closure(cl2in->link->parent, done); } else { - MultiClosureData data = closure_data[node]; - - if(data.stack_offset == SVM_STACK_INVALID) { - /* first time using closure, use stack position for weight */ - data.stack_offset = in_offset; - } - else { - /* not first time using, add weights together */ - add_node(NODE_MATH, NODE_MATH_ADD, data.stack_offset, in_offset); - add_node(NODE_MATH, data.stack_offset); - - stack_clear_offset(SHADER_SOCKET_FLOAT, in_offset); - } - - data.users--; - closure_data[node] = data; - - /* still users coming? skip generating closure code */ - if(data.users > 0) - return; - /* execute dependencies for closure */ foreach(ShaderInput *in, node->inputs) { if(!node_skip_input(node, in) && in->link) { @@ -596,7 +520,16 @@ void SVMCompiler::generate_multi_closure(ShaderNode *node, set& don } } - mix_weight_offset = data.stack_offset; + /* closure mix weight */ + const char *weight_name = (current_type == SHADER_TYPE_VOLUME)? "VolumeMixWeight": "SurfaceMixWeight"; + ShaderInput *weight_in = node->input(weight_name); + + if(weight_in && (weight_in->link || weight_in->value.x != 1.0f)) { + stack_assign(weight_in); + mix_weight_offset = weight_in->stack_offset; + } + else + mix_weight_offset = SVM_STACK_INVALID; /* compile closure itself */ node->compile(*this); @@ -609,11 +542,6 @@ void SVMCompiler::generate_multi_closure(ShaderNode *node, set& don current_shader->has_surface_emission = true; if(node->name == ustring("transparent")) current_shader->has_surface_transparent = true; - - /* end node is added outside of this */ - - if(data.stack_offset != SVM_STACK_INVALID) - stack_clear_offset(SHADER_SOCKET_FLOAT, data.stack_offset); } } @@ -685,12 +613,8 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty if(generate) { set done; - if(use_multi_closure) { - map closure_data; - - count_closure_users(clin->link->parent, closure_data); - generate_multi_closure(clin->link->parent, done, closure_data, SVM_STACK_INVALID); - } + if(use_multi_closure) + generate_multi_closure(clin->link->parent, done); else generate_closure(clin->link->parent, done); } @@ -713,9 +637,9 @@ void SVMCompiler::compile(Shader *shader, vector& global_svm_nodes, int in shader->graph_bump = shader->graph->copy(); /* finalize */ - shader->graph->finalize(false, false); + shader->graph->finalize(false, false, use_multi_closure); if(shader->graph_bump) - shader->graph_bump->finalize(true, false); + shader->graph_bump->finalize(true, false, use_multi_closure); current_shader = shader; diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h index c7b66d97289..720531c8c4b 100644 --- a/intern/cycles/render/svm.h +++ b/intern/cycles/render/svm.h @@ -130,14 +130,7 @@ protected: void generate_closure(ShaderNode *node, set& done); /* multi closure */ - struct MultiClosureData { - int stack_offset; - int users; - }; - - void generate_multi_closure(ShaderNode *node, set& done, - map& closure_data, uint in_offset); - void count_closure_users(ShaderNode *node, map& closure_data); + void generate_multi_closure(ShaderNode *node, set& done); /* compile */ void compile_type(Shader *shader, ShaderGraph *graph, ShaderType type);