Posted October 25, 2019 by RodZilla
#Material Maker #Procedural #Textures #Shaders
Here is a small guide that shows how to create new GLSL-based texture generators. Please don't hesitate to ask questions in comments so I can update it.
First, let's clarify about the shader language. Material Maker is based on the (absolutely fantastic) Godot Engine, that has its own shader language (described here) that is pretty close to GLSL. That's why I generally test shaders in Shadertoy first, then copy the code into Material Maker and adapt it.
Before creating a new generator, it is important to understand how Material Maker will use it.
There are very few generator types:
When shader-based generators are connected, Material Maker will combine their code into a new one. This is why each shader generator consists of:
If you want to create the new generator from scratch, just drag and drop a Custom Shader node from the library pane to the graph (you can enter "custom" in the filter below the library pane to spot it easily). If you want to start from an existing one, just select a node in the graph and use the Tools -> Make selected nodes editable menu (or hit Ctrl-F).
In both cases, 3 buttons will be shown on the node:
Saving the shader generator into the generators directory in the Material Maker install location will make it available in the Tools -> Create submenu. Of course, overwriting a generator that was provided in Material Maker is generally a bad idea and may break generators that use it in the library and all material projects.
The generator will always have outputs that will be connected to the inputs of other generators. It may also (and will probably) have parameters that can be modified in the user interface, and inputs to receive data from other generators.
Inputs and parameters can be added in the General tab, but first, you may want to choose a nice name for your generator.
To add a parameter, just click on the green "+" button in the Parameters section. A new parameter line will be created with a red "-" button on its left to delete the parameter. On this line:
To use a parameter in your shader code it is necessary to prefix it with a dollar sign. So a foo parameter can be refered to by $foo or $(foo) in the shader code. Gradient parameters need to be used as functions with a single float parameter. So mygradient should be refered to as $mygradient($uv.x) if you want to spread the gradient on the x axis. And yes, $uv is an implicit variable used by Material Maker for UV coordinates.
Inputs can be added and removed, have a name and a label (but no label trick) just like parameters. they also have a type that can be Greyscale, Color or RGBA. Please note that Material Maker will convert automatically if you connect an input to an output of a different type.
On the right of the input type, you must define a default value that will be used if the input is not connected. The default value is a GLSL expression that must evaluate to a float for Greyscale, a vec3 for Color or a vec4 for RGBA. Inputs default values can use the $uv implicit variable. You may want to define interesting default inputs for your generators, so it is possible to see their effect without connecting the inputs (the screenshot above is the Blend filter and has a vertical and an horizontal gradient as inputs).
In shader code, inputs are used as functions that take a single vec2 parameter. For example $myinput(2.0*$uv+vec2(0.2, 0.3)) refers to myinput, scaled and translated.
Outputs are defined in the Outputs tab and are very similar to inputs, but instead of a default value, the generated value of the output should be specified as a GLSL expression (float for Greyscale, a vec3 for Color or a vec4 for RGBA). This expression can use everything in the generator (parameters, inputs, main code, instance functions and global functions) except other outputs. And generally, complex generators mean complex output expressions. You may thus want to write simple expressions in the Outputs tab and keep complex code in the 3 remaining tabs.
Now the parameters, inputs and outputs are defined, the code that will actually generate the texture will be in the 3 remaining tabs.
The Global functions tab is used to define the functions that are necessary to implement the texture generator. Those functions will be included only once (when the generator is used of course) and cannot use parameters or inputs. This is typically where you will paste the code you prepared in Shadertoy.
Instance functions are functions that are unique to an instance of the generator. They will typically depend on parameters, and those could either be used as parameters when calling global functions, or to form global function names (as shown in the screenshot below: the blend_type parameter is an enum whose value is the suffix of one of the blend functions defined in the Global Functions pane).
Instance functions must also have a unique name, and the name implicit variable can be used to do this: whenever $name or $(name) is used, it will be replaced with a unique name that depends on the generator instance.
This tab contains code that will be inserted into the main combined shader and can be used to define variables that will be used in the outputs expressions. This can be useful either to simplify the outputs or to define variables that will be used by several outputs (hence optimizing the shader code).
Main code can use the generator's parameters and inputs as well as instance and global functions.
Since a generator can be sampled for several different UV expressions in the same combined shader, it is necessary for all variables declared in the main code section to have a unique name for each (generator instance, UV expression) pair. Material Maker provides the name_uv implicit variable for this.
I hope this small guide will help those who want to create new shader-based generators for Material Maker. Unfortunately, there is no debug tool for now, so you may want to start with very simple shaders and read the code of existing ones. And please don't hesitate to post comments below to ask questions or report problems.