Unity实现标准光照模型的Shader代码

本文展示实现标准光照模型(只关心场景里最亮的那一个平行光光源)下的光照效果。即自发光(Emissive)、环境光(Ambient)、漫反射(Diffuse)、高光(Specular)这四种光效的叠加,其中高光有两种实现方式Phong和Blinn-Phong,选择调用方法即可。

下面介绍面板参数:

_XXX_Color表示材质反射该光照的颜色,如果是黑色则表示忽略该光照;

_Calculate_Vertex决定使用顶点光照还是像素光照(大于1还是小于1);

_Lambert_Enhance是漫反射光照增强,如果值为0.5,就是常说的Half Lambert光照模型;

_Gloss是高光反射扩散度,值越小光斑越大。

下面分别是顶点光照和像素光照的效果:


最后上Shader代码:

Shader "Test/S001"
{
	Properties
	{
		_Calculate_Vertex ("_Calculate_Vertex", Range (0, 2)) = 0
		_Emissive_Color("_Emissive_Color", Color) = (1, 1, 1, 1)
		_Ambient_Color("_Ambient_Color", Color) = (1, 1, 1, 1)
		_Diffuse_Color("_Diffuse_Color", Color) = (1, 1, 1, 1)
		_Specular_Color("_Specular_Color", Color) = (1, 1, 1, 1)
		_Lambert_Enhance ("_Lambert_Enhance", Range (-1, 1)) = 0
		_Gloss ("_Gloss", Range (1, 256)) = 1
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 100

		Pass
		{
			Tags { "LightMode"="ForwardBase" }

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"
			#include "Lighting.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float3 normal : NORMAL;
				float4 tangent : TANGENT;
				float2 uv : TEXCOORD0;
				float4 color : COLOR;
			};

			struct v2f
			{
				float4 vertex : SV_POSITION;
				fixed3 wnormal : TEXCOORD4;
				float4 wvertex : TEXCOORD5;
				float2 uv : TEXCOORD0;
				fixed3 cFinal : COLOR0;
				fixed3 cVertex : COLOR1;
				fixed3 cEmissive : COLOR2;
				fixed3 cAmbient : COLOR3;
				fixed3 cDiffuse : COLOR4;
				fixed3 cSpecular : COLOR5;
			};

			fixed4 _Emissive_Color;
			fixed4 _Ambient_Color;
			fixed4 _Diffuse_Color;
			fixed4 _Specular_Color;

			fixed _Lambert_Enhance;
			half _Gloss;
			int _Calculate_Vertex;

			//---------------------------------------------------------------------------------------------------------------------------------
			fixed3 CalculateEmissiveColor()
			{
				return _Emissive_Color;
			}
			fixed3 CalculateAmbientColor()
			{
				return UNITY_LIGHTMODEL_AMBIENT * _Ambient_Color;
			}
			fixed3 CalculateDiffuseColor(float3 normalDir, float3 lightDir, fixed3 lightColor, fixed3 diffuseColor)
			{
				return saturate(dot(normalize(normalDir), normalize(lightDir)) * (1 - _Lambert_Enhance) + _Lambert_Enhance) * lightColor * diffuseColor;
			}
			fixed3 CalculateSpecularColor_Phong(float3 normalDir, float3 lightDir, float3 viewDir, fixed3 lightColor, fixed3 specularColor)
			{
				normalDir = normalize(normalDir);
				lightDir = normalize(lightDir);
				viewDir = normalize(viewDir);
				float3 reflectDir = normalize(dot(normalDir, lightDir) * 2 * normalDir - lightDir);
				//reflectDir = normalize(reflect(-lightDir, normalDir)); 同上.
				return pow(saturate(dot(reflectDir, viewDir)), _Gloss) * lightColor * specularColor;
			}
			fixed3 CalculateSpecularColor_BlinnPhong(float3 normalDir, float3 lightDir, float3 viewDir, fixed3 lightColor, fixed3 specularColor)
			{
				normalDir = normalize(normalDir);
				lightDir = normalize(lightDir);
				viewDir = normalize(viewDir);
				float3 midDir = normalize(lightDir + viewDir);
				return pow(saturate(dot(midDir, normalDir)), _Gloss) * lightColor * specularColor;
			}

			//---------------------------------------------------------------------------------------------------------------------------------
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				o.cVertex = v.color;

				float3 wnormal = mul(unity_ObjectToWorld, v.normal);
				float3 wvertex = mul(unity_ObjectToWorld, v.vertex);

				if (_Calculate_Vertex > 0)
				{
					o.cEmissive = CalculateEmissiveColor();
					o.cAmbient = CalculateAmbientColor();
					o.cDiffuse = CalculateDiffuseColor(wnormal, _WorldSpaceLightPos0, _LightColor0, _Diffuse_Color);
					o.cSpecular = CalculateSpecularColor_BlinnPhong(wnormal, _WorldSpaceLightPos0, _WorldSpaceCameraPos.xyz - wvertex, _LightColor0, _Specular_Color);
					o.cFinal = o.cEmissive + o.cAmbient + o.cDiffuse + o.cSpecular;
				}

				o.wnormal = wnormal;
				o.wvertex = float4(wvertex, 1);

				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				float3 wnormal = normalize(i.wnormal);
				float3 wvertex = i.wvertex;

				if (_Calculate_Vertex < 1)
				{
					i.cEmissive = CalculateEmissiveColor();
					i.cAmbient = CalculateAmbientColor();
					i.cDiffuse = CalculateDiffuseColor(wnormal, _WorldSpaceLightPos0, _LightColor0, _Diffuse_Color);
					i.cSpecular = CalculateSpecularColor_BlinnPhong(wnormal, _WorldSpaceLightPos0, _WorldSpaceCameraPos.xyz - wvertex, _LightColor0, _Specular_Color);
					i.cFinal = i.cEmissive + i.cAmbient + i.cDiffuse + i.cSpecular;
				}
				return fixed4(i.cFinal, 1);
			}
			ENDCG
		}
	}
}
参考:《Unity Shader 入门精要》,感谢作者妹子。

猜你喜欢

转载自blog.csdn.net/lzdidiv/article/details/62886005