Book Image

Unity 2021 Shaders and Effects Cookbook - Fourth Edition

By : John P. Doran
Book Image

Unity 2021 Shaders and Effects Cookbook - Fourth Edition

By: John P. Doran

Overview of this book

Shaders enable you to create powerful visuals for your game projects. However, creating shaders for your games can be notoriously challenging with various factors such as complex mathematics standing in the way of attaining the level of realism you crave for your shaders. The Unity 2021 Shaders and Effects Cookbook helps you overcome that with a recipe-based approach to creating shaders using Unity. This fourth edition is updated and enhanced using Unity 2021 features and tools covering Unity's new way of creating particle effects with the VFX Graph. You'll learn how to use VFX Graph for advanced shader development. The book also features updated recipes for using Shader Graph to create 2D and 3D elements. You'll cover everything you need to know about vectors, how they can be used to construct lighting, and how to use textures to create complex effects without the heavy math. You'll also understand how to use the visual-based Shader Graph for creating shaders without any code. By the end of this Unity book, you'll have developed a set of shaders that you can use in your Unity 3D games and be able to accomplish new effects and address the performance needs of your Unity game development projects. So, let's get started!
Table of Contents (16 chapters)

Creating a basic Standard Shader

In Unity, when we create a GameObject, we attach additional functionality through the use of components. Every GameObject is required to have a Transform component; there are several components included in Unity already, and we create components of our own when we write scripts that extend from MonoBehaviour.

All the objects that are part of a game contain several components that affect their look and behavior. While scripts determine how objects should behave, renderers decide how they should appear on the screen. Unity comes with several renderers, depending on the type of object that we are trying to visualize; every 3D model typically has a MeshRenderer component attached to it. An object should have only one renderer, but the renderer itself can contain several materials. Each material is a wrapper for a single shader, which is the final ring in the food chain of 3D graphics. The relationships between these components can be seen in the following diagram:

Figure 2.1 – Relationship between shaders, models, materials, and objects

Figure 2.1 – Relationship between shaders, models, materials, and objects

Note that the preceding diagram mentions Cg code. Cg is only the default for the built-in renderer. URP/HDRP defaults to using HLSL code.

Understanding the difference between these components is essential for understanding how shaders work.

Getting ready

