Serious Sam 4

Serious Sam 4

Not enough ratings
Introduction to Node Graph: Making Your Own Shaders
By noam 2000
Want to create your own shaders, but got no clue where to start with the new Node Graph? Noam knows and he might even share some secrets if you're worthy.

In this guide, we'll be constructing a basic ARM shader with a PBR2 master node to help familiarize yourself with SED's new node graph and to understand its workflow to creating shaders.
   
Award
Favorite
Favorited
Unfavorite
Shaders, Nodes, wtf is all this?
Grossly simplified, shaders tell how your material should be rendered. If your shader says the base color is red, any material using this shader will have a red color. If your shader says the base color is red + blue, any material using this shader will have a magenta color.

All these parameters like color, textures, numbers, even mathematical operations are done using "Nodes" inside the visualized Node Graph. If we wanted to mix two colors together like in the example above, we'd grab two "Color" nodes, and plug them into an "Add" node. The result of the two colors added together will be sent to the output, which we can plug elsewhere - that's the workflow of it basically, plugging nodes together and then plugging more nodes into more nodes until we have what we want.



Getting Started
First of all, remember that you only need to create new shaders if you have a special reason and need your material to behave in a certain way SS4 doesn't have set up already. If you browse to "Content/Shared/Presets/ShaderPresets/", you can find many shaders CT has already created, from basic, multilayer, and roughness-metallic ones. You can use either of these as the value in "node shader properties" of the Node shader, and in most cases, these should suit you just fine, and you can just tweak the parameters via the shader modifiers.



Still insistent on making your own shader? Good! Let's get started then. Open up the material you want to edit and remember to use the "Node" shader. Create a new "node shader properties" and save your shader wherever you like. Now just click the small graph icon to the far right side of "node shader properties", and voila, you're in!


On the left side of your workstation is the graph itself - you can move around by holding the middle mouse button, and zoom in or out using the mouse wheel. On the right side is your collection of nodes, any of those can be dragged into the graph window.



You will notice there are two types of icons: one which is a window with a green arrow, and another which is a file with a gear icon. The green arrow nodes, or the "input nodes" will auto create a shader modifier tied to this node that you can edit outside of the node graph, in the material. The gear icon ones can only be modified inside the node graph, if at all - they're constant and don't accept input.

That's about a brief overview of the node graph window. The changes apply in realtime as you edit the graph. Now let's actually make this display stuff!
The Master Node
Every shader has a "Master" node - this node is like the final stop in your graph. You plug all the data you've been calculating into this, and it will transmit it to the material. These nodes are under the "Shader" folder of your node collection.

For this guide, we'll be using a PBR2 shader.



You'll notice right away there's a ton of properties here, but for this guide, we'll only be focusing on:
  • Material Preset
  • Alpha
  • Normal
  • AO
  • Emissive

In roughly that order.
Base Color
The bread of our sandwich, this is the base color our shader is going to output.

The input for the base color, along with many others, is stored inside a "Material Preset" wrapper. We'll want to add a "Material Preset Creator" node (feel free to use the search bar on the top right), and use this node as the input for our master node's "Material Preset" property.

How do we do that? Well, you'll notice nodes have these circular sockets in them on both far ends. The ones on the left are "input" sockets - we feed data into the node through these. The ones on the right are "output" plugs - they contain the calculated data and we can input them to another node.

Simply select the "Material Preset" output plug on the right side of the material preset creator node, and drag it to the "Material Preset" input socket of our master node.



Genius! You're basically certified to be a rocket scientist now.

Now, we're only going to be focusing on the bottom layer of the material preset creator. That "Base" socket is what interests us the most.

Let's add a "Texture" node so we can texture our material. This is an input node, so we'll be able to edit it outside of the graph via the shader modifiers of the material. But, first, we ought to give it a name. At the top right of the node you'll notice 3 blocky buttons - select the empty, far left one, and click on "Edit Node Name". You can also double click the top of the node to name it.



Give it its name, and plug the output "Color" into the material preset creator's "Base" input.
Now you can head over to your shader modifiers, and you'll notice your parameter has been added. Browse for the texture you want, and.. notice that it's not working properly. This is because we haven't set up the UV.

We're going to add two nodes - "Modify UV Map", and "Stream UVMap". Modify UVMap, as the name suggests, will allow us to edit the UV Map, and the Stream will allow us to specify the name of the UV Map in the model.

As usual, name your Stream UVMap node since it is an input node (and if you want to stay organized, you can also name your constants), connect everything up, and specify the name of the UV in the shader modifier. Hooray, now it works!



