1
$\begingroup$

My friend and I are trying to create a very simple custom node with OSL. The node we are making looks like this:

node

It has very simple code, and it's only switching input data to output according to the index:

shader mySwitch(
    color map1 = 0,
    color map2 = 0,
    color map3 = 0,
    int index = 0,
    output closure color BSDF = diffuse(N)
)
{

    if (index == 0)
        BSDF = map1 * diffuse(N);
    else if (index == 1)
        BSDF = map2 * diffuse(N);
    else
        BSDF = map3 * diffuse(N);

}

However, we cannot see the maps (textures) in the 3Dview port (OSL is not supported by GPU), so it must be programmed with the Blender API to create a custom shader, which is what we did. This is what's in the file gpu_shader_material.glsl

void node_switch_shader( 
int index, 
vec4 shader0, 
vec4 shader2, 
vec4 shader3, 
vec4 shader4, 
vec4 shader5, 
vec4 shader6, 
vec4 shader7, 
vec4 shader8, 
vec4 shader9, 
out vec4 shader 
) 
{ 

switch (index) { 

case 0: shader = shader0; break; 
case 1: shader = shader1; break; 
case 2: shader = shader2; break; 
case 3: shader = shader3; break; 
case 4: shader = shader4; break; 
case 5: shader = shader5; break; 
case 6: shader = shader6; break; 
case 7: shader = shader7; break; 
case 8: shader = shader8; break; 
case 9: shader = shader9; break; 

default: shader = shader0; 

} 

} 

...

After that, we tried to create the node with C++ by changing 7 files and compiling Blender. However, this process is possible because my smart friend is a very good programmer and we did it only for Ios. For now, we don't know if it is fully functional but maybe it is. But creators and gurus will know.

So is it possible to create something like this in a simpler way? We only want to change the output color data depending on the index, nothing else. For the puppets it can be a game changer.

I am adding the .diff file to show the changes on files for C++. Or please can you add this for next day release?

diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 8a736c9..8957791 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -792,6 +792,7 @@ struct ShadeResult;
 #define SH_NODE_BEVEL                   197
 #define SH_NODE_DISPLACEMENT            198
 #define SH_NODE_VECTOR_DISPLACEMENT     199
+#define SH_NODE_SWITCH_SHADER          600

 /* custom defines options for Material node */
 #define SH_NODE_MAT_DIFF   1
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 1f5ffbd..4f134a8 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -2819,6 +2819,40 @@ void node_add_shader(vec4 shader1, vec4 shader2, out vec4 shader)
    shader = shader1 + shader2;
 }

