Unity 5 Shader Programming #3: Specular Light

image

Hi, and welcome to Tutorial 3 of my Unity 5 Shader Programming tutorial. Today we are going to implement an other lighting algorithm called Specular Light. This algorithm builds on the Ambient and Diffuse lighting tutorials, so if you haven’t been trough them, now is the time. 🙂

Specular Light

So far, we got a basic light model to illuminate objects. But, what if we got a blank, polished or shiny object we want to render? Say a metal surface, plastic, glass, bottle and so on? Diffuse light does not include any of the tiny reflections that make a smooth surface shine.

To simulate this shininess, we can use a lighting model named Specular highlights.
Specular highlights calculates another vector that simulates a reflection of a light source, which hits the camera, or “the eye”.

What’s “the eye” vector, you might think? Well, it’s a pretty easy answer to this. It’s the vector that points from our camera position to the camera target.

One way to calculate the specular light is

I=Ai*Ac+Di*Dc*N.L+Si*Sc*(R.V)n

Where

R=2*(N.L)*N-L

This is called the Phong model for specular light.

This model calculates the angle between the Reflection Vector and the View vector. It describes how much of the reflection hits directly on the camera lens.

There is another way of calculating this called the Blinn-Phong model where you don’t need to calculate the reflection vector all the time.

 

Blinn-Phong?

In Blinn-Phong, instead of calculating the reflection vector R, we calculate the halfway vector between the view and the light direction vector, meaning we can replace the dot product between R and V with the dot product between N and H.

 

 

image

where H:

image

Then we have a parameter n that describes how rough the surface is.

The biggest visual difference between these two implementations is that while Phong will always have a circular shape, the Blinn-Phong will have an elliptical shape from steep angles. This mimics the real world.

Both models got their pros and cons that we won’t discuss in this article.

 

Implementation

The implementation is straight forward, nothing new from the previous tutorials. In other words, let’s get started with the source:

Shader "UnityShaderTutorial/Tutorial3SpecularLight-GlobalStates" {
	SubShader
	{
		Pass
		{
			Tags{ "LightMode" = "ForwardBase" }

			CGPROGRAM
			#include "UnityCG.cginc"

			#pragma target 2.0
			#pragma vertex vertexShader
			#pragma fragment fragmentShader

			float4 _LightColor0;

			struct vsIn {
				float4 position : POSITION;
				float3 normal : NORMAL;
			};

			struct vsOut {
				float4 screenPosition : SV_POSITION;
				float4 position : COORDINATE0;
				float3 normal : NORMAL;
			};

			vsOut vertexShader(vsIn v)
			{
				vsOut o;
				o.screenPosition = mul(UNITY_MATRIX_MVP, v.position);
				o.normal = normalize(mul(v.normal, _World2Object));
				o.position = v.position;

				return o;
			}

			float4 fragmentShader(vsOut psIn) : SV_Target
			{
				float4 ambientLight = UNITY_LIGHTMODEL_AMBIENT;

				float4 lightDirection = normalize(_WorldSpaceLightPos0);

				float4 diffuseTerm = saturate( dot(lightDirection, psIn.normal));
				float4 diffuseLight = diffuseTerm * _LightColor0;

				float4 cameraPosition = normalize(float4( _WorldSpaceCameraPos,1) - psIn.position);

				// Blinn-Phong
				float4 halfVector = normalize(lightDirection+cameraPosition);
				float4 specularTerm = pow( saturate( dot( psIn.normal, halfVector)), 25);

				// Phong
				//float4 reflectionVector = reflect(-lightDirection, float4(psIn.normal,1));
				//float4 specularTerm = pow(saturate(dot(reflectionVector, cameraPosition)),15);

				return ambientLight + diffuseLight + specularTerm;
			}

			ENDCG
		}
	}
}

There are two main differences here, we need the vertex position in the shader, as well as the code that calculates the updated light equation.

image

This is just a pass-through from the Vertex Shader.

Then we need to do the specular calculation itself.

image

First we get the position of the camera by using the built in variable WorldSpaceCameraPos and the vertex position.

Then we calculate the half vector by normalizing the light direction added with camera positon.

The last thing we need to calculate is the specular term itself, H.V – and add it to our existing lighting equation. Here we are using a function called pow(x,y) what raises the specified value X with the specified power Y,

25 is the shininess factor, feel free to play around with the value.

As you can see, we didn’t use any new

Downloads:

Download the source from GitHub here:
https://github.com/petriw/UnityShaderProgramming/tree/master/3 – Specular Light

This entry was posted in Shaders, Tutorial, Unity. Bookmark the permalink.

3 Responses to Unity 5 Shader Programming #3: Specular Light

  1. Aditya Muley says:

    Hi.. These tuts are really informative and helped me understand unity shader programming. I was actually looking for some help on unity 5 double sided shader., and saw these post. If you could do one more tut. for a double sided shader for Unity 5, please do it. It will be a great help.
    Thanks 🙂

  2. Dark Keny says:

    Hello,
    I have a question, Why do you use negative lightDirection when you calculate the reflectionVector in the Phong model?
    Thanks. Great tutorial!!!

  3. Jacelyn Rebera says:

    This website is just gret. I’ve search these info
    a long time and I realised that is good written, easy to understand.
    I congratulate you for this article that I am going to recommend to people around.

    I ask you to go to the gpa-calculator.co site where each pupil or pupil can find ratings grade
    point average marks. All good!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.