Introduction to shader notes 12 implementation of various simple lighting models

1, Ambient light and self illumination

Control ambient light:
Window->Lighting->Ambient Source/Ambient Color/Ambient Intensity
In the Shader, you can get the ambient light information through unity? Lightmode? Ambient.

Self luminous:
Most objects do not have self illumination characteristics, and there are few calculations in shaders.
If you have to calculate, just add the self illumination of the material to the output color before the chip shader outputs the last color.

2, Realization of diffuse illumination model

Function: saturate (x) --- x can be scalar or vector, float, float2, float3.
Function: intercept X in the range of [0,1]. If x is a vector, it will operate on each component.

Function: reflect (I, n) ---- I is the incident direction (the light source points to the intersection, note that the worldLightDir provided in Unity is reverse and needs to take a negative number), n is the normal direction. Return to reflection direction
Function: calculate the reflection direction of the incident direction.

1. Achieve diffuse effect per vertex:

Code:

Shader "Unity Shaders Book /Chapter 6/Diffuse Vertex-Level"   //Name
{
	Properties { _Diffuse("Diffuse",Color)=(1,1,1,1) } //Set material properties - diffuse color

	SubShader
	{
	 Pass{
	 	Tags{ "LightMode"="ForwardBase" } //Pass label, set the correct LightMode, then you can get the built-in lighting variable of Unity, such as (below 65124; LightColor0)
	 	
		CGPROGRAM
		
		#pragma vertex vert
		#pragma fragment frag
		#include "Lighting.cginc" / / introduce the Unity built-in file to use built-in variables (such as "lightcolor0")
		fixed4 _Diffuse; //Referencing variables in properties

		struct a2v
		{ 
			float4 vertex : POSITION;
			float3 normal : NORMAL;
		};
		struct v2f
 	        { 
			float4 pos : SV_POSITION;
			flxed3 color : COLOR;
		};
  		
  		v2f vert(a2v v)
  		{
  			v2f o;
  			o.pos = mul( UNITY_MATRIX_MVP, v.vertex ); //Model space to crop space
  			fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; //Get ambient light
  			fixed3 worldNormal = normalize( mul(v.normal,(float3×3)_World2Object) ); //Get normals: converts the normals of model space into world space and into unit vectors
  			fixed3 worldLight = normalize( _WorldSpaceLightPos0.xyz ); //Get light direction
  			fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*saturate( dot(worldNormal,worldLight) ); //Calculating diffuse illumination model
  			o.color = ambient + diffuse; //Calculation includes ambient and diffuse
  			return o;
  		}
  		fixed4 frag(v2f i): SV_Target
  		{
  			return fixed4(i.color,1.0); //Slice shader returns vertex color directly
  		}
		
		ENDCG
		
	    } 
	}
	Fallback "Diffuse"
}

2. Achieve pixel by pixel diffuse effect

Pixel by pixel lighting gives a smoother lighting effect.

Shader "Unity Shaders Book /Chapter 6/Diffuse Pixel-Level"
{
	Properties { _Diffuse("Diffuse",Color)=(1,1,1,1) } //Set material properties - diffuse color
	SubShader
	{
		Pass
		{
			Tags{ "LightMode"="ForwardBase" } //Pass label, set the correct LightMode, then you can get the built-in lighting variable of Unity, such as (below 65124; LightColor0)
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "Lighting.cginc" / / introduce the Unity built-in file to use built-in variables (such as "lightcolor0")
			fixed4 _Diffuse; //Referencing variables in properties
 			struct a2v
			{ 
 				float4 vertex : POSITION;
   				float3 normal : NORMAL;
  			};
  			struct v2f
 		        { 
				float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0; //The contrast here is to change the color transfer to texture coordinate transfer (transfer normals).
			};
			v2f vert(a2v v)
			{
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
				o.worldNormal = mul(v.normal,(float3×3)_World2Object); //Normals are still taken in vertex shaders and converted to world coordinates.
				return o;
			}
			fixed4 frag(v2f i):SV_Target
			{
				fixed3 ambient = UNTIY_LIGHTMODEL_AMBIENT.xyz; //Ambient light
				fixed3 worldNormal = normalize(i.worldNormal); //Convert normal to unit vector
				fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); //Unit vector of light direction
				fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal,worldLightDir)); //Calculates the diffuse.
				fixed3 color = diffuse+ambient;
				return fixed4(color,1.0);				
			}
			ENDCG
		}
	}
	Fallback "Diffuse"
}

