Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Become a Unity Shaders Guru

You're reading from   Become a Unity Shaders Guru Create advanced game visuals using code and graphs in Unity 2022

Arrow left icon
Product type Paperback
Published in Jul 2023
Publisher Packt
ISBN-13 9781837636747
Length 492 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Mina Pêcheux Mina Pêcheux
Author Profile Icon Mina Pêcheux
Mina Pêcheux
Arrow right icon
View More author details
Toc

Table of Contents (23) Chapters Close

Preface 1. Part 1: Creating Shaders in Unity
2. Chapter 1: Re-Coding a Basic Blinn-Phong Shader with Unity/CG FREE CHAPTER 3. Part 2: Stepping Up to URP and the Shader Graph
4. Chapter 2: The Three Unity Render Pipelines 5. Chapter 3: Writing Your First URP Shader 6. Chapter 4: Transforming Your Shader into a Lit PBS Shader 7. Chapter 5: Discovering the Shader Graph with a Toon Shader 8. Part 3: Advanced Game Shaders
9. Chapter 6: Simulating Geometry Efficiently 10. Chapter 7: Exploring the Unity Compute Shaders and Procedural Drawing 11. Chapter 8: The Power of Ray Marching 12. Part 4: Optimizing Your Unity Shaders
13. Chapter 9: Shader Compilation, Branching, and Variants 14. Chapter 10: Optimizing Your Code, or Making Your Own Pipeline? 15. Part 5: The Toolbox
16. Chapter 11: A Little Suite of 2D Shaders 17. Chapter 12: Vertex Displacement Shaders 18. Chapter 13: Wireframes and Geometry Shaders 19. Chapter 14: Screen Effect Shaders 20. Index 21. Other Books You May Enjoy Appendix: Some Quick Refreshers on Shaders in Unity

Adding the ambient and specular components

Our shader now handles the diffuse lighting. However, we know that this is just part of a real Blinn-Phong model – we also need to have some specular reflections, and we should handle ambient lighting to better integrate it into the scene.

In the following sections, we will add both components one by one, starting with the ambient lighting since, as we will see, it is quick to do in Unity before taking care of the speculars.

Injecting the ambient lighting

Do you remember how, in the Setting up our Unity shader section, we managed to get our light direction just by calling a Unity built-in variable? Well, guess what – adding ambient lighting is just easy!

All we have to do for this step is get the UNITY_LIGHTMODEL_AMBIENT variable, and this will directly give us the ambient light to add to our previously computed diffuse component, which means we simply have to update our fragment shader function like this:

float4 frag (v2f i) : SV_Target {
    float3 N = normalize(i.normal);
    float3 L = _WorldSpaceLightPos0.xyz;
    float lambert = saturate(dot(N, L));
    float3 diffuseLight = lambert * _LightColor0.xyz;
    float3 ambientLight = UNITY_LIGHTMODEL_AMBIENT.xyz;
    return float4(diffuseLight * _Color + ambientLight, 1);
}

And with these quick modifications, we added ambient lighting to our diffuse shader. If you recompile the file, you should see that the shape is now slightly illuminated everywhere:

Figure 1.19 – Compositing of the diffuse and ambient lighting components

Figure 1.19 – Compositing of the diffuse and ambient lighting components

If you want to change the color of the ambient light, you can change this in the environment parameters of the scene. These settings are located in the Lighting window. To access them, follow these steps:

  1. Go to the Window | Rendering | Lighting menu.
  2. Switch over to the Environment tab at the top of the Lighting window.
  3. In the inspector, you will see the ambient lighting in the Environment Lighting group.

Unity offers us three ways of setting the ambient color – either with a single source color, a gradient, or a skybox, which are discussed here:

  • If you use the Color mode, then all ambient light will have the flat color you define in the color picker, as shown in Figure 1.20:
Figure 1.20 – Configuration of the ambient color for the Unity scene in the Color mode

Figure 1.20 – Configuration of the ambient color for the Unity scene in the Color mode

  • If you use the Gradient mode, you will be able to define separate colors for ambient lighting coming from the sky, the horizon, and the ground. You will have three pickers for each of those important marks, as shown in Figure 1.21, and the rest of the levels will blend between those references:
Figure 1.21 – Configuration of the ambient color for the Unity scene in the Gradient mode

Figure 1.21 – Configuration of the ambient color for the Unity scene in the Gradient mode

