forked from bartvdbraak/blender
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:
parent
eab58bf994
commit
ceed3ef640
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user