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

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

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

View File

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

View File

@ -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);
}

View File

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

View File

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

View File

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