天天看點

Unity Shader基礎的使用 基礎、法線貼圖及光照模型代碼的注釋

版本:unity 5.3.4  語言:C#

這邊主要參考了貓也能學會Shader的文章。

話說之前是不是說暫時不研究Shader?沒事哈,不要在意那麼多細節,要的就是莽,瘋狂加點就行了。

這邊主要是把貓大寫的Shader仔細注釋了一下,以便以後查閱,暫時不系統的學習Shader。

Shader其實相當于一個後期的處理,在已經有的模型上加個特效什麼的,讓它的顯示更加炫酷,Shader也算是學習Unity的一個重中之重。

下面發一下代碼(主要做備忘用,不太了解的玩家可以參考一下貓大的文章):

//一個基礎的Shader
Shader "Custom/Diffuse Texture" {
	Properties {
		/*
		 類型:
		 Color 一種顔色
		 2D 2的階數大小的貼圖
		 Rect 非2階數大小的貼圖
		 Cube 立方體紋理
		 Range(min, max) 介于最小值最大值的浮點數
		 Float 任意一個浮點數
		 Vector 一個四維數
		 */
		_Color ("Color", Color) = (0,0,0,1)	//一種顔色
		_MainTex ("Albedo (RGB)", 2D) = "white" {}	//2階數大小的貼圖
		_Glossiness ("Smoothness", Range(0,1)) = 0.5	//浮點數
		_Metallic ("Metallic", Range(0,1)) = 0.0	//浮點數
	}
	SubShader {
		/*
		 重要的Tags:
		 "RenderType"="Transparent" 透明、半透明像素渲染
		 "ForceNoShadowCasting"="True" 從不産生陰影
		 "Queue"="xxx" 渲染順序隊列,主要參數:
				"Backgroung" 最早調用,用來渲染天空盒或者背景 1000
				"Geometry" 渲染非透明物體,預設值 2000
				"AlphaText" 用來渲染經過Alpha Test的像素(這個不太了解) 2450
				"Transparent" 從後往前的順序渲染透明物體 3000
				"Overlay" 渲染疊加效果,渲染的最後階段,鏡頭光暈之類 4000
		*/
		Tags { "RenderType"="Opaque" }	//渲染非透明物時執行
		LOD 200	//Level of Detail,該值不能小于unity中設定的值,我的工程中該值為0,而且最高隻能設定為7(不是很明白)
		
		CGPROGRAM	//腳本開始,這邊用的是Cg/HLSL語言,主要用于Dx的程式,如果是運作在OpenGL上的程式,unity會轉化為GLSL語言,或者可以選擇直接寫GLSL語言的Shader,但顯然使用Cg\HLSL有更好的移植性
		
		// surface表明是一個表面着色器,surf 代碼名稱,Standard 光照模型
		#pragma surface surf Standard fullforwardshadows

		// Shader模型的版本為3.0
		#pragma target 3.0

		sampler2D _MainTex;	//需要處理的貼圖放在這裡,注意這裡的_MainTex是前面聲明過的屬性

		struct Input {
			float2 uv_MainTex;	//算是一個長度為2的float數組,uv字首表示貼圖上點的二維坐标
		};

		half _Glossiness;
		half _Metallic;
		fixed4 _Color;

		/*
		 SurfaceOutputStandard的結構(教程中的是SurfaceOutput,這邊應該是U5的新特性吧)
		 struct SurfaceOutputStandard
		 {
			fixed3 Albedo;	//漫反射顔色
			fixed3 Normal;	//切線空間法線
			half3 Emission;	//自發光
			half Metallic;	//金屬度,0為非金屬,1為金屬
			half Smoothness;	//光澤度,0為非常粗糙,1為非常光滑
			half Occlusion;	//遮擋(預設1)
			fixed Alpha;	//透明度
		 }
		 SurfaceOutput中是Specular鏡面高光、Gloss發光強度代替了Metallic、Smoothness、Occlusion
		
		*/

		// 主處理函數,輸入輸出必須按規定寫
		void surf (Input IN, inout SurfaceOutputStandard o) {
			// 對一個點進行采樣
			fixed4 c = tex2D(_MainTex, IN.uv_MainTex); //* _Color;
			o.Albedo = c.rgb;
			o.Metallic = _Metallic;
			o.Smoothness = _Glossiness;
			o.Alpha = c.a;
		}
		ENDCG	//腳本結束
	}
	FallBack "Diffuse"
}
           