+void node_switch_shader(
+   int index,
+   vec4 shader0,
+   vec4 shader2,
+   vec4 shader3,
+   vec4 shader4,
+   vec4 shader5,
+   vec4 shader6,
+   vec4 shader7,
+   vec4 shader8,
+   vec4 shader9,
+   out vec4 shader
+)
+{
+   
+   switch (index) {
+
+       case 0: shader = shader0; break;
+       case 1: shader = shader1; break;
+       case 2: shader = shader2; break;
+       case 3: shader = shader3; break;
+       case 4: shader = shader4; break;
+       case 5: shader = shader5; break;
+       case 6: shader = shader6; break;
+       case 7: shader = shader7; break;
+       case 8: shader = shader8; break;
+       case 9: shader = shader9; break;
+
+       default: shader = shader0;
+
+   }
+
+}
+
 /* fresnel */

 void node_fresnel(float ior, vec3 N, vec3 I, out float result)
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 1acd1c4..3e4a9d3 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -181,6 +181,7 @@ set(SRC
    shader/nodes/node_shader_light_falloff.c
    shader/nodes/node_shader_light_path.c
    shader/nodes/node_shader_mix_shader.c
+   shader/nodes/node_shader_switch_shader.c
    shader/nodes/node_shader_normal_map.c
    shader/nodes/node_shader_object_info.c
    shader/nodes/node_shader_hair_info.c
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 6ed71e0..7734205 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -117,6 +117,7 @@ void register_node_type_sh_volume_scatter(void);
 void register_node_type_sh_bsdf_hair(void);
 void register_node_type_sh_subsurface_scattering(void);
 void register_node_type_sh_mix_shader(void);
+void register_node_type_sh_switch_shader(void);
 void register_node_type_sh_add_shader(void);
 void register_node_type_sh_uvmap(void);
 void register_node_type_sh_uvalongstroke(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 2db23c2..e7d3c03 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -73,6 +73,7 @@ DefNode( ShaderNode,     SH_NODE_OUTPUT_LINESTYLE,   def_sh_output_linestyle,"OU
 DefNode( ShaderNode,     SH_NODE_FRESNEL,            0,                      "FRESNEL",            Fresnel,          "Fresnel",           ""       )
 DefNode( ShaderNode,     SH_NODE_LAYER_WEIGHT,       0,                      "LAYER_WEIGHT",       LayerWeight,      "Layer Weight",      ""       )
 DefNode( ShaderNode,     SH_NODE_MIX_SHADER,         0,                      "MIX_SHADER",         MixShader,        "Mix Shader",        ""       )
+DefNode( ShaderNode,     SH_NODE_SWITCH_SHADER,      0,                      "SWITCH_SHADER",      SwitchShader,     "Switch Shader",     ""       )
 DefNode( ShaderNode,     SH_NODE_ADD_SHADER,         0,                      "ADD_SHADER",         AddShader,        "Add Shader",        ""       )
 DefNode( ShaderNode,     SH_NODE_ATTRIBUTE,          def_sh_attribute,       "ATTRIBUTE",          Attribute,        "Attribute",         ""       )
 DefNode( ShaderNode,     SH_NODE_AMBIENT_OCCLUSION,  0,                      "AMBIENT_OCCLUSION",  AmbientOcclusion, "Ambient Occlusion", ""       ) 

eddited Diff 02/15/2018 15:30

diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 3338470..2ecfadb 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -382,6 +382,9 @@ static ShaderNode *add_node(Scene *scene,
    else if(b_node.is_a(&RNA_ShaderNodeMixShader)) {
        node = new MixClosureNode();
    }
+   else if(b_node.is_a(&RNA_ShaderNodeSwitchShader)) {
+       node = new SwitchClosureNode();
+   }
    else if(b_node.is_a(&RNA_ShaderNodeAttribute)) {
        BL::ShaderNodeAttribute b_attr_node(b_node);
        AttributeNode *attr = new AttributeNode();
diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt
index 19b7769..e781017 100644
--- a/intern/cycles/kernel/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/shaders/CMakeLists.txt
@@ -48,6 +48,7 @@ set(SRC_OSL
    node_math.osl
    node_mix.osl
    node_mix_closure.osl
+   node_switch_closure.osl
    node_musgrave_texture.osl
    node_noise_texture.osl
    node_normal.osl
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 48613a9..db75c59 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -3819,6 +3819,51 @@ void MixClosureNode::constant_fold(const ConstantFolder& folder)
    }
 }

+/* Switch Closure */
+
+NODE_DEFINE(SwitchClosureNode)
+{
+   NodeType* type = NodeType::add("switch_closure", create, NodeType::SHADER);
+
+   SOCKET_IN_FLOAT(index, "Index", 1.0f);
+   SOCKET_IN_CLOSURE(closure1,  "Closure1");
+   SOCKET_IN_CLOSURE(closure2,  "Closure2");
+   SOCKET_IN_CLOSURE(closure3,  "Closure3");
+   SOCKET_IN_CLOSURE(closure4,  "Closure4");
+   SOCKET_IN_CLOSURE(closure5,  "Closure5");
+   SOCKET_IN_CLOSURE(closure6,  "Closure6");
+   SOCKET_IN_CLOSURE(closure7,  "Closure7");
+   SOCKET_IN_CLOSURE(closure8,  "Closure8");
+   SOCKET_IN_CLOSURE(closure9,  "Closure9");
+   SOCKET_IN_CLOSURE(closure10, "Closure10");
+
+   SOCKET_OUT_CLOSURE(closure, "Closure");
+
+   return type;
+}
+
+SwitchClosureNode::SwitchClosureNode()
+: ShaderNode(node_type)
+{
+   // special_type = SHADER_SPECIAL_TYPE_CLOSURE;
+   // Don't know which type to use
+}
+
+void SwitchClosureNode::compile(SVMCompiler& compiler)
+{
+   // How to achieve the same behaviour as in OSL node_switch_closure using SVM?
+}
+
+void SwitchClosureNode::compile(OSLCompiler& compiler)
+{
+   compiler.add(this, "node_switch_closure");
+}
+
+void SwitchClosureNode::constant_fold(const ConstantFolder& folder)
+{
+   // Do not need to modify folder, probably
+}
+
 /* Mix Closure */

 NODE_DEFINE(MixClosureWeightNode)
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index f664ebf..5650e2a 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -674,6 +674,14 @@ public:
    float fac;
 };

+class SwitchClosureNode : public ShaderNode {
+public:
+   SHADER_NODE_CLASS(SwitchClosureNode)
+   void constant_fold(const ConstantFolder& folder);
+
+   float index;
+};
+
 class MixClosureWeightNode : public ShaderNode {
 public:
    SHADER_NODE_CLASS(MixClosureWeightNode)
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 8a736c9..887062e 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -792,6 +792,7 @@ struct ShadeResult;
 #define SH_NODE_BEVEL                   197
 #define SH_NODE_DISPLACEMENT            198
 #define SH_NODE_VECTOR_DISPLACEMENT     199
+#define SH_NODE_SWITCH_SHADER          924

 /* custom defines options for Material node */
 #define SH_NODE_MAT_DIFF   1
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 74766be..45478d9 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -3618,6 +3618,7 @@ static void registerShaderNodes(void)
    register_node_type_sh_volume_scatter();
    register_node_type_sh_subsurface_scattering();
    register_node_type_sh_mix_shader();
+   register_node_type_sh_switch_shader();
    register_node_type_sh_add_shader();
    register_node_type_sh_uvmap();
    register_node_type_sh_uvalongstroke();
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 1f5ffbd..b7200d4 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -2819,6 +2819,47 @@ void node_add_shader(vec4 shader1, vec4 shader2, out vec4 shader)
    shader = shader1 + shader2;
 }

+void node_switch_shader(
+   float index,
+   vec4 shader1,
+   vec4 shader2,
+   vec4 shader3,
+   vec4 shader4,
+   vec4 shader5,
+   vec4 shader6,
+   vec4 shader7,
+   vec4 shader8,
+   vec4 shader9,
+   vec4 shader10,
+   out vec4 shader
+)
+{
+
+   vec4 _placeholder = vec4(0.0, 0.0, 0.0, 0.0);
+   float _index = ceil(index);
+
+   if(_index == 2)
+       shader = mix(shader2, _placeholder, 0.0);
+   else if(_index == 3)
+       shader = mix(shader3, _placeholder, 0.0);
+   else if(_index == 4)
+       shader = mix(shader4, _placeholder, 0.0);
+   else if(_index == 5)
+       shader = mix(shader5, _placeholder, 0.0);
+   else if(_index == 6)
+       shader = mix(shader6, _placeholder, 0.0);
+   else if(_index == 7)
+       shader = mix(shader7, _placeholder, 0.0);
+   else if(_index == 8)
+       shader = mix(shader8, _placeholder, 0.0);
+   else if(_index == 9)
+       shader = mix(shader9, _placeholder, 0.0);
+   else if(_index == 10)
+       shader = mix(shader10, _placeholder, 0.0);
+   else
+       shader = mix(shader1, _placeholder, 0.0);
+}
+
 /* fresnel */

 void node_fresnel(float ior, vec3 N, vec3 I, out float result)
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 1acd1c4..3e4a9d3 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -181,6 +181,7 @@ set(SRC
    shader/nodes/node_shader_light_falloff.c
    shader/nodes/node_shader_light_path.c
    shader/nodes/node_shader_mix_shader.c
+   shader/nodes/node_shader_switch_shader.c
    shader/nodes/node_shader_normal_map.c
    shader/nodes/node_shader_object_info.c
    shader/nodes/node_shader_hair_info.c
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 6ed71e0..7734205 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -117,6 +117,7 @@ void register_node_type_sh_volume_scatter(void);
 void register_node_type_sh_bsdf_hair(void);
 void register_node_type_sh_subsurface_scattering(void);
 void register_node_type_sh_mix_shader(void);
+void register_node_type_sh_switch_shader(void);
 void register_node_type_sh_add_shader(void);
 void register_node_type_sh_uvmap(void);
 void register_node_type_sh_uvalongstroke(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 2db23c2..e7d3c03 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -73,6 +73,7 @@ DefNode( ShaderNode,     SH_NODE_OUTPUT_LINESTYLE,   def_sh_output_linestyle,"OU
 DefNode( ShaderNode,     SH_NODE_FRESNEL,            0,                      "FRESNEL",            Fresnel,          "Fresnel",           ""       )
 DefNode( ShaderNode,     SH_NODE_LAYER_WEIGHT,       0,                      "LAYER_WEIGHT",       LayerWeight,      "Layer Weight",      ""       )
 DefNode( ShaderNode,     SH_NODE_MIX_SHADER,         0,                      "MIX_SHADER",         MixShader,        "Mix Shader",        ""       )
+DefNode( ShaderNode,     SH_NODE_SWITCH_SHADER,      0,                      "SWITCH_SHADER",      SwitchShader,     "Switch Shader",     ""       )
 DefNode( ShaderNode,     SH_NODE_ADD_SHADER,         0,                      "ADD_SHADER",         AddShader,        "Add Shader",        ""       )
 DefNode( ShaderNode,     SH_NODE_ATTRIBUTE,          def_sh_attribute,       "ATTRIBUTE",          Attribute,        "Attribute",         ""       )
 DefNode( ShaderNode,     SH_NODE_AMBIENT_OCCLUSION,  0,                      "AMBIENT_OCCLUSION",  AmbientOcclusion, "Ambient Occlusion", ""       )
$\endgroup$
9
  • $\begingroup$ This is not a Dev's site, you are better off directing questions about source code and development to the dev's IRC and mailing-list. This will be closed as off-topic. But to help you what you are searching for is probably here: blender.stackexchange.com/a/99003/7777 $\endgroup$ Feb 15, 2018 at 0:14
  • 1
    $\begingroup$ Possible duplicate of Cycles Materials Math node with more than two inputs $\endgroup$ Feb 15, 2018 at 0:14
  • 4
    $\begingroup$ @Jerryno, unfortunatelly, that method still lacks of gpu rendering in the viewport. I wrote a patch to fix it, but it didn't went to master. If I had time I could write a better patch for 2.79a, thought i'm aiming for 2.8. $\endgroup$
    – Secrop
    Feb 15, 2018 at 8:43
  • $\begingroup$ @Secrop True, I completely overlooked the GPU rendering requirement.. $\endgroup$ Feb 15, 2018 at 12:13
  • $\begingroup$ I am sorry, i am quite new here, so would I delete or edit this question ? Because its about the Gpu rendering and viewport problem. $\endgroup$
    – MRL
    Feb 15, 2018 at 12:19

1 Answer 1

1
$\begingroup$

P.S.: Before you read the rest of this answer, check if the ColorRamp node with a constant interpolation suits your needs. It won't work if you need to input a texture, but it is enough for simple colors.


If you don't strictly need to do this in OSL, I suggest you use the Group feature. Basically, a group lets you create a node and define it's behavior using other nodes. It should be relatively simple for the goal that you're trying to achieve.

First, we'll create a bunch of nodes that do just what you need. Then, we'll convert these into a node group, so that you can use this functionality as many times as you want in that Blender file. You will even be able to export this to other .blend files.

Imagine for a moment that you want to switch between two colors. Index 0 = first color; index 1 = second color. You could do it with the following node setup:

node setup

Here, we have one number input (the index) and two color inputs. If the index is 0, the first color is output. If the index is anything greater, like 1, the second color is output.

We can also add another color:

node setup

Now, whenever the index is larger than 0, there is a choice between color 2 and 3, depending on whether the index is 1 or more.

Notice that we can repeat this as much as we like, to add more colors:

node setup

When you have setup this node tree, select all the nodes in it (but not the placeholder color input nodes*!). You can do this easily with circle select (C).

*If you have Node Wrangler installed, you can first add reroutes to all outputs of the index input, that will save you a few worries later. Select the reroute, too.

Now, click Group > Make Group. Your nodes will be packed into a group that you can use wherever you like.

You might have to clean the inputs up a bit, because you only need one index input that is inserted to all the greater than math nodes.

You should now have something like this:

node group

In the tab on the right, you can edit the inputs and outputs, rename them, delete them, etc.

Now, click that arrow-up thingy at the bottom of the screen to get out of the node group.

parent node

You will see that the node setup that you selected is replaced by a single node. If you select it, you can rename the node group on the tab at the right side of the screen.

What's important is that you can create more nodes like this by going to Group and clicking [name of node]. In my example, I renamed the node group to "MySwitch":

node

3 groups

$\endgroup$
1
  • $\begingroup$ Thank you, I will try to script this solution, for my purpose, I would like to have it all automated. $\endgroup$
    – MRL
    Feb 16, 2018 at 12:11

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .