Getting started with Unity's new Shader Graph Node-based Shader Creator/Editor (tutorial 1 - setup and first "basic" shader)
Introduction (to the Tutorial Series):
I will be writing about my own experiences using Unity's new beta Shader Graph, part of its upcoming 2018 release (also in beta). The Shader Graph lets you create a variety of Unity shaders using nodes - not requiring you to write code.I will be writing about this journey over multiple posts, usually spaced about a week apart. Each post will be a short tutorial on how to use various node types to create different shader effects. And will include brief discussions on types of shaders and their uses, and later, how the Shader Graph compares with code-based shaders. I will try not to get overly technical, but will try to give you an idea of the complexity involved in shaders, from lighting to vertex and fragment manipulation.
Given the nature of beta software, expect the Shader Graph (and later tutorials) to vary from earlier ones that you can now find online. Even within my tutorials there will be changes if/when the beta evolves - including, if necessary, going over the basics again if something in the editor changes significantly.
I hope you find this tutorial useful. If you do, please be kind and click an interesting ad to help support this site. It really does help, believe me. And thank you, I'm grateful to you!
If you have any questions or comments, please leave a comment and I'll try to respond with a day or so. I'm writing these tutorials in my spare time and each one takes several hours to put together. And I prefer to write them, instead of doing a quick video sequence. A written tutorial is more easily translated by those who do not speak English.
Other Tutorials in the Series:
Background:
Like many people that are deep into shader development, I am happy that Unity Technologies is adding a node-based shader editor to it's upcoming 2018 Unity engine release. Node-based shader editors allow you to create graphics shaders without traditional coding. You see such editors in Maya, Substance Designer and Unreal. So while Unity is only catching up, the fact that it also allows you to continue to create shaders via a shader coding language gives you the best of both worlds. (Unity uses a shader coding language that is a combination of Nvidia's Cg and Microsoft DirectX's HLSL with some macros of their own thrown in to simplify common tasks.)Now, I write shaders using code, but I have a coding background and enjoy creating shaders using Unity's Cg/HLSL variant. But I also appreciate node-based development, despite having to get used to doing things "the hard way" when compared with a few simple lines of code.
Or maybe not so hard - just a different way.
Node-based shader development opens up Unity shaders to a wider audience. And while (currently) it is not a full replacement for code-based shader development, it is a welcome first step.
Unity's Shader Graph only works with Unity's new 2018.1+ beta, so like the new Unity beta engine, it has problems that are currently being worked on. That is the nature of beta software. And the Shader Graph interface has already gone through major changes. If you've looked at some unofficial YouTube tutorials you'll realize that the biggest UI change is with the properties. However, with those changes also comes the welcome addition of flow control nodes (logic nodes). What are those? Logic nodes let you do things like "IF this AND that THEN do this". This isn't a big deal with basic shaders, but for shaders that alter their behavior dynamically, it's priceless.
First Steps:
It's recommended that you familiarize yourself with Matt Dean's (kink3d) thread post that details an introduction to the Shader Graph (click here) as well as a thread post on the latest release notes on the current version (0.1.17 as of this writing). Click here for blog thread post of latest release notes. Links will open in a new window.You will also need to install the Unity 2018 beta (minimum 2018.1 beta 4 but the most current beta version is recommended). To download the beta, click here.
Note: Update - this tutorial was based on Unity 2018.1.0b7 and Shader Graph 0.1.17. One change that has happened since that time is that you now create shader graphs by Assets->Create -> Shader->PBR Graph (or Sub Graph or Unlit Shader) instead of Assets->Create->Shader Graph.
Other Official Unity Resources:
The Unity Shader Graph team has created a fun little fly-through demo, you can download it here.They also have a very quick no-audio walkthrough video on shader creation here.
These links are also in the introduction to the Shader Graph post by Matt Dean (kink3d) listed above.
OK, Here We Go (Step 1):
I am using Unity beta 2018.1.0b7. First, open up Unity beta and create a new Lightweight-Preview project. If you are using Unity Hub (which let's you keep track of all your Unity engine installs and projects, see blog post here for more information), then set Unity 2018.1.0b7 as your preferred install. To do that, under Installs Left-Click ... to the right of the Unity version you want to use and select it as your preferred.Then, under Projects, click New and create a new Lightweight-Preview project. I'm calling mine ShaderGraphTutorial.
The Lightweight project should open. It may take longer than you expect, remember, this is beta software.
Using the Package Manager to Update Shader Graph (Step 2):
The first thing we are going to do is make sure we are using the most recent Shader Graph, which according to the 0.1.17 release notes, requires a minimum of beta 4 (I am using beta 7) and needs render-pipelines.lightweight minimum version 0.1.28.Under Windows, choose Package Manager and the Package Manager window should open and update with your currently loaded packages (and built-in packages). Make sure the In Project button is clicked (not the All button). It will also show whether or not an update is ready for any packages.
Update your render-pipelines.lightweight to the latest version (should be 0.1.28) and shader graph (to 0.1.17). To update, click the Update To X.XX.XX button in the upper right corner. (Don't click the Remove button!) Close the Package Manager.
Note 1: This is beta software, if it starts acting up, close the project and reload. Then recheck the Package Manager and make sure everything is up to date. The same applies if you get a series of errors (see the Console).
Note 2: I don't recommend opening any project other than a New Lightweight-Preview project for this updating step. I tried it using their sample project (see link earlier) and got errors during the update. Also, I noticed that I needed to update the rendering pipeline core package (which I did), but nowhere did the Release notes for Shader Graph mention that. Again, beta software!
Create a New Shader Graph and Material (Step 3):
Before we open the Shader Graph editor, we are going to create a shader graph. It seems a little confusing but a shader graph is the basic unit. It essentially is a file that will contain the node information. It is not shader code, for those who are used to Cg/HLSL shaders.However, visually, a shader graph asset looks the same as a shader code asset in your Project->Assets window.
First, create a new shader graph. Click Assets -> Create -> Shader Graph (or Right-Click in the Assets part of the Project Window and select Create -> Shader Graph)
Note: You are creating a Shader Graph, not a Shader! The Shader Graph is currently further down the list than the Shader menu item.
Now, before we dive into editing our graph, we are going to create a material and assign our shader to our material. And we are going to create a sphere and assign our material to that sphere.
For now, hide most of the default created objects in the scene (click on each one in the Hierarchy, then uncheck them in the Inspector.) Leave the Main Camera and Directional Light active.
Then create a new 3D sphere. (GameObject -> 3D Object -> Sphere). A sphere is created at the center of the Scene (make sure you are in Scene View.)
Scale the Sphere so it is easier to see (select it, click the Scale Tool button in the upper left corner, then Left-Click and Drag the center of the 3D widget that appears.)
Create a new Material. Either Right-Click in the Project-Assets Window and Create -> Material, or select Assets from the top menu bar and Assets -> Create -> Material. Name the material BasicShaderMat.
Note: For simplicity, I am purposely keeping both the shader graph and the material using it at the top level of Assets. In a real project, you would likely group materials together in a folder, and shader graphs in a folder. You might want to keep code-based shaders in a different folder than shader graphs, just for ease of identification.
Now, you can either Left-Click drag the material in Assets onto the Sphere in the Scene. Or, you can select the Sphere in the Scene, then assign the Material via the Inspector. (You will find the Material Selection under Mesh Renderer. Click the circle to the right of the current Material then select your Material from the list. You can also Left-Click drag your Material onto the Material name under Materials in the Mesh Renderer component.
Now we will assign the shader to the Material. You can again Left-Click drag the shader icon onto the Material icon (within the Assets window). OR, Left-Click drag the shader icon onto the BasicShaderMat component in the Inspector (onto the shader dropdown area). OR you can select your shader from the dropdown area of the BasicShaderMat component (see image).
Note: Currently, shader graphs are under the graphs menu item in the Material Component Shader dropdown. This may change in later releases to allow shader writers to customize where shaders are listed. This is a common practice with code-based shaders.
Open the Shader Graph Editor (Step 4):
In the Assets part of the Project Window, click on the shader graph icon (BasicShader). In the Inspector, you'll see information about the shader. Ignore most of this, this is just a basic tutorial. You will also very likely see warnings under Errors - truncation warnings. These are just warnings and have to do with how Unity is implementing Shader Graph parameters. Ignore them for now.Advanced Note:
The other information has to do with how the shader is to be setup in the rendering pipeline. It's important to remember that you are not truly creating a shader with a shader graph, nor shader code, nor even Unity's Standard Shader. You are actually setting up parameters and logic that define how you want your shader to behave. A shader has to be compiled before it is truly a shader. Even Unity's Standard Shader is really just code (an app, in a sense) within the larger Unity Editor system that lets you define the type of shader you want. Then when you're ready to build your application, Unity will compile your instructions and create (typically) a series of shaders that might be needed. Yes, it sounds complicated. It's an advanced topic, and for basic shader creation, especially using the Shader Graph editor, you don't need to worry about such details.If you want to get a feel for what will happen when your shader is compiled, click the Down Arrow on the Compile And Show Code button. That's a lot of "what if" shader variants being generated. Each one is designed to handle a particular configuration of device. Shaders are customized a great deal for the target platform/device.
Now, to open the Shader Graph either click the Open Shader Editor button in the Inspector (with the shader graph asset selected). OR you can Left-Double-Click the shader graph asset icon (in the Project Assets window).
The Shader Graph editor is opened. Play around with the three windows. You can move and resize them.
You may have to Left-Click and pull the PBR Master node out from under the Properties sub-window. You can move the Blackboard/Property Window and the Preview window by Left-Clicking and dragging them by their Title bar. The PBR master node (currently) can be dragged by clicking practically anywhere.
The Property window (also now known as the Blackboard Window) (in the picture, it is Upper Left) will show any properties you create for your shader graph. These properties will allow users of your shader to make changes, for example, to assign a texture to the shader or to assign a color to use. With code-based shaders, you do something very similar. It's how you create a User Interface to your shader. Otherwise, you can still assign textures, colors and so forth with the editor (your shader network) but someone using your shader (in the Unity Editor/Inspector interface) can't make any changes to your choices.
Right now, I see that it says Blackboard in faint lettering. I'm calling it the Property window for convenience since that's what it lists, but Unity is calling it the Blackboard now. I'll try to remember to call it both. Again, it's beta. Names may change over time.
The Preview Window (in the picture, it is Lower Right), will show you a preview of what your shader will output. You'll notice, as I did, that occasionally it will go 'blank'. It doesn't matter if you select a particular 'mesh' form to use for the preview, it may still go blank. I've found that click and moving the PBR Master node automatically forces a refresh of the Preview and brings back the output. Also, as I just mentioned, you can select a 'Mesh' to use for the Preview. For now, leave it at 'none' or select 'sphere'. Currently, the default is a sphere.
Working with Default PBR Inputs (Step 5):
You'll notice that the PBR Master node already has a number of connections (input nodes). These are defaults. If you click on them, you'll see that you can edit them (such as clicking on the gray box connected to Albedo brings up the Color Picker. It is assigning a color to the shader's Albedo input.)The PBR Master node is based on Physically-Based Rendering, which aims to model the real world more closely than earlier non-PBR shader models. PBR is a huge topic, for a quick introduction, you can go here (wikipedia).
Note: Most shaders I have written (code-based) are not PBR. Often I am trying to mimic the real world without weighing the shader down with intensive real-world lighting equations. I do that for performance reasons, as mobile development is very tight on resources. I also like writing shaders that are simply NPR (non-photorealistic). Cartoon shadering, shaders that look like a watercolor painting or sketch are examples of NPR shaders.
Click the default input node attached to Albedo and bring up the Color Picker. Change the color. You'll see the change propagated to the PBR Master node and the Preview window. Now, click Save Asset in the Shader Graph Editor (Upper Left button). The shader has been saved.
Move the Shader Graph window to the side and look at your scene with the Sphere. You should see that your sphere has turned that color. If it hasn't (and you did Save Asset) then double check to make sure that the shader being used by your material is BasicShader. (Check the dropdown selection in the Material Component of the Inspector.)
Also note that these default inputs to the PBR Master node DO NOT translate into properties that are visible in the Inspector. You can change the color in the Shader Graph Editor, but you cannot make those same changes in the Inspector.
Create a Custom Custom Property (Step 6):
So, for our first basic shader, we will add a property and a color that will feed the Albedo input of the PBR Master.First, click the 'Plus' (+) sign in the Blackboard/Property Window. A dropdown appears showing you the types of properties you can create. Select Color. A new color property appears in the window with the name hi-lighted so you can edit it to something more descriptive than Color.
Change the name to Diffuse. It's a shout-out to an older term for the base color of a material, the diffuse reflected color, which was really a generalization since a real object is much more complex than that. With PBR we use Albedo, which in its idealized, constant state is simply Diffuse, but encompasses more complexity when trying to truly replicate light in the real world.
If you click on the black rectangle, the color picker will appear. Pick a color you like.
As for the Default dropdown, leave it as it is. We are not doing a HDR (High-Dynamic Range) shader.
Left-Click the Diffuse Property in the Blackboard/Property Window (clicking on the name is a good spot) and drag your pointer outside the window and into an empty space of the editor. A Property Node appears called Property but with Diffuse(4) in the window with a circle next to Diffuse(4). You'll see that the arrow (down) controls the visibility of the window. If you click on the arrow, it changes to > and hides the details of the property. The 4 in Diffuse(4) indicates four elements to the parameter, in this case, RGBA, since it's a Color property. Move the Property to the left of the PBR Master for layout simplicity.
If you Left-Click on the circle next to Diffuse(4) and drag, you'll see a connection appear. Ideally, you should just be able to drag it to the input (the circle next to Albedo) and the two will hook together. Sometimes thought, if you try to Drop it onto the input of Albedo(3), you'll find that it won't connect. In fact, a menu will likely appear asking you if you want to create a node. The targeting in the editor seems a little hit-and-miss sometimes. So sometimes you should do it in reverse, click the input circle of Albedo(3) and drag/drop it onto the output of the Diffuse property.
The Diffuse property is now connected to the input for Albedo in the PBR Master. The color you picked for your Diffuse is now the color of Albedo.
Click Save Asset and look at your Scene's sphere. It should now be the color you chose. AND you should see Diffuse as an editable property in your shader (under the Material Component in the Inspector when the sphere is selected.)
Adding a Custom Texture Property (Step 7):
I know we've covered a lot, but let's cover one more common type of node connection. Let's create a texture property (so our user's can select their own textures) and input that texture to Albedo. In other words, we want to map a 'base' texture, not simply a 'base' color, to our sphere object.First, Right-Click the connection between our Color Property Node and Albedo. You should see a popup that says Delete. Select it and delete the connection.
As with Color, we will first create a property in the Blackboard/Property Window. Click the + (Plus) sign and select Texture. Name it DiffuseTexture. For fun, select a Default texture to use. I will simly use UISprite (a rough square on a transparent background). Now Left-Click the DiffuseTexture name and drag it to an open spot in the Shader Graph editor. A Property node is created containing DiffuseTexture(T).
However, unlike Color, this time if you try to connect Albedo(3). it doesn't work. You likely get a popup menu asking you if you want to Create a node. You don't. This is because, unlike the Color property, we need another node in-between - a node for an actual Texture.
Right-Click in the Shader Graph Editor (in an empty space) and a dropdown menu will appear. Select Create Node. Another window will appear. Now, if you know the name of the type of node you want to create, you can search for it in the Search box at the top. In this case, we are looking for Texture. To speed things up, type Texture in the Search box.
Three items come up: Texture 2D Asset, Property: DiffuseTexture, and Sample Texture 2D.
The second is the Property that we created, so one of the other two must be what we need. See image showing all three nodes.
You can see that only Sample Texture 2D has inputs as well as outputs. We need to input our Property choice and output the result through a node that handles textures. So that is the node we need. Create one.
As for Texture 2D Asset, you'll quickly find that you can't connect the output of that node to Albedo's input either. It is the same as the property in function, except it's not a visible property.
Now connect the output of DiffuseTexture to the Texture(T) input of Sample Texture 2D. Inputs are on the Left side of a node, outputs are on the Right side. And then connect RGBA(4) output of Sample Texture 2D to the Albedo(3) input. You'll see the output of the PBR Master and the Preview both change to reflect the next texture.
Note: You can click in the Preview window and rotate the sphere to get a fuller look at the texture.
Click the Save Asset button to save the shader and take a look at your sphere object in the Scene view. The texture you chose in the Shader Graph isn't there. However, the DiffuseTexture property is now available. Add UISprite as your texture.
UISprite is a transparent texture, or it's supposed to be. Here you see the transparent areas as black. (You may have to rotate the sphere to see the black areas.) So what happened? Why aren't those black areas transparent?
Note: If you know about shaders, you might try changing the RenderQueue dropdown choice from "From Shader" to "Transparent" in the Inspector/Material Component. It doesn't do any good. The problem is at the shader level. And apparently, it won't force an override. I don't know if Unity will change this later into the beta or not. For now, assume you need to use From Shader for custom shaders and deal with renderqueue issues within the shader. If someone knows different, please comment, as I would prefer the ability to override in the Inspector, too.
Go back to the Shader Graph Editor and look more closely at the PBR Master node. You'll see a dropdown that is set to Opaque. This is telling Unity to create a shader that is opaque. A shader that does not do any transparency. Set the dropdown to AlphaBlend. This will tell Unity to build a shader that uses transparency and wants it blended with other objects.
But that isn't all. If you Save Asset and look at your scene, you still don't see any transparency. What's missing is the alpha channel. You need to feed the alpha channel from your texture to the PBR Master. Right now you are just feeding RGBA to Albedo. Now the 3 in Albedo(3) makes more sense. Albedo is only taking the first three channels of RGBA, ignoring the alpha.
All you need to do is connect the alpha in Sample Texture 2D, the A(1) output, to the Alpha(1) input on the PBR Master node.
Now you immediately see the PBR Master and the Preview window show transparency in their visualization.
Click Save Asset and check your Scene. Transparency is now being correctly shown.
Conclusion:
Congratulations! You have not only set up your 2018.1 Unity beta and Shader Graph, but created a basic shader.Note: Just a reminder that this is beta code. During the making of this tutorial, I had the Shader Graph go a little wacky on me as I played with Running the scene, then changing the RenderQueue to Transparent, then running again, then back. During this, the Shader Graph suddenly stopped working and hung. And I lost transparency. So just keep that in mind as you play with the Shader Graph and render settings. Keep a backup and don't use the beta for shippable code.
But why did I not delete the Diffuse color property? In the next tutorial post, we'll be digging deeper into shader creation. We'll be combining color (as a Tint) with textures, as well as looking at UV textures, Normal maps, specular effects, dynamic effects and maybe a bit more. This was just a warm up.
As an exercise, I recommend you play a bit more with the Shader Graph and also re-read Matt Dean's posts regarding the Shader Graph. As I experiment more with the Shader Graph Editor, I find I pick up more information from Matt's posts.
update: it's Matt Dean not Matt Helm. doh! Somehow I fixated on an old 1960s movie when I was writing this!! Sorry Matt!
Next Tutorial:
copyright 2018 cg anderson - all rights reserved
Dude amazing work on explaining it!
ReplyDelete