//一個帶法線貼圖、光照模型的Shader
Shader "Custom/Normal Mapping" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}	//原本的貼圖
		_Bump("Bump", 2D) = "bump"{}	//法線貼圖
		_Snow("Snow Level", Range(0, 1)) = 0	//雪等級
		_SnowColor("Snow Color", Color) = (1.0, 1.0, 1.0, 1.0)	//雪顔色
		_SnowDirection("Snow Direction", Vector) = (0, 1, 0)	//雪的方向
		_SnowDepth("Snow Depth", Range(0, 0.3)) = 0.1	//雪的深度
	}
	SubShader {

		Tags { "RenderType"="Opaque" }
		LOD 200
		
		CGPROGRAM
		
		#pragma surface surf CustomDiffuse vertex:vert	//vertex:vert表明我們會改變頂點,并且會使用vert函數來做處理

		// 定義自己的光照模型
		//#pragma surface surf CustomDiffuse
		/*
		 參數:SurfaceOutput 經過表面計算後的輸入;lightDir 光線方向;atten 光衰減系數
		*/
		half4 LightingCustomDiffuse(SurfaceOutput s, half3 lightDir, half atten) {
			half difLight = max(0, dot(s.Normal, lightDir));	//點積調整目前點的亮度
			difLight = difLight * 0.5 + 0.5;	//低光下增亮效果(半條命),範圍從0-1到0.5-1
			half4 col;
			col.rgb = s.Albedo * _LightColor0.rgb * (difLight * atten * 2);	//根據物體的顔色、光顔色、光亮度、衰減度計算目前點的顔色,2是曆史問題,U5中已經移除,但我們這邊還保留着
			col.a = s.Alpha;
			return col;
		}

		sampler2D _MainTex;
		sampler2D _Bump;
		float _Snow;
		float4 _SnowColor;
		float4 _SnowDirection;
		float _SnowDepth;

		struct Input {
			float2 uv_MainTex;
			float2 uv_Bump;
			float3 worldNormal; INTERNAL_DATA	//目前點在世界中的法線值
		};

		void vert(inout appdata_full v)
		{
			float4 sn = mul(transpose(_Object2World), _SnowDirection);	//把積雪方向的矩陣轉換到世界矩陣
			if (dot(v.normal, sn.xyz) >= lerp(1, -1, (_Snow * 2) / 3))
			{
				v.vertex.xyz += (sn.xyz + v.normal) * _SnowDepth * _Snow;
			}
		}

		void surf (Input IN, inout SurfaceOutput o) {	//使用自己的光照模型時,參數為SurfaceOutput,而不是SurfaceOutputStandard
			half4 c = tex2D(_MainTex, IN.uv_MainTex);
			o.Normal = UnpackNormal(tex2D(_Bump, IN.uv_Bump));

			// 世界中的法線方與垂直方向做點積,計算出1到-1的值,如果大于雪的門檻值,則顯示白色
			if (dot(WorldNormalVector(IN, o.Normal), _SnowDirection.xyz) > lerp(1, -1, _Snow))
			{
				o.Albedo = _SnowColor.rgb;
			}
			else
			{
				o.Albedo = c.rgb;
			}

			o.Alpha = c.a;
		}
		ENDCG
	}
	FallBack "Diffuse"
}
           

基本上來說,跟貓大那時候的版本差不多,不過注意的是Unity5.0時代基礎建立的Shader使用的是Standard的一個光照模型,是以這邊要注意一下,我在代碼中也有标明。

繼續閱讀