Thanks to the Modify UVMap node, we can also manipulate this UV too. The rest of the inputs take floats (basically real numbers), so let's add a "Float" node for each of these inputs, name them and plug them up. (Protip - you can set the "default" value of input nodes, these are the values that will be automatically set up by default if no other value was set. You can also copy paste nodes with Ctrl + C and Ctrl + V)



We got our UV's set up and all is good. But what if we want to tint the color of our texture?

Well, as you might have guessed, we're gonna start by adding a "COLOR" node. Set it up as usual, and then we'll want to multiply the color of our texture with our color node. Simply add a "Multiply" node, and plug the color output of our texture into slot A, and the color output of our color modifier into slot B. As you might also have guessed if you're clever, we'll want to replace the base input of our material preset creator with our new multiplication.



Sweet! That's basically our base color done. Hopefully with this alone, you can already get an idea of all the crazy stuff you can do with the node graph.
Alpha
We've got the base color, but it doesn't account for Alpha - that's a separate property on the master node. In theory, you can use this to create special transparency masks, but for this guide, we'll just simply use the alpha from the base texture.

**Note - Alpha is a property on the master node, not inside the material preset.

Right now, the final result of our base color is a multiplication with the color modifier. This multiplication stores an RGBA value (or a Vector4, if you will), and we want to extract that "A" and use it as our alpha.

Super easy! Add a "Split Vector" node and input the multiplication into it. The alpha is the 4th channel, which would be "W" in the split vector node. Simply plug that output into the alpha input in our master node, and that's it! Your shader now supports transparency.

Remember that your material blend type must be set to one that supports transparency.

Normal
Normal is pretty simple, too. Let's start by adding a new Texture node, to which we'll input our normal map.

First things first, since normal maps aren't your typical textures and serve a special purpose, we want to change the sampler type from "SRGB" to "Normal". For the UV, you can create a new set of nodes to control the UV of the normal separately, but in my case, that's not necessary and I can use the same UV I've created earlier for the base color.

Plug the color output into the normal input of the master node, and there we go, easy normals!

ARM (AO, Roughness, Metalness)
Now we're stepping into big boy territory. To control certain aspects of the PBR shader such as ambient occlusion, roughness, or metalness, we use a special mask texture that contains the values for each one stored in the corresponding RGB channels. The one CT went with in most of their shaders is ARM (Red - Ambient Occlusion, Green - Roughness, Blue - Metalness). If you want to learn more about it, I recommend this guide.

We're going to implement the ARM functionality into our shader. Our roughness and metalness inputs are in our material preset creator, whilst the AO is on the master node.

Let's add a new Texture node, which will be the ARM mask texture, and set the sampler type to Linear. Don't forget to set the UV!

Now, instead of using the Color output, we're going to use each channel individually. Let's start with Red, which would be our Ambient Occlusion. Simply drag the "Red" output to the "AO" input of the master node. That's it, AO set up!

Next up is Green - Roughness. Let's add a new Float node which we'll use to control the strength of the roughness, call it "Roughness Multiplier", and multiply it with the green channel. Plug it into "Roughness" in the material preset creator, and now we can control the roughness!

Similarly to the roughness, let's create a new Float node which will control the Metalness. Call it "Metalness Multiplier", multiply it with the Blue channel, and plug into "Metalness" in the material preset creator.

Since we still have the alpha channel available, let's use that to control "Reflectance". Once again, create a new Float node, name it "Reflectance Multiplier", and multiply it with the alpha, plug into "Reflectance" in the material preset creator, and voila! You have a flexible ARM setup.



If you want to set up bounds for those multiplier values, this is where the "Clamp" node comes in useful. You give it the base value as an input, and two min/max values. If the value is bigger than the max, this node will return the max value. If the value is smaller, it will return the min value.

For the min/max values, since we don't need them to be editable, they can be constant, so use a "Constant Float" node, and you can set the value simply by setting the node's name to the value.

Emissive
One more time - create a new Texture node which will be our emission mask, and set the sampler type to Linear, as well as the UV.

Since this is Emission, we're going to want to multiply it with an HDR color. So instead of the typical "COLOR" node, let's grab a "Color4f" node, multiply it with our texture, and plug it into "Emissive". That's it! You have emission.

Endword
Hopefully now you have a basic understanding of how the node graph works and what you can do with it. I'd highly recommend messing around with it more, learning how to use different nodes and create cool stuff. You can even google shader tutorials and follow along on how a bunch of cool shaders are constructed.

For any issues or trouble, feel free to leave a comment.