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 *, ShaderOutput *, ShaderInput *optimized) | bool RGBToBWNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| optimized->set(linear_rgb_to_gray(color)); | return folder->make_constant(linear_rgb_to_gray(color)); | ||||
| return true; | |||||
| } | } | ||||
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 false; | 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, | ||||
| ▲ Show 20 Lines • Show All 63 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 *, ShaderOutput *, ShaderInput *optimized) | bool ConvertNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| /* 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(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)); | return 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)); | return 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)); | return folder->make_constant(average(value_vector)); | ||||
| return true; | } | ||||
| } | } | ||||
| else if(SocketType::is_float3(to)) { | else if(SocketType::is_float3(to)) { | ||||
| optimized->set(value_color); | return folder->make_constant(value_color); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void ConvertNode::compile(SVMCompiler& compiler) | void ConvertNode::compile(SVMCompiler& compiler) | ||||
| ▲ Show 20 Lines • Show All 658 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 *, ShaderOutput *, ShaderInput *) | bool EmissionNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| 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)) | ||||
| { | |||||
| return folder->discard_node(); | |||||
| } | |||||
| return false; | |||||
| } | } | ||||
| /* 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 *, ShaderOutput *, ShaderInput *) | bool BackgroundNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| 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)) | ||||
| { | |||||
| return folder->discard_node(); | |||||
| } | |||||
| return false; | |||||
| } | } | ||||
| /* 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 *, ShaderOutput *, ShaderInput *optimized) | bool ValueNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| optimized->set(value); | return 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 *, ShaderOutput *, ShaderInput *optimized) | bool ColorNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| optimized->set(value); | return 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 20 Lines • Show All 63 Lines • ▼ Show 20 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, ShaderOutput *, ShaderInput *) | bool MixClosureNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| 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 && closure1_in->link == closure2_in->link) { | ||||
| graph->relink(this, closure_out, closure1_in->link); | return folder->make_noop(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 */ | ||||
| if(closure1_in->link && closure2_in->link && !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); | return folder->make_noop(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); | return folder->make_noop(closure2_in); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Mix Closure */ | /* Mix Closure */ | ||||
| ▲ Show 20 Lines • Show All 49 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, ShaderOutput *, ShaderInput *optimized) | bool InvertNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| 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)); | return 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); | return folder->make_noop(color_in); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void InvertNode::compile(SVMCompiler& compiler) | void InvertNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 76 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, ShaderOutput *, ShaderInput *optimized) | bool MixNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| 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(all_inputs_constant()) { | ||||
| float3 result = svm_mix(type, fac, color1, color2); | return folder->make_constant_clamp(use_clamp, svm_mix(type, fac, color1, color2)); | ||||
| optimized->set(use_clamp ? svm_mix_clamp(result) : result); | |||||
| 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); | return folder->make_constant_clamp(use_clamp, svm_mix(type, 0.0f, color1, color1)); | ||||
| optimized->set(use_clamp ? svm_mix_clamp(result) : result); | |||||
| 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_make_noop(use_clamp, color1_in, color1)) | |||||
| return true; | |||||
| } | } | ||||
| if(type != NODE_MIX_BLEND) { | if(type == NODE_MIX_BLEND) { | ||||
| return false; | |||||
| } | |||||
| /* 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_make_noop(use_clamp, color1_in, color1)) | ||||
| return true; | |||||
| } | |||||
| if(!color1_in->link && !color2_in->link && color1 == color2) { | |||||
| optimized->set(use_clamp ? svm_mix_clamp(color1) : color1); | |||||
| return true; | 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_make_noop(use_clamp, color2_in, color2)) | ||||
| optimized->set(use_clamp ? svm_mix_clamp(color2) : color2); | |||||
| return true; | |||||
| } | |||||
| else if(!use_clamp) { | |||||
| graph->relink(this, color_out, color2_in->link); | |||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Combine RGB */ | /* Combine RGB */ | ||||
| Show All 10 Lines | NODE_DEFINE(CombineRGBNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| CombineRGBNode::CombineRGBNode() | CombineRGBNode::CombineRGBNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool CombineRGBNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | bool CombineRGBNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| optimized->set(make_float3(r, g, b)); | return folder->make_constant(make_float3(r, g, b)); | ||||
| return true; | |||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void CombineRGBNode::compile(SVMCompiler& compiler) | void CombineRGBNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *red_in = input("R"); | ShaderInput *red_in = input("R"); | ||||
| Show All 34 Lines | NODE_DEFINE(CombineXYZNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| CombineXYZNode::CombineXYZNode() | CombineXYZNode::CombineXYZNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool CombineXYZNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | bool CombineXYZNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| optimized->set(make_float3(x, y, z)); | return folder->make_constant(make_float3(x, y, z)); | ||||
| return true; | |||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void CombineXYZNode::compile(SVMCompiler& compiler) | void CombineXYZNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *x_in = input("X"); | ShaderInput *x_in = input("X"); | ||||
| Show All 34 Lines | NODE_DEFINE(CombineHSVNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| CombineHSVNode::CombineHSVNode() | CombineHSVNode::CombineHSVNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool CombineHSVNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | bool CombineHSVNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| optimized->set(hsv_to_rgb(make_float3(h, s, v))); | return folder->make_constant(hsv_to_rgb(make_float3(h, s, v))); | ||||
| return true; | |||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void CombineHSVNode::compile(SVMCompiler& compiler) | void CombineHSVNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *hue_in = input("H"); | ShaderInput *hue_in = input("H"); | ||||
| Show All 27 Lines | NODE_DEFINE(GammaNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| GammaNode::GammaNode() | GammaNode::GammaNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool GammaNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | bool GammaNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| optimized->set(svm_math_gamma_color(color, gamma)); | return folder->make_constant(svm_math_gamma_color(color, gamma)); | ||||
| return true; | |||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void GammaNode::compile(SVMCompiler& compiler) | void GammaNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *color_in = input("Color"); | ShaderInput *color_in = input("Color"); | ||||
| Show All 26 Lines | NODE_DEFINE(BrightContrastNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| BrightContrastNode::BrightContrastNode() | BrightContrastNode::BrightContrastNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool BrightContrastNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) | bool BrightContrastNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| optimized->set(svm_brightness_contrast(color, bright, contrast)); | return folder->make_constant(svm_brightness_contrast(color, bright, contrast)); | ||||
| return true; | |||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void BrightContrastNode::compile(SVMCompiler& compiler) | void BrightContrastNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *color_in = input("Color"); | ShaderInput *color_in = input("Color"); | ||||
| Show All 29 Lines | NODE_DEFINE(SeparateRGBNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| SeparateRGBNode::SeparateRGBNode() | SeparateRGBNode::SeparateRGBNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool SeparateRGBNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) | bool SeparateRGBNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(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->socket) { | ||||
| optimized->set(color[channel]); | return folder->make_constant(color[channel]); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void SeparateRGBNode::compile(SVMCompiler& compiler) | void SeparateRGBNode::compile(SVMCompiler& compiler) | ||||
| Show All 36 Lines | NODE_DEFINE(SeparateXYZNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| SeparateXYZNode::SeparateXYZNode() | SeparateXYZNode::SeparateXYZNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool SeparateXYZNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) | bool SeparateXYZNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(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->socket) { | ||||
| optimized->set(vector[channel]); | return folder->make_constant(vector[channel]); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void SeparateXYZNode::compile(SVMCompiler& compiler) | void SeparateXYZNode::compile(SVMCompiler& compiler) | ||||
| Show All 36 Lines | NODE_DEFINE(SeparateHSVNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| SeparateHSVNode::SeparateHSVNode() | SeparateHSVNode::SeparateHSVNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool SeparateHSVNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) | bool SeparateHSVNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(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->socket) { | ||||
| optimized->set(hsv[channel]); | return folder->make_constant(hsv[channel]); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void SeparateHSVNode::compile(SVMCompiler& compiler) | void SeparateHSVNode::compile(SVMCompiler& compiler) | ||||
| ▲ Show 20 Lines • Show All 374 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 *, ShaderOutput *, ShaderInput *optimized) | bool BlackbodyNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| optimized->set(svm_math_blackbody_color(temperature)); | return folder->make_constant(svm_math_blackbody_color(temperature)); | ||||
| return true; | |||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void BlackbodyNode::compile(SVMCompiler& compiler) | void BlackbodyNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *temperature_in = input("Temperature"); | ShaderInput *temperature_in = input("Temperature"); | ||||
| ▲ Show 20 Lines • Show All 88 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 *, ShaderOutput *, ShaderInput *optimized) | bool MathNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| if(all_inputs_constant()) { | if(all_inputs_constant()) { | ||||
| float value = svm_math(type, value1, value2); | return folder->make_constant_clamp(use_clamp, svm_math(type, value1, value2)); | ||||
| optimized->set(use_clamp ? saturate(value) : value); | |||||
| return true; | |||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void MathNode::compile(SVMCompiler& compiler) | void MathNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ShaderInput *value1_in = input("Value1"); | ShaderInput *value1_in = input("Value1"); | ||||
| Show All 40 Lines | NODE_DEFINE(VectorMathNode) | ||||
| return type; | return type; | ||||
| } | } | ||||
| VectorMathNode::VectorMathNode() | VectorMathNode::VectorMathNode() | ||||
| : ShaderNode(node_type) | : ShaderNode(node_type) | ||||
| { | { | ||||
| } | } | ||||
| bool VectorMathNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) | bool VectorMathNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| float value; | float value; | ||||
| float3 vector; | float3 vector; | ||||
| if(all_inputs_constant()) { | if(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->socket == output("Value")) { | ||||
| optimized->set(value); | return folder->make_constant(value); | ||||
| return true; | |||||
| } | } | ||||
| else if(socket == output("Vector")) { | else if(folder->socket == output("Vector")) { | ||||
| optimized->set(vector); | return folder->make_constant(vector); | ||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void VectorMathNode::compile(SVMCompiler& compiler) | void VectorMathNode::compile(SVMCompiler& compiler) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 121 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, ShaderOutput *, ShaderInput *) | bool BumpNode::constant_fold(ConstantFolder *folder) | ||||
| { | { | ||||
| 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")); | return folder->substitute_node(geom->output("Normal")); | ||||
| } | } | ||||
| else { | else { | ||||
| graph->relink(this, outputs[0], normal_in->link); | return folder->make_noop(normal_in); | ||||
| } | } | ||||
| return true; | |||||
| } | } | ||||
| /* TODO(sergey): Ignore bump with zero strength. */ | /* TODO(sergey): Ignore bump with zero strength. */ | ||||
| return false; | return false; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 441 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.