Changeset View
Standalone View
intern/cycles/render/nodes.cpp
| Show All 16 Lines | |||||
| #include "image.h" | #include "image.h" | ||||
| #include "integrator.h" | #include "integrator.h" | ||||
| #include "nodes.h" | #include "nodes.h" | ||||
| #include "scene.h" | #include "scene.h" | ||||
| #include "svm.h" | #include "svm.h" | ||||
| #include "svm_color_util.h" | #include "svm_color_util.h" | ||||
| #include "svm_math_util.h" | #include "svm_math_util.h" | ||||
| #include "osl.h" | #include "osl.h" | ||||
| #include "constant_fold.h" | |||||
| #include "util_sky_model.h" | #include "util_sky_model.h" | ||||
| #include "util_foreach.h" | #include "util_foreach.h" | ||||
| #include "util_transform.h" | #include "util_transform.h" | ||||
| CCL_NAMESPACE_BEGIN | CCL_NAMESPACE_BEGIN | ||||
| /* Texture Mapping */ | /* Texture Mapping */ | ||||
| #define TEXTURE_MAPPING_DEFINE(TextureNode) \ | #define TEXTURE_MAPPING_DEFINE(TextureNode) \ | ||||
sergey: Arguably, should it actually be a function or a method of `Graph` / `ShaderNode` /… | |||||
Not Done Inline Actions
Actually, links are removed by the main constant folding function if constant_fold returned true, so at this point there definitely are links. The main function also copies the value to other sibling users from this one ShaderInput that was directly set here. This does feel a bit weird so maybe now there's fold_as_value, it should do all that stuff instead?.. angavrilov: > We might add extra sanity checks there like `assert… | |||||
| SOCKET_POINT(tex_mapping.translation, "Translation", make_float3(0.0f, 0.0f, 0.0f)); \ | SOCKET_POINT(tex_mapping.translation, "Translation", make_float3(0.0f, 0.0f, 0.0f)); \ | ||||
| SOCKET_VECTOR(tex_mapping.rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f)); \ | SOCKET_VECTOR(tex_mapping.rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f)); \ | ||||
| SOCKET_VECTOR(tex_mapping.scale, "Scale", make_float3(1.0f, 1.0f, 1.0f)); \ | SOCKET_VECTOR(tex_mapping.scale, "Scale", make_float3(1.0f, 1.0f, 1.0f)); \ | ||||
| \ | \ | ||||
| SOCKET_VECTOR(tex_mapping.min, "Min", make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); \ | SOCKET_VECTOR(tex_mapping.min, "Min", make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); \ | ||||
| SOCKET_VECTOR(tex_mapping.max, "Max", make_float3(FLT_MAX, FLT_MAX, FLT_MAX)); \ | SOCKET_VECTOR(tex_mapping.max, "Max", make_float3(FLT_MAX, FLT_MAX, FLT_MAX)); \ | ||||
| SOCKET_BOOLEAN(tex_mapping.use_minmax, "Use Min Max", false); \ | SOCKET_BOOLEAN(tex_mapping.use_minmax, "Use Min Max", false); \ | ||||
| \ | \ | ||||
| ▲ Show 20 Lines • Show All 1,528 Lines • ▼ Show 20 Lines | NODE_DEFINE(RGBToBWNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| RGBToBWNode::RGBToBWNode() | RGBToBWNode::RGBToBWNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool RGBToBWNode::constant_fold(ShaderGraph * /*graph*/, | void RGBToBWNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput * /*socket*/, | |||||
| ShaderInput *optimized) | |||||
| { | { | ||||
| if(all_inputs_constant()) { | if(folder.all_inputs_constant()) { | ||||
| optimized->set(linear_rgb_to_gray(color)); | folder.make_constant(linear_rgb_to_gray(color)); | ||||
Not Done Inline ActionsIs it a nifty way to save one line of code with a searate return? Feel weird about reutning a void value. And either having memory glitch, or some compilers might generate warning? sergey: Is it a nifty way to save one line of code with a searate return?
Feel weird about reutning a… | |||||
Not Done Inline ActionsIt's valid C++, but since it's causing confusion I'll change it. brecht: It's valid C++, but since it's causing confusion I'll change it. | |||||
Not Done Inline ActionsInteresting. Coz i remember having issues with such (or similar but more tricky?) case. If it's valid, i'm not fussed at all. But code after changes i like more, since it leaves no room to confusion. sergey: Interesting. Coz i remember having issues with such (or similar but more tricky?) case.
If… | |||||
| return true; | |||||
| } | } | ||||
| return false; | |||||
| } | } | ||||
| void RGBToBWNode::compile(SVMCompiler& compiler) | void RGBToBWNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| compiler.add_node(NODE_CONVERT, | compiler.add_node(NODE_CONVERT, | ||||
| NODE_CONVERT_CF, | NODE_CONVERT_CF, | ||||
| compiler.stack_assign(inputs[0]), | compiler.stack_assign(inputs[0]), | ||||
| compiler.stack_assign(outputs[0])); | compiler.stack_assign(outputs[0])); | ||||
| ▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | : ShaderNode(node_types[from_][to_]) | ||||
| to = to_; | to = to_; | ||||
| if(from == to) | if(from == to) | ||||
| special_type = SHADER_SPECIAL_TYPE_PROXY; | special_type = SHADER_SPECIAL_TYPE_PROXY; | ||||
| else if(autoconvert) | else if(autoconvert) | ||||
| special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT; | special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT; | ||||
| } | } | ||||
| bool ConvertNode::constant_fold(ShaderGraph * /*graph*/, | void ConvertNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput * /*socket*/, | |||||
| ShaderInput *optimized) | |||||
| { | { | ||||
| /* proxy nodes should have been removed at this point */ | /* proxy nodes should have been removed at this point */ | ||||
| assert(special_type != SHADER_SPECIAL_TYPE_PROXY); | assert(special_type != SHADER_SPECIAL_TYPE_PROXY); | ||||
| /* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */ | /* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */ | ||||
| if(all_inputs_constant()) { | if(folder.all_inputs_constant()) { | ||||
| if(from == SocketType::FLOAT) { | if(from == SocketType::FLOAT) { | ||||
| if(SocketType::is_float3(to)) { | if(SocketType::is_float3(to)) { | ||||
| optimized->set(make_float3(value_float, value_float, value_float)); | folder.make_constant(make_float3(value_float, value_float, value_float)); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| else if(SocketType::is_float3(from)) { | else if(SocketType::is_float3(from)) { | ||||
| if(to == SocketType::FLOAT) { | if(to == SocketType::FLOAT) { | ||||
| if(from == SocketType::COLOR) | if(from == SocketType::COLOR) { | ||||
| /* color to float */ | /* color to float */ | ||||
| optimized->set(linear_rgb_to_gray(value_color)); | folder.make_constant(linear_rgb_to_gray(value_color)); | ||||
| else | } | ||||
| else { | |||||
| /* vector/point/normal to float */ | /* vector/point/normal to float */ | ||||
| optimized->set(average(value_vector)); | folder.make_constant(average(value_vector)); | ||||
| return true; | } | ||||
| } | } | ||||
| else if(SocketType::is_float3(to)) { | else if(SocketType::is_float3(to)) { | ||||
| optimized->set(value_color); | folder.make_constant(value_color); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | |||||
| } | } | ||||
| void ConvertNode::compile(SVMCompiler& compiler) | void ConvertNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| /* proxy nodes should have been removed at this point */ | /* proxy nodes should have been removed at this point */ | ||||
| assert(special_type != SHADER_SPECIAL_TYPE_PROXY); | assert(special_type != SHADER_SPECIAL_TYPE_PROXY); | ||||
| ShaderInput *in = inputs[0]; | ShaderInput *in = inputs[0]; | ||||
| ▲ Show 20 Lines • Show All 653 Lines • ▼ Show 20 Lines | void EmissionNode::compile(SVMCompiler& compiler) | ||||
| compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset()); | compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset()); | ||||
| } | } | ||||
| void EmissionNode::compile(OSLCompiler& compiler) | void EmissionNode::compile(OSLCompiler& compiler) | ||||
| { | { | ||||
| compiler.add(this, "node_emission"); | compiler.add(this, "node_emission"); | ||||
| } | } | ||||
| bool EmissionNode::constant_fold(ShaderGraph * /*graph*/, | void EmissionNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput * /*socket*/, | |||||
| ShaderInput * /*optimized*/) | |||||
| { | { | ||||
| ShaderInput *color_in = input("Color"); | ShaderInput *color_in = input("Color"); | ||||
| ShaderInput *strength_in = input("Strength"); | ShaderInput *strength_in = input("Strength"); | ||||
| return ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || | if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || | ||||
| (!strength_in->link && strength == 0.0f)); | (!strength_in->link && strength == 0.0f)) { | ||||
| folder.discard(); | |||||
| } | |||||
| } | } | ||||
| /* Background Closure */ | /* Background Closure */ | ||||
| NODE_DEFINE(BackgroundNode) | NODE_DEFINE(BackgroundNode) | ||||
| { | { | ||||
| NodeType* type = NodeType::add("background_shader", create, NodeType::SHADER); | NodeType* type = NodeType::add("background_shader", create, NodeType::SHADER); | ||||
| Show All 27 Lines | void BackgroundNode::compile(SVMCompiler& compiler) | ||||
| compiler.add_node(NODE_CLOSURE_BACKGROUND, compiler.closure_mix_weight_offset()); | compiler.add_node(NODE_CLOSURE_BACKGROUND, compiler.closure_mix_weight_offset()); | ||||
| } | } | ||||
| void BackgroundNode::compile(OSLCompiler& compiler) | void BackgroundNode::compile(OSLCompiler& compiler) | ||||
| { | { | ||||
| compiler.add(this, "node_background"); | compiler.add(this, "node_background"); | ||||
| } | } | ||||
| bool BackgroundNode::constant_fold(ShaderGraph * /*graph*/, | void BackgroundNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput * /*socket*/, | |||||
| ShaderInput * /*optimized*/) | |||||
| { | { | ||||
| ShaderInput *color_in = input("Color"); | ShaderInput *color_in = input("Color"); | ||||
| ShaderInput *strength_in = input("Strength"); | ShaderInput *strength_in = input("Strength"); | ||||
| return ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || | if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || | ||||
| (!strength_in->link && strength == 0.0f)); | (!strength_in->link && strength == 0.0f)) { | ||||
| folder.discard(); | |||||
| } | |||||
| } | } | ||||
| /* Holdout Closure */ | /* Holdout Closure */ | ||||
| NODE_DEFINE(HoldoutNode) | NODE_DEFINE(HoldoutNode) | ||||
| { | { | ||||
| NodeType* type = NodeType::add("holdout", create, NodeType::SHADER); | NodeType* type = NodeType::add("holdout", create, NodeType::SHADER); | ||||
| ▲ Show 20 Lines • Show All 945 Lines • ▼ Show 20 Lines | NODE_DEFINE(ValueNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| ValueNode::ValueNode() | ValueNode::ValueNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool ValueNode::constant_fold(ShaderGraph * /*graph*/, | void ValueNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput * /*socket*/, | |||||
| ShaderInput *optimized) | |||||
| { | { | ||||
| optimized->set(value); | folder.make_constant(value); | ||||
| return true; | |||||
| } | } | ||||
| void ValueNode::compile(SVMCompiler& compiler) | void ValueNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderOutput *val_out = output("Value"); | ShaderOutput *val_out = output("Value"); | ||||
| compiler.add_node(NODE_VALUE_F, __float_as_int(value), compiler.stack_assign(val_out)); | compiler.add_node(NODE_VALUE_F, __float_as_int(value), compiler.stack_assign(val_out)); | ||||
| } | } | ||||
| Show All 16 Lines | NODE_DEFINE(ColorNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| ColorNode::ColorNode() | ColorNode::ColorNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool ColorNode::constant_fold(ShaderGraph * /*graph*/, | void ColorNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput * /*socket*/, | |||||
| ShaderInput *optimized) | |||||
| { | { | ||||
| optimized->set(value); | folder.make_constant(value); | ||||
| return true; | |||||
| } | } | ||||
| void ColorNode::compile(SVMCompiler& compiler) | void ColorNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderOutput *color_out = output("Color"); | ShaderOutput *color_out = output("Color"); | ||||
| if(!color_out->links.empty()) { | if(!color_out->links.empty()) { | ||||
| compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out)); | compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out)); | ||||
| Show All 32 Lines | void AddClosureNode::compile(SVMCompiler& /*compiler*/) | ||||
| /* handled in the SVM compiler */ | /* handled in the SVM compiler */ | ||||
| } | } | ||||
| void AddClosureNode::compile(OSLCompiler& compiler) | void AddClosureNode::compile(OSLCompiler& compiler) | ||||
| { | { | ||||
| compiler.add(this, "node_add_closure"); | compiler.add(this, "node_add_closure"); | ||||
| } | } | ||||
| void AddClosureNode::constant_fold(const ConstantFolder& folder) | |||||
| { | |||||
| ShaderInput *closure1_in = input("Closure1"); | |||||
| ShaderInput *closure2_in = input("Closure2"); | |||||
| /* remove useless add closures nodes */ | |||||
| if(!closure1_in->link) { | |||||
| folder.bypass_or_discard(closure2_in); | |||||
| } | |||||
| else if(!closure2_in->link) { | |||||
| folder.bypass_or_discard(closure1_in); | |||||
| } | |||||
| } | |||||
| /* Mix Closure */ | /* Mix Closure */ | ||||
| NODE_DEFINE(MixClosureNode) | NODE_DEFINE(MixClosureNode) | ||||
| { | { | ||||
| NodeType* type = NodeType::add("mix_closure", create, NodeType::SHADER); | NodeType* type = NodeType::add("mix_closure", create, NodeType::SHADER); | ||||
| SOCKET_IN_FLOAT(fac, "Fac", 0.5f); | SOCKET_IN_FLOAT(fac, "Fac", 0.5f); | ||||
| SOCKET_IN_CLOSURE(closure1, "Closure1"); | SOCKET_IN_CLOSURE(closure1, "Closure1"); | ||||
| Show All 15 Lines | void MixClosureNode::compile(SVMCompiler& /*compiler*/) | ||||
| /* handled in the SVM compiler */ | /* handled in the SVM compiler */ | ||||
| } | } | ||||
| void MixClosureNode::compile(OSLCompiler& compiler) | void MixClosureNode::compile(OSLCompiler& compiler) | ||||
| { | { | ||||
| compiler.add(this, "node_mix_closure"); | compiler.add(this, "node_mix_closure"); | ||||
| } | } | ||||
| bool MixClosureNode::constant_fold(ShaderGraph *graph, | void MixClosureNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput * /*socket*/, | |||||
| ShaderInput * /*optimized*/) | |||||
| { | { | ||||
| ShaderInput *fac_in = input("Fac"); | ShaderInput *fac_in = input("Fac"); | ||||
| ShaderInput *closure1_in = input("Closure1"); | ShaderInput *closure1_in = input("Closure1"); | ||||
| ShaderInput *closure2_in = input("Closure2"); | ShaderInput *closure2_in = input("Closure2"); | ||||
| ShaderOutput *closure_out = output("Closure"); | |||||
| /* remove useless mix closures nodes */ | /* remove useless mix closures nodes */ | ||||
| if(closure1_in->link == closure2_in->link) { | if(closure1_in->link == closure2_in->link) { | ||||
| graph->relink(this, closure_out, closure1_in->link); | folder.bypass_or_discard(closure1_in); | ||||
| return true; | |||||
| } | } | ||||
| /* remove unused mix closure input when factor is 0.0 or 1.0 | |||||
| /* remove unused mix closure input when factor is 0.0 or 1.0 */ | * check for closure links and make sure factor link is disconnected */ | ||||
| /* check for closure links and make sure factor link is disconnected */ | else if(!fac_in->link) { | ||||
| if(closure1_in->link && closure2_in->link && !fac_in->link) { | |||||
| /* factor 0.0 */ | /* factor 0.0 */ | ||||
| if(fac == 0.0f) { | if(fac <= 0.0f) { | ||||
| graph->relink(this, closure_out, closure1_in->link); | folder.bypass_or_discard(closure1_in); | ||||
| return true; | |||||
| } | } | ||||
| /* factor 1.0 */ | /* factor 1.0 */ | ||||
| else if(fac == 1.0f) { | else if(fac >= 1.0f) { | ||||
| graph->relink(this, closure_out, closure2_in->link); | folder.bypass_or_discard(closure2_in); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| return false; | |||||
| } | } | ||||
| /* Mix Closure */ | /* Mix Closure */ | ||||
| NODE_DEFINE(MixClosureWeightNode) | NODE_DEFINE(MixClosureWeightNode) | ||||
| { | { | ||||
| NodeType* type = NodeType::add("mix_closure_weight", create, NodeType::SHADER); | NodeType* type = NodeType::add("mix_closure_weight", create, NodeType::SHADER); | ||||
| ▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | NODE_DEFINE(InvertNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| InvertNode::InvertNode() | InvertNode::InvertNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool InvertNode::constant_fold(ShaderGraph *graph, | void InvertNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput * /*socket*/, | |||||
| ShaderInput *optimized) | |||||
| { | { | ||||
| ShaderInput *fac_in = input("Fac"); | ShaderInput *fac_in = input("Fac"); | ||||
| ShaderInput *color_in = input("Color"); | ShaderInput *color_in = input("Color"); | ||||
| ShaderOutput *color_out = output("Color"); | |||||
| if(!fac_in->link) { | if(!fac_in->link) { | ||||
| /* evaluate fully constant node */ | /* evaluate fully constant node */ | ||||
| if(!color_in->link) { | if(!color_in->link) { | ||||
| optimized->set(interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac)); | folder.make_constant(interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac)); | ||||
| return true; | |||||
| } | } | ||||
| /* remove no-op node */ | /* remove no-op node */ | ||||
| else if(fac == 0.0f) { | else if(fac == 0.0f) { | ||||
| graph->relink(this, color_out, color_in->link); | folder.bypass(color_in->link); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| return false; | |||||
| } | } | ||||
| void InvertNode::compile(SVMCompiler& compiler) | void InvertNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *fac_in = input("Fac"); | ShaderInput *fac_in = input("Fac"); | ||||
| ShaderInput *color_in = input("Color"); | ShaderInput *color_in = input("Color"); | ||||
| ShaderOutput *color_out = output("Color"); | ShaderOutput *color_out = output("Color"); | ||||
| ▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | |||||
| void MixNode::compile(OSLCompiler& compiler) | void MixNode::compile(OSLCompiler& compiler) | ||||
| { | { | ||||
| compiler.parameter(this, "type"); | compiler.parameter(this, "type"); | ||||
| compiler.parameter(this, "use_clamp"); | compiler.parameter(this, "use_clamp"); | ||||
| compiler.add(this, "node_mix"); | compiler.add(this, "node_mix"); | ||||
| } | } | ||||
| bool MixNode::constant_fold(ShaderGraph *graph, | void MixNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput * /*socket*/, | |||||
| ShaderInput *optimized) | |||||
| { | { | ||||
| ShaderInput *fac_in = input("Fac"); | ShaderInput *fac_in = input("Fac"); | ||||
| ShaderInput *color1_in = input("Color1"); | ShaderInput *color1_in = input("Color1"); | ||||
| ShaderInput *color2_in = input("Color2"); | ShaderInput *color2_in = input("Color2"); | ||||
| ShaderOutput *color_out = output("Color"); | |||||
| /* evaluate fully constant node */ | /* evaluate fully constant node */ | ||||
| if(all_inputs_constant()) { | if(folder.all_inputs_constant()) { | ||||
| float3 result = svm_mix(type, fac, color1, color2); | folder.make_constant_clamp(svm_mix(type, fac, color1, color2), use_clamp); | ||||
| optimized->set(use_clamp ? svm_mix_clamp(result) : result); | return; | ||||
| return true; | |||||
| } | } | ||||
| /* remove no-op node when factor is 0.0 */ | /* remove no-op node when factor is 0.0 */ | ||||
| if(!fac_in->link && fac <= 0.0f) { | if(!fac_in->link && fac <= 0.0f) { | ||||
| /* note that some of the modes will clamp out of bounds values even without use_clamp */ | /* note that some of the modes will clamp out of bounds values even without use_clamp */ | ||||
| if(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN) { | |||||
| if(!color1_in->link) { | if(!color1_in->link) { | ||||
| float3 result = svm_mix(type, 0.0f, color1, color1); | folder.make_constant_clamp(svm_mix(type, 0.0f, color1, color1), use_clamp); | ||||
| optimized->set(use_clamp ? svm_mix_clamp(result) : result); | return; | ||||
| return true; | |||||
| } | } | ||||
| else if(!use_clamp && type != NODE_MIX_LIGHT && type != NODE_MIX_DODGE && type != NODE_MIX_BURN) { | |||||
| graph->relink(this, color_out, color1_in->link); | |||||
| return true; | |||||
| } | } | ||||
| else if(folder.try_bypass_or_make_constant(color1_in, color1, use_clamp)) { | |||||
| return; | |||||
| } | } | ||||
| if(type != NODE_MIX_BLEND) { | |||||
| return false; | |||||
| } | } | ||||
| if(type == NODE_MIX_BLEND) { | |||||
| /* remove useless mix colors nodes */ | /* remove useless mix colors nodes */ | ||||
| if(color1_in->link && color1_in->link == color2_in->link && !use_clamp) { | if(color1_in->link ? (color1_in->link == color2_in->link) : (!color2_in->link && color1 == color2)) { | ||||
| graph->relink(this, color_out, color1_in->link); | if(folder.try_bypass_or_make_constant(color1_in, color1, use_clamp)) { | ||||
| return true; | return; | ||||
| } | } | ||||
| if(!color1_in->link && !color2_in->link && color1 == color2) { | |||||
| optimized->set(use_clamp ? svm_mix_clamp(color1) : color1); | |||||
| return true; | |||||
| } | } | ||||
| /* remove no-op mix color node when factor is 1.0 */ | /* remove no-op mix color node when factor is 1.0 */ | ||||
| if(!fac_in->link && fac >= 1.0f) { | if(!fac_in->link && fac >= 1.0f) { | ||||
| if(!color2_in->link) { | if(folder.try_bypass_or_make_constant(color2_in, color2, use_clamp)) { | ||||
| optimized->set(use_clamp ? svm_mix_clamp(color2) : color2); | return; | ||||
| return true; | |||||
| } | } | ||||
| else if(!use_clamp) { | |||||
| graph->relink(this, color_out, color2_in->link); | |||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| return false; | |||||
| } | } | ||||
| /* Combine RGB */ | /* Combine RGB */ | ||||
| NODE_DEFINE(CombineRGBNode) | NODE_DEFINE(CombineRGBNode) | ||||
| { | { | ||||
| NodeType* type = NodeType::add("combine_rgb", create, NodeType::SHADER); | NodeType* type = NodeType::add("combine_rgb", create, NodeType::SHADER); | ||||
| SOCKET_IN_FLOAT(r, "R", 0.0f); | SOCKET_IN_FLOAT(r, "R", 0.0f); | ||||
| SOCKET_IN_FLOAT(g, "G", 0.0f); | SOCKET_IN_FLOAT(g, "G", 0.0f); | ||||
| SOCKET_IN_FLOAT(b, "B", 0.0f); | SOCKET_IN_FLOAT(b, "B", 0.0f); | ||||
| SOCKET_OUT_COLOR(image, "Image"); | SOCKET_OUT_COLOR(image, "Image"); | ||||
| return type; | return type; | ||||
| } | } | ||||
| CombineRGBNode::CombineRGBNode() | CombineRGBNode::CombineRGBNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool CombineRGBNode::constant_fold(ShaderGraph * /*graph*/, | void CombineRGBNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput * /*socket*/, | |||||
| ShaderInput *optimized) | |||||
| { | { | ||||
| if(all_inputs_constant()) { | if(folder.all_inputs_constant()) { | ||||
| optimized->set(make_float3(r, g, b)); | folder.make_constant(make_float3(r, g, b)); | ||||
| return true; | |||||
| } | } | ||||
| return false; | |||||
| } | } | ||||
| void CombineRGBNode::compile(SVMCompiler& compiler) | void CombineRGBNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *red_in = input("R"); | ShaderInput *red_in = input("R"); | ||||
| ShaderInput *green_in = input("G"); | ShaderInput *green_in = input("G"); | ||||
| ShaderInput *blue_in = input("B"); | ShaderInput *blue_in = input("B"); | ||||
| ShaderOutput *color_out = output("Image"); | ShaderOutput *color_out = output("Image"); | ||||
| Show All 31 Lines | NODE_DEFINE(CombineXYZNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| CombineXYZNode::CombineXYZNode() | CombineXYZNode::CombineXYZNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool CombineXYZNode::constant_fold(ShaderGraph * /*graph*/, | void CombineXYZNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput * /*socket*/, | |||||
| ShaderInput *optimized) | |||||
| { | { | ||||
| if(all_inputs_constant()) { | if(folder.all_inputs_constant()) { | ||||
| optimized->set(make_float3(x, y, z)); | folder.make_constant(make_float3(x, y, z)); | ||||
| return true; | |||||
| } | } | ||||
| return false; | |||||
| } | } | ||||
| void CombineXYZNode::compile(SVMCompiler& compiler) | void CombineXYZNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *x_in = input("X"); | ShaderInput *x_in = input("X"); | ||||
| ShaderInput *y_in = input("Y"); | ShaderInput *y_in = input("Y"); | ||||
| ShaderInput *z_in = input("Z"); | ShaderInput *z_in = input("Z"); | ||||
| ShaderOutput *vector_out = output("Vector"); | ShaderOutput *vector_out = output("Vector"); | ||||
| Show All 31 Lines | NODE_DEFINE(CombineHSVNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| CombineHSVNode::CombineHSVNode() | CombineHSVNode::CombineHSVNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool CombineHSVNode::constant_fold(ShaderGraph * /*graph*/, | void CombineHSVNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput * /*socket*/, | |||||
| ShaderInput *optimized) | |||||
| { | { | ||||
| if(all_inputs_constant()) { | if(folder.all_inputs_constant()) { | ||||
| optimized->set(hsv_to_rgb(make_float3(h, s, v))); | folder.make_constant(hsv_to_rgb(make_float3(h, s, v))); | ||||
| return true; | |||||
| } | } | ||||
| return false; | |||||
| } | } | ||||
| void CombineHSVNode::compile(SVMCompiler& compiler) | void CombineHSVNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *hue_in = input("H"); | ShaderInput *hue_in = input("H"); | ||||
| ShaderInput *saturation_in = input("S"); | ShaderInput *saturation_in = input("S"); | ||||
| ShaderInput *value_in = input("V"); | ShaderInput *value_in = input("V"); | ||||
| ShaderOutput *color_out = output("Color"); | ShaderOutput *color_out = output("Color"); | ||||
| Show All 24 Lines | NODE_DEFINE(GammaNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| GammaNode::GammaNode() | GammaNode::GammaNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool GammaNode::constant_fold(ShaderGraph * /*graph*/, | void GammaNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput * /*socket*/, | |||||
| ShaderInput *optimized) | |||||
| { | { | ||||
| if(all_inputs_constant()) { | if(folder.all_inputs_constant()) { | ||||
| optimized->set(svm_math_gamma_color(color, gamma)); | folder.make_constant(svm_math_gamma_color(color, gamma)); | ||||
| return true; | |||||
| } | } | ||||
| return false; | |||||
| } | } | ||||
| void GammaNode::compile(SVMCompiler& compiler) | void GammaNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *color_in = input("Color"); | ShaderInput *color_in = input("Color"); | ||||
| ShaderInput *gamma_in = input("Gamma"); | ShaderInput *gamma_in = input("Gamma"); | ||||
| ShaderOutput *color_out = output("Color"); | ShaderOutput *color_out = output("Color"); | ||||
| Show All 23 Lines | NODE_DEFINE(BrightContrastNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| BrightContrastNode::BrightContrastNode() | BrightContrastNode::BrightContrastNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool BrightContrastNode::constant_fold(ShaderGraph * /*graph*/, | void BrightContrastNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput * /*socket*/, | |||||
| ShaderInput *optimized) | |||||
| { | { | ||||
| if(all_inputs_constant()) { | if(folder.all_inputs_constant()) { | ||||
| optimized->set(svm_brightness_contrast(color, bright, contrast)); | folder.make_constant(svm_brightness_contrast(color, bright, contrast)); | ||||
| return true; | |||||
| } | } | ||||
| return false; | |||||
| } | } | ||||
| void BrightContrastNode::compile(SVMCompiler& compiler) | void BrightContrastNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *color_in = input("Color"); | ShaderInput *color_in = input("Color"); | ||||
| ShaderInput *bright_in = input("Bright"); | ShaderInput *bright_in = input("Bright"); | ||||
| ShaderInput *contrast_in = input("Contrast"); | ShaderInput *contrast_in = input("Contrast"); | ||||
| ShaderOutput *color_out = output("Color"); | ShaderOutput *color_out = output("Color"); | ||||
| Show All 26 Lines | NODE_DEFINE(SeparateRGBNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| SeparateRGBNode::SeparateRGBNode() | SeparateRGBNode::SeparateRGBNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool SeparateRGBNode::constant_fold(ShaderGraph * /*graph*/, | void SeparateRGBNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput *socket, | |||||
| ShaderInput *optimized) | |||||
| { | { | ||||
| if(all_inputs_constant()) { | if(folder.all_inputs_constant()) { | ||||
| for(int channel = 0; channel < 3; channel++) { | for(int channel = 0; channel < 3; channel++) { | ||||
| if(outputs[channel] == socket) { | if(outputs[channel] == folder.output) { | ||||
| optimized->set(color[channel]); | folder.make_constant(color[channel]); | ||||
| return true; | return; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | |||||
| } | } | ||||
| void SeparateRGBNode::compile(SVMCompiler& compiler) | void SeparateRGBNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *color_in = input("Image"); | ShaderInput *color_in = input("Image"); | ||||
| ShaderOutput *red_out = output("R"); | ShaderOutput *red_out = output("R"); | ||||
| ShaderOutput *green_out = output("G"); | ShaderOutput *green_out = output("G"); | ||||
| ShaderOutput *blue_out = output("B"); | ShaderOutput *blue_out = output("B"); | ||||
| Show All 31 Lines | NODE_DEFINE(SeparateXYZNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| SeparateXYZNode::SeparateXYZNode() | SeparateXYZNode::SeparateXYZNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool SeparateXYZNode::constant_fold(ShaderGraph * /*graph*/, | void SeparateXYZNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput *socket, | |||||
| ShaderInput *optimized) | |||||
| { | { | ||||
| if(all_inputs_constant()) { | if(folder.all_inputs_constant()) { | ||||
| for(int channel = 0; channel < 3; channel++) { | for(int channel = 0; channel < 3; channel++) { | ||||
| if(outputs[channel] == socket) { | if(outputs[channel] == folder.output) { | ||||
| optimized->set(vector[channel]); | folder.make_constant(vector[channel]); | ||||
| return true; | return; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | |||||
| } | } | ||||
| void SeparateXYZNode::compile(SVMCompiler& compiler) | void SeparateXYZNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *vector_in = input("Vector"); | ShaderInput *vector_in = input("Vector"); | ||||
| ShaderOutput *x_out = output("X"); | ShaderOutput *x_out = output("X"); | ||||
| ShaderOutput *y_out = output("Y"); | ShaderOutput *y_out = output("Y"); | ||||
| ShaderOutput *z_out = output("Z"); | ShaderOutput *z_out = output("Z"); | ||||
| Show All 31 Lines | NODE_DEFINE(SeparateHSVNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| SeparateHSVNode::SeparateHSVNode() | SeparateHSVNode::SeparateHSVNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool SeparateHSVNode::constant_fold(ShaderGraph * /*graph*/, | void SeparateHSVNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput *socket, | |||||
| ShaderInput *optimized) | |||||
| { | { | ||||
| if(all_inputs_constant()) { | if(folder.all_inputs_constant()) { | ||||
| float3 hsv = rgb_to_hsv(color); | float3 hsv = rgb_to_hsv(color); | ||||
| for(int channel = 0; channel < 3; channel++) { | for(int channel = 0; channel < 3; channel++) { | ||||
| if(outputs[channel] == socket) { | if(outputs[channel] == folder.output) { | ||||
| optimized->set(hsv[channel]); | folder.make_constant(hsv[channel]); | ||||
| return true; | return; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | |||||
| } | } | ||||
| void SeparateHSVNode::compile(SVMCompiler& compiler) | void SeparateHSVNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *color_in = input("Color"); | ShaderInput *color_in = input("Color"); | ||||
| ShaderOutput *hue_out = output("H"); | ShaderOutput *hue_out = output("H"); | ||||
| ShaderOutput *saturation_out = output("S"); | ShaderOutput *saturation_out = output("S"); | ||||
| ShaderOutput *value_out = output("V"); | ShaderOutput *value_out = output("V"); | ||||
| ▲ Show 20 Lines • Show All 369 Lines • ▼ Show 20 Lines | NODE_DEFINE(BlackbodyNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| BlackbodyNode::BlackbodyNode() | BlackbodyNode::BlackbodyNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool BlackbodyNode::constant_fold(ShaderGraph * /*graph*/, | void BlackbodyNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput * /*socket*/, | |||||
| ShaderInput *optimized) | |||||
| { | { | ||||
| if(all_inputs_constant()) { | if(folder.all_inputs_constant()) { | ||||
| optimized->set(svm_math_blackbody_color(temperature)); | folder.make_constant(svm_math_blackbody_color(temperature)); | ||||
| return true; | |||||
| } | } | ||||
| return false; | |||||
| } | } | ||||
| void BlackbodyNode::compile(SVMCompiler& compiler) | void BlackbodyNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *temperature_in = input("Temperature"); | ShaderInput *temperature_in = input("Temperature"); | ||||
| ShaderOutput *color_out = output("Color"); | ShaderOutput *color_out = output("Color"); | ||||
| compiler.add_node(NODE_BLACKBODY, | compiler.add_node(NODE_BLACKBODY, | ||||
| ▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | NODE_DEFINE(MathNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| MathNode::MathNode() | MathNode::MathNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool MathNode::constant_fold(ShaderGraph * /*graph*/, | void MathNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput * /*socket*/, | { | ||||
| ShaderInput *optimized) | if(folder.all_inputs_constant()) { | ||||
| { | folder.make_constant_clamp(svm_math(type, value1, value2), use_clamp); | ||||
| if(all_inputs_constant()) { | |||||
| float value = svm_math(type, value1, value2); | |||||
| optimized->set(use_clamp ? saturate(value) : value); | |||||
| return true; | |||||
| } | } | ||||
| return false; | |||||
| } | } | ||||
| void MathNode::compile(SVMCompiler& compiler) | void MathNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *value1_in = input("Value1"); | ShaderInput *value1_in = input("Value1"); | ||||
| ShaderInput *value2_in = input("Value2"); | ShaderInput *value2_in = input("Value2"); | ||||
| ShaderOutput *value_out = output("Value"); | ShaderOutput *value_out = output("Value"); | ||||
| Show All 37 Lines | NODE_DEFINE(VectorMathNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| VectorMathNode::VectorMathNode() | VectorMathNode::VectorMathNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool VectorMathNode::constant_fold(ShaderGraph * /*graph*/, | void VectorMathNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput *socket, | |||||
| ShaderInput *optimized) | |||||
| { | { | ||||
| float value; | float value; | ||||
| float3 vector; | float3 vector; | ||||
| if(all_inputs_constant()) { | if(folder.all_inputs_constant()) { | ||||
| svm_vector_math(&value, | svm_vector_math(&value, | ||||
| &vector, | &vector, | ||||
| type, | type, | ||||
| vector1, | vector1, | ||||
| vector2); | vector2); | ||||
| if(socket == output("Value")) { | if(folder.output == output("Value")) { | ||||
| optimized->set(value); | folder.make_constant(value); | ||||
| return true; | |||||
| } | } | ||||
| else if(socket == output("Vector")) { | else if(folder.output == output("Vector")) { | ||||
| optimized->set(vector); | folder.make_constant(vector); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| return false; | |||||
| } | } | ||||
| void VectorMathNode::compile(SVMCompiler& compiler) | void VectorMathNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *vector1_in = input("Vector1"); | ShaderInput *vector1_in = input("Vector1"); | ||||
| ShaderInput *vector2_in = input("Vector2"); | ShaderInput *vector2_in = input("Vector2"); | ||||
| ShaderOutput *value_out = output("Value"); | ShaderOutput *value_out = output("Value"); | ||||
| ShaderOutput *vector_out = output("Vector"); | ShaderOutput *vector_out = output("Vector"); | ||||
| ▲ Show 20 Lines • Show All 117 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| void BumpNode::compile(OSLCompiler& compiler) | void BumpNode::compile(OSLCompiler& compiler) | ||||
| { | { | ||||
| compiler.parameter(this, "invert"); | compiler.parameter(this, "invert"); | ||||
| compiler.add(this, "node_bump"); | compiler.add(this, "node_bump"); | ||||
| } | } | ||||
| bool BumpNode::constant_fold(ShaderGraph *graph, | void BumpNode::constant_fold(const ConstantFolder& folder) | ||||
| ShaderOutput * /*socket*/, | |||||
| ShaderInput * /*optimized*/) | |||||
| { | { | ||||
| ShaderInput *height_in = input("Height"); | ShaderInput *height_in = input("Height"); | ||||
| ShaderInput *normal_in = input("Normal"); | ShaderInput *normal_in = input("Normal"); | ||||
| if(height_in->link == NULL) { | if(height_in->link == NULL) { | ||||
| if(normal_in->link == NULL) { | if(normal_in->link == NULL) { | ||||
| GeometryNode *geom = new GeometryNode(); | GeometryNode *geom = new GeometryNode(); | ||||
| graph->add(geom); | folder.graph->add(geom); | ||||
| graph->relink(this, outputs[0], geom->output("Normal")); | folder.bypass(geom->output("Normal")); | ||||
| } | } | ||||
| else { | else { | ||||
| graph->relink(this, outputs[0], normal_in->link); | folder.bypass(normal_in->link); | ||||
| } | } | ||||
| return true; | |||||
| } | } | ||||
| /* TODO(sergey): Ignore bump with zero strength. */ | /* TODO(sergey): Ignore bump with zero strength. */ | ||||
| return false; | |||||
| } | } | ||||
| /* Curve node */ | /* Curve node */ | ||||
| CurvesNode::CurvesNode(const NodeType *node_type) | CurvesNode::CurvesNode(const NodeType *node_type) | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 436 Lines • Show Last 20 Lines | |||||
Arguably, should it actually be a function or a method of Graph / ShaderNode / ShaderInput?
For now functions will work fine, but making it a method can save us passing some arguments perhaps. Just thinking we can have:
And things like that. We might add extra sanity checks there like assert(there_is_no_connected_links_to_this_input);.
Just an idea which we can do later if this new approach is accepted by everyone.