|
@@ -17,17 +17,17 @@ jME3 material system is entirely based on shaders. While it's pretty powerful, t
|
|
|
* Adding new features to those shaders decrease the ease of maintenance a lot. This point made us reluctant to do so and some feature were never added (Fog to name it, but many more).
|
|
* Adding new features to those shaders decrease the ease of maintenance a lot. This point made us reluctant to do so and some feature were never added (Fog to name it, but many more).
|
|
|
* Users can't add their own feature to the shader unless they fork it, and fall back to the same issues explained in previous points.
|
|
* Users can't add their own feature to the shader unless they fork it, and fall back to the same issues explained in previous points.
|
|
|
|
|
|
|
|
-Shader Nodes were designed with this in mind and are the fruit of many long discussions in the core chat balancing the pros and cons of this or that pattern.+
|
|
|
|
|
-At first this system was referred to as “Shader injection. The basic idea was to allow users to inject code into shaders with a tag replacement system.+
|
|
|
|
|
-We finally came with a different concept called Shader Nodes, that is inspired from blender nodes system for textures and post process.+
|
|
|
|
|
|
|
+Shader Nodes were designed with this in mind and are the fruit of many long discussions in the core chat balancing the pros and cons of this or that pattern. +
|
|
|
|
|
+At first this system was referred to as “Shader injection. The basic idea was to allow users to inject code into shaders with a tag replacement system. +
|
|
|
|
|
+We finally came with a different concept called Shader Nodes, that is inspired from blender nodes system for textures and post process. +
|
|
|
*The final shader is generated at run time by the system by assembling shader nodes together.*
|
|
*The final shader is generated at run time by the system by assembling shader nodes together.*
|
|
|
|
|
|
|
|
|
|
|
|
|
== What is a Shader Node?
|
|
== What is a Shader Node?
|
|
|
|
|
|
|
|
-Conceptually, it's just a self sufficient piece of glsl code that accepts inputs and produce some outputs.+
|
|
|
|
|
-Inputs are glsl variables that may be fed by previous nodes output values.+
|
|
|
|
|
-Outputs are glsl variables fed with values computed in the shader node code.+
|
|
|
|
|
|
|
+Conceptually, it's just a self sufficient piece of glsl code that accepts inputs and produce some outputs. +
|
|
|
|
|
+Inputs are glsl variables that may be fed by previous nodes output values. +
|
|
|
|
|
+Outputs are glsl variables fed with values computed in the shader node code. +
|
|
|
|
|
|
|
|
In practice it's a bit more than that.A shader node is declined in several parts :
|
|
In practice it's a bit more than that.A shader node is declined in several parts :
|
|
|
|
|
|
|
@@ -51,13 +51,13 @@ In practice it's a bit more than that.A shader node is declined in several parts
|
|
|
|
|
|
|
|
== Shader Node definition
|
|
== Shader Node definition
|
|
|
|
|
|
|
|
-First ShaderNodes have to be defined either in a separate file (j3sn for jme3 shader node) or directly embed in the Technique block of the j3md file.+
|
|
|
|
|
|
|
+First ShaderNodes have to be defined either in a separate file (j3sn for jme3 shader node) or directly embed in the Technique block of the j3md file. +
|
|
|
Please refer to this documentation for global structure of a j3md file
|
|
Please refer to this documentation for global structure of a j3md file
|
|
|
<<jme3/advanced/material_specification#,jMonkeyEngine3 Material Specification>>
|
|
<<jme3/advanced/material_specification#,jMonkeyEngine3 Material Specification>>
|
|
|
|
|
|
|
|
-All is included in a *ShaderNodeDefinitions* bloc. This block can have several nodes defined (it's recommended to define nodes that have strong dependencies with each other in the same j3sn file).+
|
|
|
|
|
-A ShaderNode is declared in a *ShaderNodeDefinition* block.+
|
|
|
|
|
-global structure should look like this :+
|
|
|
|
|
|
|
+All is included in a *ShaderNodeDefinitions* bloc. This block can have several nodes defined (it's recommended to define nodes that have strong dependencies with each other in the same j3sn file). +
|
|
|
|
|
+A ShaderNode is declared in a *ShaderNodeDefinition* block. +
|
|
|
|
|
+global structure should look like this :
|
|
|
|
|
|
|
|
[source,java]
|
|
[source,java]
|
|
|
----
|
|
----
|
|
@@ -90,7 +90,7 @@ ShaderNodeDefinitions{
|
|
|
|
|
|
|
|
----
|
|
----
|
|
|
|
|
|
|
|
-All that is not between [] is mandatory.+
|
|
|
|
|
|
|
+All that is not between [] is mandatory.
|
|
|
|
|
|
|
|
* +++<u>ShaderNodeDefinition</u>+++ : the definition block. You can have several definition in the same ShaderNodeDefinitions block.
|
|
* +++<u>ShaderNodeDefinition</u>+++ : the definition block. You can have several definition in the same ShaderNodeDefinitions block.
|
|
|
** *NodeDefName* : The name of this ShaderNodeDefinition
|
|
** *NodeDefName* : The name of this ShaderNodeDefinition
|
|
@@ -152,9 +152,9 @@ ShaderNodeDefinitions{
|
|
|
|
|
|
|
|
=== Declare an array
|
|
=== Declare an array
|
|
|
|
|
|
|
|
-To declare an array you have to specify its size between square brackets.+
|
|
|
|
|
-*Constant size*+
|
|
|
|
|
-The size can be an int constant+
|
|
|
|
|
|
|
+To declare an array you have to specify its size between square brackets. +
|
|
|
|
|
+*Constant size* +
|
|
|
|
|
+The size can be an int constant +
|
|
|
_Example_
|
|
_Example_
|
|
|
|
|
|
|
|
[source]
|
|
[source]
|
|
@@ -165,10 +165,10 @@ _Example_
|
|
|
----
|
|
----
|
|
|
|
|
|
|
|
this will declare a float array with 10 elements.
|
|
this will declare a float array with 10 elements.
|
|
|
-Any material parameter mapped with this array should be of FloatArray type and it's size will be assumed as 10 when the shader is generated.+
|
|
|
|
|
|
|
+Any material parameter mapped with this array should be of FloatArray type and it's size will be assumed as 10 when the shader is generated.
|
|
|
|
|
|
|
|
-*Material parameter driven size*+
|
|
|
|
|
-The size can be dynamic and driven by a material parameter. GLSL does not support non constant values for array declaration so this material parameter will be mapped to a define.+
|
|
|
|
|
|
|
+*Material parameter driven size* +
|
|
|
|
|
+The size can be dynamic and driven by a material parameter. GLSL does not support non constant values for array declaration so this material parameter will be mapped to a define. +
|
|
|
_Example_
|
|
_Example_
|
|
|
|
|
|
|
|
[source]
|
|
[source]
|
|
@@ -178,18 +178,22 @@ _Example_
|
|
|
|
|
|
|
|
----
|
|
----
|
|
|
|
|
|
|
|
-This declares a float array with the size depending on the value of the NumberOfElement material parameter.+
|
|
|
|
|
|
|
+This declares a float array with the size depending on the value of the NumberOfElement material parameter. +
|
|
|
NumberOfElement *HAS* to be declared in the material definition as a material parameter. It will be mapped to a define and used in the shader.
|
|
NumberOfElement *HAS* to be declared in the material definition as a material parameter. It will be mapped to a define and used in the shader.
|
|
|
-Not that if this value change the shader will have to be recompiled, due to the fact that it's mapped to a define.
|
|
|
|
|
|
|
+
|
|
|
|
|
+[NOTE]
|
|
|
|
|
+====
|
|
|
|
|
+If this value change the shader will have to be recompiled, due to the fact that it's mapped to a define.
|
|
|
|
|
+====
|
|
|
|
|
|
|
|
|
|
|
|
|
== Shader Node code
|
|
== Shader Node code
|
|
|
|
|
|
|
|
-The shader code associated with a Shader node is similar to any shader code.+
|
|
|
|
|
|
|
+The shader code associated with a Shader node is similar to any shader code. +
|
|
|
the code for a Vertex shader node should be in a .vert file and the code for a Fragment shader node should be in a .frag file.
|
|
the code for a Vertex shader node should be in a .vert file and the code for a Fragment shader node should be in a .frag file.
|
|
|
-It has a declarative part containing variable declaration, function declaration and so on… And a main part that is embed in a “void main(){} block.+
|
|
|
|
|
-Input and output variables declared in the shader node definition can be used *without* being declared in the shader code. ( they shouldn't even or you'll have issues).+
|
|
|
|
|
-Here is a the code of the LightMap.frag shader.+
|
|
|
|
|
|
|
+It has a declarative part containing variable declaration, function declaration and so on… And a main part that is embed in a “void main(){} block. +
|
|
|
|
|
+Input and output variables declared in the shader node definition can be used *without* being declared in the shader code. ( they shouldn't even or you'll have issues). +
|
|
|
|
|
+Here is a the code of the LightMap.frag shader.
|
|
|
|
|
|
|
|
[source,java]
|
|
[source,java]
|
|
|
----
|
|
----
|
|
@@ -200,16 +204,16 @@ void main(){
|
|
|
|
|
|
|
|
----
|
|
----
|
|
|
|
|
|
|
|
-Very simple, it's just a texture fetch, but of course anything can be done.+
|
|
|
|
|
|
|
+Very simple, it's just a texture fetch, but of course anything can be done. +
|
|
|
*Do not declare uniforms, attributes or varyings in a shader node code*, the Generator will handle this, just use the inputs and outputs and optional local variables you may need.
|
|
*Do not declare uniforms, attributes or varyings in a shader node code*, the Generator will handle this, just use the inputs and outputs and optional local variables you may need.
|
|
|
|
|
|
|
|
|
|
|
|
|
== Shader Node declaration
|
|
== Shader Node declaration
|
|
|
|
|
|
|
|
To create a shader we need to plug shader nodes to each other, but also interact with built in glsl inputs and outputs.
|
|
To create a shader we need to plug shader nodes to each other, but also interact with built in glsl inputs and outputs.
|
|
|
-Shader nodes are declared inside the Technique block. The vertex nodes are declared in the VertexShaderNodes block and the fragment nodes are declared in the FragmentShaderNodes block.+
|
|
|
|
|
|
|
+Shader nodes are declared inside the Technique block. The vertex nodes are declared in the VertexShaderNodes block and the fragment nodes are declared in the FragmentShaderNodes block. +
|
|
|
Note that if the j3md has ember shader nodes definition (in a ShaderNodesDefinitions block) it *must* be declared before the VertexShaderNodes and FragmentShaderNodes blocks.
|
|
Note that if the j3md has ember shader nodes definition (in a ShaderNodesDefinitions block) it *must* be declared before the VertexShaderNodes and FragmentShaderNodes blocks.
|
|
|
-Of course there can be several ShaderNode declaration in those block.+
|
|
|
|
|
|
|
+Of course there can be several ShaderNode declaration in those block. +
|
|
|
Here is how a ShaderNode declaration should look :
|
|
Here is how a ShaderNode declaration should look :
|
|
|
|
|
|
|
|
[source,java]
|
|
[source,java]
|
|
@@ -238,10 +242,9 @@ ShaderNode <ShaderNodeName>{
|
|
|
** *DefinitionPath* : in case the definition is declared in it's own j3sn file, you have to set the path to this file here.
|
|
** *DefinitionPath* : in case the definition is declared in it's own j3sn file, you have to set the path to this file here.
|
|
|
|
|
|
|
|
* +++<u>Condition</u>+++ a condition that dictates if the node is active or not.
|
|
* +++<u>Condition</u>+++ a condition that dictates if the node is active or not.
|
|
|
-** *Activationcondition* : The condition for this node to be used. Today we use Defines to use different blocks of code used depending on the state of a Material Parameter. The condition here use the exact same paradigm. A valid condition must be the name of a material parameter or any combinations using logical operators “||,“&&,“! or grouping characters “( and “). The generator will create the corresponding define and the shader node code will be embed into and #ifdef statement.+
|
|
|
|
|
|
|
+** *ActivationCondition* : The condition for this node to be used. Today we use Defines to use different blocks of code used depending on the state of a Material Parameter. The condition here use the exact same paradigm. A valid condition must be the name of a material parameter or any combinations using logical operators “||,“&&,“! or grouping characters “( and “). The generator will create the corresponding define and the shader node code will be embed into and #ifdef statement.
|
|
|
|
|
|
|
|
-
|
|
|
|
|
- For example, let's say we have a Color and ColorMap material parameter, this condition “Color || ColorMap will generate this statement :
|
|
|
|
|
|
|
+For example, let's say we have a Color and ColorMap material parameter, this condition “Color || ColorMap will generate this statement :
|
|
|
|
|
|
|
|
[source,java]
|
|
[source,java]
|
|
|
----
|
|
----
|
|
@@ -323,10 +326,10 @@ MaterialDef Simple {
|
|
|
|
|
|
|
|
----
|
|
----
|
|
|
|
|
|
|
|
-This Material definition has one Default technique with 2 node declarations.+
|
|
|
|
|
-+++<u>*CommonVert Definition*</u>++++
|
|
|
|
|
-CommonVert is a vertex shader node that has commonly used input and outputs of a vertex shader. It also computes the position of the vertex in projection space
|
|
|
|
|
-here is the definition content (Common/MatDefs/ShaderNodes/Common/CommonVert.j3sn) :
|
|
|
|
|
|
|
+This Material definition has one Default technique with 2 node declarations. +
|
|
|
|
|
+*+++<u>CommonVert Definition</u>+++* +
|
|
|
|
|
+CommonVert is a vertex shader node that has commonly used input and outputs of a vertex shader. It also computes the position of the vertex in projection space. +
|
|
|
|
|
+Here is the definition content (Common/MatDefs/ShaderNodes/Common/CommonVert.j3sn) :
|
|
|
|
|
|
|
|
[source,java]
|
|
[source,java]
|
|
|
----
|
|
----
|
|
@@ -369,10 +372,10 @@ ShaderNodesDefinitions {
|
|
|
|
|
|
|
|
[TIP]
|
|
[TIP]
|
|
|
====
|
|
====
|
|
|
-Note that texCoord1/2 and vertColor are declared both as input and output. the generator will use the same variables for them
|
|
|
|
|
|
|
+Note that texCoord1/2 and vertColor are declared both as input and output. The generator will use the same variables for them.
|
|
|
====
|
|
====
|
|
|
|
|
|
|
|
-here is the shader Node code ( Common/MatDefs/ShaderNodes/Common/commonVert.vert)
|
|
|
|
|
|
|
+Here is the shader Node code ( Common/MatDefs/ShaderNodes/Common/commonVert.vert)
|
|
|
|
|
|
|
|
[source,java]
|
|
[source,java]
|
|
|
----
|
|
----
|
|
@@ -383,10 +386,10 @@ void main(){
|
|
|
|
|
|
|
|
----
|
|
----
|
|
|
|
|
|
|
|
-As you can see all the inputs and outputs are not used. that's because most of them are attributes meant to be passed to the fragment shader as varyings. all the wiring will be handled by the generator only if those variables are used in an input or output mapping.+
|
|
|
|
|
|
|
+As you can see all the inputs and outputs are not used. That's because most of them are attributes meant to be passed to the fragment shader as varyings. All the wiring will be handled by the generator only if those variables are used in an input or output mapping.
|
|
|
|
|
|
|
|
+++<u>*CommonVert input mapping*</u>++++
|
|
+++<u>*CommonVert input mapping*</u>++++
|
|
|
-here we have the most basic yet mandatory thing in a vertex shader, computing vertex position in projection space. for this we have 2 mapping :
|
|
|
|
|
|
|
+Here we have the most basic yet mandatory thing in a vertex shader, computing vertex position in projection space. for this we have 2 mappings :
|
|
|
|
|
|
|
|
* *worldViewProjectionMatrix = WorldParam.WorldViewProjectionMatrix* : the input parameter worldViewProjectionMatrix is assigned with the WorldViewProjectionMatrix World parameter declared in the WorlParameters block of the technique.
|
|
* *worldViewProjectionMatrix = WorldParam.WorldViewProjectionMatrix* : the input parameter worldViewProjectionMatrix is assigned with the WorldViewProjectionMatrix World parameter declared in the WorlParameters block of the technique.
|
|
|
* *modelPosition = Global.position.xyz* : the modelPosition (understand the vertex position in the model coordinate space) is assigned with the Global position variable.
|
|
* *modelPosition = Global.position.xyz* : the modelPosition (understand the vertex position in the model coordinate space) is assigned with the Global position variable.
|
|
@@ -394,13 +397,18 @@ here we have the most basic yet mandatory thing in a vertex shader, computing ve
|
|
|
|
|
|
|
|
[TIP]
|
|
[TIP]
|
|
|
====
|
|
====
|
|
|
-As mentioned before Global position is initialized with the attribute inPosition, so this is equivalent to : modelPosition = Attr.inPosition.xyz
|
|
|
|
|
|
|
+As mentioned before Global position is initialized with the attribute inPosition, so this is equivalent to :
|
|
|
|
|
+
|
|
|
|
|
+[source, java]
|
|
|
|
|
+----
|
|
|
|
|
+modelPosition = Attr.inPosition.xyz
|
|
|
|
|
+----
|
|
|
====
|
|
====
|
|
|
|
|
|
|
|
|
|
|
|
|
[TIP]
|
|
[TIP]
|
|
|
====
|
|
====
|
|
|
-also note the swizzle of the Global.position variable. modelPosition is a vec3 and GlobalPosition is a vec4 so we just take the first 3 components.
|
|
|
|
|
|
|
+Also note the swizzle of the Global.position variable. modelPosition is a vec3 and GlobalPosition is a vec4 so we just take the first 3 components.
|
|
|
====
|
|
====
|
|
|
|
|
|
|
|
+++<u>*CommonVert output mapping*</u>++++
|
|
+++<u>*CommonVert output mapping*</u>++++
|
|
@@ -442,7 +450,7 @@ ShaderNodeDefinitions{
|
|
|
|
|
|
|
|
----
|
|
----
|
|
|
|
|
|
|
|
-here is the shader Node code (Common/MatDefs/ShaderNodes/Basic/colorMult.frag)
|
|
|
|
|
|
|
+Here is the shader Node code (Common/MatDefs/ShaderNodes/Basic/colorMult.frag)
|
|
|
|
|
|
|
|
[source,java]
|
|
[source,java]
|
|
|
----
|
|
----
|
|
@@ -457,7 +465,12 @@ void main(){
|
|
|
All inputs are mapped here :
|
|
All inputs are mapped here :
|
|
|
|
|
|
|
|
* *color1 = MatParam.Color* : The first color is assigned to the Color Material parameter declared in the MaterialParameter block of the material definition
|
|
* *color1 = MatParam.Color* : The first color is assigned to the Color Material parameter declared in the MaterialParameter block of the material definition
|
|
|
-* *color2 = Global.color* : The second color is assigned with the Global color variable. this is defaulted to vec4(1.0) (opaque white). Note that in a much complex material def this variable could already have been assigned with a previous Shader Node output
|
|
|
|
|
|
|
+* *color2 = Global.color* : The second color is assigned with the Global color variable. this is defaulted to vec4(1.0) (opaque white).
|
|
|
|
|
+
|
|
|
|
|
+[NOTE]
|
|
|
|
|
+====
|
|
|
|
|
+In a very complex material def this variable could already have been assigned with a previous Shader Node output.
|
|
|
|
|
+====
|
|
|
|
|
|
|
|
+++<u>*ColorMult output mapping*</u>++++
|
|
+++<u>*ColorMult output mapping*</u>++++
|
|
|
|
|
|