To get started with this recipe, you will need to have Unity running and must have a project opened using the built-in renderer. (In my case, I am using the 3D template. If you're using Unity Hub 3, go to Core | 3D.) As we mentioned previously, a Unity project has been included with this cookbook, so you can use that one as well and simply add custom shaders to it as you step through each recipe. Once you've done this, you will be ready to step into the wonderful world of real-time shading!

Note

If you are using the Unity project that came with this cookbook, you can open the Chapter 2 | Scenes | Starting Point scene instead of completing the Getting ready section as it has been set up already.

Before we create our first shader, let's create a small scene for us to work with:

  1. Let's create a scene by navigating to File | New Scene. A dialog window will appear, asking what template should be used. Select 3D and then click on the Create button:
    Figure 2.2 – New Scene window

    Figure 2.2 – New Scene window

  2. Once you've created the scene, create a plane that will act as the ground by going to the Unity Editor and selecting GameObject | 3D Object | Plane from the top menu bar:
    Figure 2.3 – Creating a Plane

    Figure 2.3 – Creating a Plane

  3. Next, select the object in the Hierarchy tab and then go into the Inspector tab. From there, right-click on the Transform component and select the Reset Property | Position option:
    Figure 2.4 – Resetting the position of the object

    Figure 2.4 – Resetting the position of the object

    This will reset the Position property of the object to 0, 0, 0, which is the center of our game world.

  4. To make it easier to see what our shaders will look like when applied, let's add some shapes to visualize what each of our shaders will do. Create a sphere by going to GameObject | 3D Object | Sphere. Once created, select it and go to the Inspector tab. Next, change Position to 0, 1, 0 so that it is above the origin of the world (which is at 0, 0, 0) and our previously created plane:
    Figure 2.5 – Adding a sphere

    Figure 2.5 – Adding a sphere

  5. Once this sphere has been created, create two more spheres and place them to the left and right of the sphere at -2, 1, 0 and 2, 1, 0, respectively:
    Figure 2.6 – Completing our scene

    Figure 2.6 – Completing our scene

    Note

    One quick way to do this is to duplicate the objects by hitting the Ctrl + D keys while having the object selected in the Hierarchy window. You can rename the objects via the top textbox in the Inspector window.

  6. Confirm that you have directional light (it should be in the Hierarchy tab). If not, you can add it by selecting GameObject | Light | Directional Light to make it easier to see your changes and how your shaders react to light.
  7. The example code for this book can be found in a folder called Chapter 2. This folder holds all the code for this chapter. To organize your code, create a folder by going to the Project tab in the Unity Editor, right-clicking, and selecting Create | Folder. Rename the folder Chapter 2.

How to do it...

With our scene generated, we can start writing the shader:

  1. In the Project tab in the Unity Editor, right-click on the Chapter 2 folder and select Create | Folder.
  2. Rename the folder that you created to Shaders by right-clicking on it and selecting Rename from the drop-down list, or by selecting the folder and hitting F2 on the keyboard.
  3. Create another folder and rename it Materials. Place this folder inside the Chapter 2 folder as well.
  4. Right-click on the Shaders folder and select Create | Shader | Standard Surface Shader. Then, right-click on the Materials folder and select Create | Material.
  5. Rename both the shader and material to StandardDiffuse.
  6. Launch the StandardDiffuse shader by double-clicking on the file. This will automatically launch a scripting editor for you (Visual Studio, by default) and display the shader's code.

    Note

    You will see that Unity has already populated our shader with some basic code. This, by default, will get you a basic shader that accepts one texture in the Albedo (RGB) property. We will be modifying this base code so that you can learn how to quickly start developing custom shaders.

  7. Now, let's give our shader a custom folder that it can be selected from. The very first line of code in the shader is the custom description that we have to give the shader so that Unity can make it available in the shader drop-down list when assigning it to materials. We have renamed our path to Shader "CookbookShaders/Chapter 02/StandardDiffuse", but you can name it whatever you want and rename it at any time, so don't worry about any dependencies at this point.
  8. Save the shader in your script editor and return to the Unity Editor. Unity will automatically compile the shader when it recognizes that the file has been updated. This is what the top of your shader file should look like at this point:
    Shader "CookbookShaders/Chapter 02/StandardDiffuse"
    {
        Properties
        {
            _Color ("Color", Color) = (1,1,1,1)
            _MainTex ("Albedo (RGB)", 2D) = "white" {}
            _Glossiness ("Smoothness", Range(0,1)) = 0.5
            _Metallic ("Metallic", Range(0,1)) = 0.0
        }
        SubShader
        {
            // Rest of file…
  9. Technically speaking, this is a Surface Shader based on physically based rendering (PBR). As the name suggests, this type of shader achieves realism by simulating how light physically behaves when hitting objects.
  10. Once you've created your shader, you need to connect it to a material. Select the StandardDiffuse material that we created in Step 4 and look at the Inspector tab. From the Shader drop-down list, select CookbookShaders/Chapter 02/StandardDiffuse (your shader path might be different if you chose to use a different pathname):
    Figure 2.7 – The StandardDiffuse shader has been set as the shader to use on this material

    Figure 2.7 – The StandardDiffuse shader has been set as the shader to use on this material

  11. This will assign your shader to your material so that you can assign it to an object.

    Note

    To assign a material to an object, you can simply click and drag your material from the Project tab to the object in your scene. You can also drag the material to the Inspector tab of an object in the Unity Editor to assign it.

The following screenshot shows what we have done so far:

Figure 2.8 – The created material

Figure 2.8 – The created material

There's not much to look at at this point, but our shader development environment has been set up, which means we can start to modify the shader so that it suits our needs.

How it works...

Unity has made the task of getting your shader environment up and running very easy. It is simply a matter of a few clicks and you are good to go. There are a lot of elements working in the background concerning the Surface Shader itself. Unity has taken the Cg shader language and made it more efficient to write by doing a lot of the heavy Cg code lifting for you. The Surface Shader language is a more component-based way of writing shaders. Tasks such as processing texture coordinates and transformation matrices have already been done for you, so you don't have to start from scratch anymore. In the past, we would have to start a new shader and rewrite a lot of code over and over again. As you gain more experience with Surface Shaders, you will want to explore more of the underlying functions of the Cg language and how Unity is processing all of the low-level graphics processing unit (GPU) tasks for you.

Note

All the files in a Unity project are referenced independently from the folder that they are in. We can move shaders and materials from within the editor without the risk of breaking any connections. Files, however, should never be moved from outside the editor as Unity will not be able to update their references.

So, by simply changing the shader's pathname to a name of our choice, we have got our basic diffuse shader working in the Unity environment, along with lights and shadows, just by changing one line of code!

There's more...

The source code of the built-in shaders is typically hidden in Unity. You cannot open this from the editor as you do with your own shaders. For more information on where to find a large portion of the built-in Cg functions for Unity, go to your Unity install directory (visible in the Installs section of Unity Hub, if you have it installed; select the three dots next to Installs (a gear icon in Unity Hub 3) and select the Show in Explorer option):

Figure 2.9 – The Show in Explorer option

Figure 2.9 – The Show in Explorer option

From the installation location, navigate to the Editor | Data | CGIncludes folder:

Figure 2.10 – The location of the CGIncludes folder

Figure 2.10 – The location of the CGIncludes folder

In this folder, you can find the source code for the shaders that were shipped with Unity. Over time, they have changed a lot; you can visit the Unity download archive (https://unity3d.com/get-unity/download/archive) if you need to access the source code of a shader that's been used in a different version of Unity. After choosing the right version, select Built in shaders from the drop-down list, as shown in the following screenshot:

Figure 2.11 – Unity download archive

Figure 2.11 – Unity download archive

There are three files that that are important at this point: UnityCG.cginc, Lighting.cginc, and UnityShaderVariables.cginc. Our current shader is making use of all these files at the moment. In Chapter 12, Advanced Shading Techniques, we will explore how to use CGInclude for a modular approach to shader coding.