3. Realization of semi Lambert illumination model

The diffuse light model we used earlier is also called Lambert model,
Lambert's Law: the light intensity of diffuse reflection light at a point in the plane is directly proportional to the normal vector of the reflection point and the cosine value of the angle of the incident light.
The half Lambert model can improve the above two kinds of reflection when the backlight is the same shade.
Half Lambert lighting model is a technology proposed by Valve company when it developed half life. It has no physical basis but visual enhancement.
The formula of light model: c(diffuse)=(c(light) · m(diffuse))(a(n · l)+b), in general, a and B are 0.5.

Changes the per pixel diffuse illumination model's slice shader.

fixed4 frag(v2f i):SV_Target
   {
	fixed3 ambient = UNTIY_LIGHTMODEL_AMBIENT.xyz; //Ambient light
 	fixed3 worldNormal = normalize(i.worldNormal); //Convert normal to unit vector
  	fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); //Unit vector of light direction

	fixed3 halfLambert = dot(worldNormal,worldLightDir)*0.5+0.5; //The calculation of half Lambert is to map (n · l) results from [- 1, 1] to [0, 1].
	fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*halfLambert; //Calculate the illumination effect of the half Lambert illumination model.
 	fixed3 color = diffuse+ambient;
	return fixed4(color,1.0);    
   }
   

4. Realize the specular model of vertex by vertex illumination

Code:

Shader "Untiy Shaders Book/Chapter 6/Specular Vertex-Level"
{
	Properties
	{
		_Diffuse ("Diffuse",Color)=(1,1,1,1)  //Diffuse attribute - color
		_Specular ("Specular",Color)=(1,1,1,1) //Control specular attributes
		_Gloss ("Gloss",Range(8.0,256))=20 //Control highlight area size
	}
	SubShader
	{
		Pass
		{
			Tags {"LightMode"="ForwardBase"}//Pass label, set the correct LightMode, then you can get the built-in lighting variable of Unity, such as (below 65124; LightColor0)
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "Lighting.cginc" / / introduce the Unity built-in file to use built-in variables (such as "lightcolor0")
			fixed4 _Diffuse;
			fixed4 _Specular;
			fixed4 _Gloss;//The above three attributes are introduced
			struct a2v
			{
				float4 vertex: POSITION;
				float3 normal : NORMAL;
			};
			struct v2f
			{
				float4 pos : SV_POSITION;
				fixed3 color : COLOR;
			};
			v2f vert(a2v v)
			{
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP,v.vertex);//Convert model space to crop space
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//Get ambient light
				fixed3 worldNormal = normalize(mul(v.normal,(float3×float3)_World2Object));//Get normals and convert to world coordinates
				fixed3 worldLightDir = normallize(_WorldSpaceLightPos0.xyz);//Get the incident light and drop it to
				fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal,worldLightDir));//Calculate diffuse
				fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal));//Calculate the direction of reflected light and reverse it
				fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz-mul(_Object2World,v.vertex).xyz);Get perspective direction
				fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(reflectDir,viewDir)),_Gloss);//Calculate specular part
				o.color=ambient+diffuse+specular;//Add additivity
				return o;
			}
			fixed4 frag(v2f i) : SV_Target
			{
				return fixed4(i.color,1.0);
			}
		}
	}
	Fallback "Specular" 
}

The specular effect obtained by vertex by vertex method is not smooth.
Because the specular calculation is non-linear, and the calculation is linear in the vertex shader, there will be a larger visual problem.
So we need to use pixel by pixel method to calculate specular reflection.

5. Implement pixel by pixel specular model

Code:

Shader "Untiy Shaders Book/Chapter 6/Specular Pixel-Level"
{
	 Properties
	 {
		  _Diffuse ("Diffuse",Color)=(1,1,1,1)  //Diffuse attribute - color
		  _Specular ("Specular",Color)=(1,1,1,1) //Control specular attributes
		  _Gloss ("Gloss",Range(8.0,256))=20 //Control highlight area size
	 }
	 SubShader
	 {
		  Pass
		  {
			   Tags {"LightMode"="ForwardBase"}//Pass label, set the correct LightMode, then you can get the built-in lighting variable of Unity, such as (below 65124; LightColor0)
			   CGPROGRAM
			   #pragma vertex vert
			   #pragma fragment frag
			   #include "Lighting.cginc" / / introduce the Unity built-in file to use built-in variables (such as "lightcolor0")
			   fixed4 _Diffuse;
			   fixed4 _Specular;
			   fixed4 _Gloss;//The above three attributes are introduced
			   struct a2v
			   {
				    float4 vertex: POSITION;
				    float3 normal : NORMAL;
			   };
			   struct v2f
			   {
				    float4 pos : SV_POSITION;
				    float3 worldNormal : TEXCOORD0;
				    float3 worldPos : TEXCOORD1;
			   };
			   v2f vert(a2v v)
			   {
				    v2f o;
				    o.pos = mul(UNITY_MATRIX_MVP,v.vertex);//Convert model space to crop space
				    o.worldNormal = mul(v.normal,(float3×3)_World2Object);//Transfer normals to tiles
				    o.worldPos = mul(_Object2World,v.vertex).xyz;//Transfer vertex coordinates to slice elements
				    return o;
			   }
			   fixed4 frag(v2f i) : SV_Target
			   {
				    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//Get ambient light
				    fixed3 worldNormal = normalize(i.worldNormal);//Get normal, unit Vectorization
				    fixed3 worldLightDir = normallize(_WorldSpaceLightPos0.xyz);//Get incident light, unit Vectorization
				    fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal,worldLightDir));//Calculate diffuse
				    fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal));//Calculate the direction of reflected light and reverse it
				    fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz-i.worldPos.xyz);Get perspective direction
				    fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(reflectDir,viewDir)),_Gloss);//Calculate specular part
				    return fixed4(ambiet+diffuse+specular,1.0);Computation and
			   }
		  }
	 }
	 Fallback "Specular" 
}

According to the above pixel by pixel method, you can get a smoother effect, which is the complete Phong lighting model.

6. Implement Blinn Phong model

Change the code in the chip shader:

fixed4 frag(v2f i) : SV_Target
			   {
				    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//Get ambient light
				    fixed3 worldNormal = normalize(i.worldNormal);//Get normal, unit Vectorization
				    fixed3 worldLightDir = normallize(_WorldSpaceLightPos0.xyz);//Get incident light, unit Vectorization
				    fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal,worldLightDir));//Calculate diffuse				    
				    fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz-i.worldPos.xyz);Get perspective direction
				    fixed3 halfDir = normalize(worldLightDir+viewDir);//Calculate h in Blinn Phong.
				    fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(max(0,dot(worldNormal,halfDir)),_Gloss);//Calculate the specular part (Blinn Phong)
				    return fixed4(ambiet+diffuse+specular,1.0);Computation and
			   }

The specular part of the Blinn Phong lighting model looks larger and brighter.
In many practical renderings, we will choose Blinn Phong model.
These two lighting models are both empirical models, Blinn Phong is not an approximation of Phong model, because sometimes Blinn Phong is more consistent with the results.

3, Using built-in functions in Unity

The above calculation of light source direction, viewing angle direction, etc. is only applicable to the parallel light.
When we calculate the point light source, spotlight and so on, the above method is not applicable.

Note: the return value of the above function is not unit vector. Remember to change it into unit vector before use.
To calculate the light direction, you need to pay attention to forward rendering. In the forward rendering, its internal built-in variable ﹐ WorldSpaceLightPos(), etc. will be assigned correctly.
What is forward rendering, Chapter 9. Write a link to Chapter 9.

Published 22 original articles, won praise 3, visited 3294
Private letter follow

Tags: Unity Fragment Attribute

Posted on Thu, 13 Feb 2020 00:22:11 -0800 by madkris