Note that if you use Gradient, our UNITY_LIGHTMODEL_AMBIENT variable will use the sky color by default. But you can use one of the three defined color marks by replacing UNITY_LIGHTMODEL_AMBIENT with unity_AmbientSky, unity_AmbientEquator, or unity_AmbientGround.

  • If you use the Skybox mode, then the ambient light will be computed based on the Skybox Material resource you pass in. This can help do more detailed lighting, but it requires a bit more setup. If you want to learn more about this, check out this documentation page from Unity at https://docs.unity3d.com/Manual/skyboxes-using.html.

We now have a shader with both the diffuse and ambient components, and we even know how to change the color of our ambient light to create a custom feel for our scene. However, this material is visually quite basic and very matte – so it is time to implement the final part of our shader: the specular.

Computing the specular lighting

As we discussed in the Doing a quick study of the Blinn-Phong shading model section, the only additional vector we need to prepare for computing the specular highlights with the Blinn-Phong reflection model is the view vector, V.

Remember that this is a vector that goes from the surface to the rendering eye position. To compute it, we therefore need to get the position of our main camera and the position of the fragment we are currently calculating the output value for, both in world space coordinates.

As usual, the camera position is readily available in the UnityCG.cging library. The _WorldSpaceCameraPos variable directly gives us the 3D world position of the main camera.

The world position of the vertices can be found using the vertex position in object space and the handy unity_ObjectToWorld matrix. Multiplying this matrix by the local vertex position converts the local coordinates to world coordinates and gives us its equivalent as a world position. We then simply need to pass it in the v2f data structure as our second UV set to have it interpolated and re-inputted into the fragment shader. Here are the updated parts of our shader code:

struct v2f {
    float4 vertex : SV_POSITION;
    float3 normal : TEXCOORD0;
    float3 worldPos : TEXCOORD1;
};
v2f vert (appdata v) {
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.normal = v.normal;
    o.worldPos = mul(unity_ObjectToWorld, v.vertex);
    return o;
}
float4 frag (v2f i) : SV_Target {
    float3 V = normalize(_WorldSpaceCameraPos –
        i.worldPos);
    ...
}

Here, we use the normalize function to transform our position offset into a direction.

Then, we will define our _Gloss property for the surface smoothness:

Shader "Custom/BlinnPhong" {
    Properties {
        ...
        _Gloss ("Gloss", Float) = 1
    }
    SubShader {
        Tags { "RenderType" = "Opaque" }
        Pass {
            ...
            float _Gloss;
        }
    }
}

Finally, we simply need to copy back the formulas we prepared during the theoretical analysis to first get the halfway vector, H, get the specular, apply glossiness, and use the light source color. We eventually composite all three components in the final return with a simple sum. Our following fragment shader function, therefore, looks as follows:

float4 frag (v2f i) : SV_Target {
    float3 N = normalize(i.normal);
    float3 L = _WorldSpaceLightPos0.xyz;
    float3 V = normalize(_WorldSpaceCameraPos –
        i.worldPos);
    // diffuse lighting (lambertian)
    float lambert = saturate(dot(N, L));
    float3 diffuseLight = lambert * _LightColor0.xyz;
    float3 diffuseColor = diffuseLight * _Color;
    // ambient lighting (direct from Unity settings)
    float3 ambientLight = UNITY_LIGHTMODEL_AMBIENT.xyz;
    // specular lighting (Blinn-Phong)
    float3 H = normalize(L + V);
    float3 specularLight = saturate(dot(N, H)) *
        (lambert > 0);
    specularLight = pow(specularLight, _Gloss) *
        _LightColor0.xyz;
    return float4(diffuseColor + ambientLight +
        specularLight, 1);
}

At the very top, we get the three vectors we require for the diffuse and specular lighting, then we compute each component, and finally, we composite them. The following diagram shows how different primitive objects look with our associated material applied to them:

Figure 1.22 – Some applications of our final shader with the diffuse, ambient, and specular lighting components

Figure 1.22 – Some applications of our final shader with the diffuse, ambient, and specular lighting components

We have successfully implemented the model we wanted with the following components:

  • The diffuse component uses the color of the surface and the light to create a base lighting that is the same no matter where the camera is
  • The ambient component slightly impacts all the shapes in the render and brings out the shadows
  • The specular component varies depending on the position of the rendering camera, and it simply reflects the color of the light to make this shiny plastic-like effect

There are, of course, an infinite number of ways to tweak and modify all of our settings and simulate other types of materials. Even if Blinn-Phong is a crude lighting model, we know that changing the size of the specular highlights or tinting them with the surface color can already give quite a different feel, and we also said that ambient lighting is optional.

So, to further improve this shader, let’s take a bit of time to review Unity’s tool for creating easy-to-use and well-controlled material inspectors.

You have been reading a chapter from
Become a Unity Shaders Guru
Published in: Jul 2023
Publisher: Packt
ISBN-13: 9781837636747
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image