Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/intern
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2012-11-27 01:59:41 +0400
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2012-11-27 01:59:41 +0400
commitceed3ef640bb40e1232feeb409220fe19011bc43 (patch)
tree48ad960f483ad185718b14bbc605b6182732f56c /intern
parenteab58bf994323a53311543d7d706b0be87ffe197 (diff)
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.
Diffstat (limited to 'intern')
-rw-r--r--intern/cycles/kernel/svm/svm_closure.h225
-rw-r--r--intern/cycles/render/graph.cpp104
-rw-r--r--intern/cycles/render/graph.h17
-rw-r--r--intern/cycles/render/nodes.cpp59
-rw-r--r--intern/cycles/render/nodes.h5
-rw-r--r--intern/cycles/render/svm.cpp124
-rw-r--r--intern/cycles/render/svm.h9
7 files changed, 318 insertions, 225 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);
-
- /* 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);
+ ShaderClosure *sc = svm_node_closure_get_weight(sd, mix_weight);
+
+ 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);
-
- 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);
+ ShaderClosure *sc = svm_node_closure_get_weight(sd, mix_weight);
+
+ if(sc) {
+ sc->N = N;
+ sc->data0 = param1;
+
+ 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);
- /* refraction */
- sc = svm_node_closure_get(sd);
- sc->N = N;
+ if(sc) {
+ sc->N = N;
+ svm_node_glass_setup(sd, sc, type, eta, roughness, false);
+ }
+ /* refraction */
+ 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);
-#else
- ShaderClosure *sc = svm_node_closure_get(sd);
- sc->N = N;
+ sc = svm_node_closure_get_weight(sd, mix_weight*(1.0f - fresnel));
- bool refract = (randb > fresnel);
+ if(sc) {
+ sc->N = N;
+ svm_node_glass_setup(sd, sc, type, eta, roughness, true);
+ }
+#else
+ ShaderClosure *sc = svm_node_closure_get_weight(sd, mix_weight);
- 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<ShaderNode* const, ShaderNode*> 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<ShaderNode*>& done)
}
}
-void SVMCompiler::count_closure_users(ShaderNode *node, map<ShaderNode*, MultiClosureData>& 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<ShaderNode*>& done,
- map<ShaderNode*, MultiClosureData>& closure_data, uint in_offset)
+void SVMCompiler::generate_multi_closure(ShaderNode *node, set<ShaderNode*>& 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<ShaderNode*> 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<ShaderNode*>& 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<ShaderNode*>& 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<ShaderNode*> done;
- if(use_multi_closure) {
- map<ShaderNode*, MultiClosureData> 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<int4>& 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<ShaderNode*>& done);
/* multi closure */
- struct MultiClosureData {
- int stack_offset;
- int users;
- };
-
- void generate_multi_closure(ShaderNode *node, set<ShaderNode*>& done,
- map<ShaderNode*,MultiClosureData>& closure_data, uint in_offset);
- void count_closure_users(ShaderNode *node, map<ShaderNode*, MultiClosureData>& closure_data);
+ void generate_multi_closure(ShaderNode *node, set<ShaderNode*>& done);
/* compile */
void compile_type(Shader *shader, ShaderGraph *graph, ShaderType type);