本教程參考了《貓都能學會的Unity3dShaderLab教程.CHM》,
1.請上網搜索並下載此文件。
2.隨后再下載里面提到的素材:
http://vdisk.weibo.com/s/y-NNpUsxhYhZI
第一組實驗(復習課,實現最簡單的漫反射 [該組實驗參考了官網示例中的Normal-Diffuse.shader例子]):
第1.1步:創建一個名為“NormalDiffuse”的shader
第1.2步:看到其中有一些已有的內容,不妨全部刪掉(除了第一行),這樣更加容易鍛煉你的代碼能力和加深理解。
筆者將會一行一行地帶領讀者寫這個示例。
詳細解讀:
▼代碼開始 Shader "Custom/NormalDiffuse" { Properties{ //調制色_Color和主要紋理_MainTex將會相乘,得到調制后的顏色 _Color("The Main Color", Color) = (1,1,1,1) _MainTex("Base Picture", 2D) = "white"{} //兩張圖默認都是白色(前面的數據結構是顏色,后面的是二維圖像) } //之前也說過,這是一個處理子程序(一個Pass) SubShader{ //渲染類型是不透明 Tags{"RenderType" = "Opaque"} //當機器的能力超過200時,會執行這個SubShader LOD 200 CGPROGRAM //pragma surface 處理函數 光照模型 /*其中這里的光照模型是Lambert模型,也就是環境光+散射光+反射高光+放射光*/ #pragma surface surf Lambert //還記得嗎?同名變量,注意對應關系:Color對應fixed4,2D對應sampler2D sampler2D _MainTex; fixed4 _Color; //輸入結構體一定要命名為Input,自己規定其輸入,注意紋理坐標的寫法一定是紋理貼圖變量名前面加uv struct Input { float2 uv_MainTex; }; //surf函數的輸入輸出是定死的,即Input和inout SurfaceOutput,后者是輸出 void surf(Input IN, inout SurfaceOutput o) { //非常簡單,就是用tex2D(貼圖,紋理坐標)取出紋理上的一點,然后和Color相乘調制即可得到結果 fixed4 c = tex2D(_MainTex, IN.uv_MainTex)*_Color; //Albedo是主顏色的意思(本質是一個用來相乘的系數,當外界光線找到此表面上時,反射的光線 = 入射光線 * Albedo) o.Albedo = c.rgb; //獲得其透明度Alpha o.Alpha = c.a; /*追加說明:SurfaceOutput這個固定好的結構中,有以下幾個值: struct SurfaceOutput { half3 Albedo; //像素的顏色 half3 Normal; //像素的法向值 half3 Emission; //像素的發散顏色 half Specular; //像素的鏡面高光 half Gloss; //像素的發光強度 half Alpha; //像素的透明度 }; */ } ENDCG } //Fallback暗藏乾坤,表示將此回滾全部插入到本代碼中!(我憑什么這么說:http://www.ceeger.com/forum/read.php?tid=31958) //也就是說"Legacy Shaders/VertexLit"會完全插入到這里 Fallback "Legacy Shaders/VertexLit" } ▲代碼結束
注意事項:
Unity3d下方可能有報錯提示,可以根據此提示修改代碼。
第1.3步:新建一個Material,命名為MNormalDif,按照下圖配置一下(注意此處用到了上面它提到的資源)。
總結:這個實驗用到的算法和前面第一節入門課提到的一樣,就是很簡單的取出了紋理顏色,然后就結束了。
第二組內容:
第2.1步:
▼代碼開始 Shader "Custom/NormalBumped" { Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Normal("Normal", 2D) = "bump"{} //什么是"bump"{},通過實驗可以知道,它是指藍色“bump” (RGBA: 0.5,0.5,1,0.5),參考:https://docs.unity3d.com/Manual/SL-Properties.html /*簡單說說我是如何知道的:我將下文中的surf函數的代碼改為只有一句o.Albedo = tex2D(_Normal, IN.uv_Normal);並在inspector面板中設置Normal為none(於是采用默認值bump),得到下圖
當然,這個不是本實驗的最終效果,只是為了說明bump是指藍色(0.5,0.5,1,0.5)罷了 */ } SubShader { Tags { "RenderType"="Opaque" } LOD 300 CGPROGRAM #pragma surface surf Lambert fixed4 _Color; sampler2D _MainTex; sampler2D _Normal; struct Input { float2 uv_MainTex; float2 uv_Normal; }; void surf (Input IN, inout SurfaceOutput o) { fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; //o.Albedo = (tex2D(_Normal, IN.uv_Normal)).rgb; o.Albedo = c.rgb; o.Alpha = c.a; //利用UnpackNormal(tex2D(_Normal, IN.uv_Normal))方法獲取解包后的法方向(什么是UnpackNormal,存疑) o.Normal = UnpackNormal(tex2D(_Normal, IN.uv_Normal)); } ENDCG } FallBack "Diffuse" } ▲代碼結束
第2.2步:仿照第一組實驗的做法,新建一個材質,指定主紋理和法向量貼圖。效果為:
第三組實驗:本組實驗介紹Properties類型
參考資料:http://blog.csdn.net/candycat1992/article/details/17152641
第3.1步:新建一個shader,命名為LearnPropertiesType,新建一個Material應用它。
第3.2步:僅僅在默認的LearnPropertiesType代碼中加入幾個變量,我們就看看它們的寫法和在editor中的樣子。
▼代碼開始 Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness("Smoothness", Range(0,1)) = 0.5 _Metallic("Metallic", Range(0,1)) = 0.0 //新加入的部分: _MyRange1("RangedNumber", Range(0,100)) = 20 _MyFloat2("MyFloat", Float) = 1.1 //其它的就不多說了,只說Cube和Rect的默認值是“”{}這樣就可以了,以及Vector如果沒有寫4維度,默認是4維度的,缺省的通道為1 _MyInt3("MyInt", Int) = 2 _MyVec("MyVec", Vector) = (1,1,1,0.5) _MyVec3("MyVec3", Vector) = (1,2,3) _MyCube("MyCube", Cube) = ""{} _MyRec("MyRec", Rect) = ""{} /*官網中關於默認值的介紹: For Range and Float properties it’s just a single number, for example “13.37”. For Color and Vector properties it’s four numbers in parentheses, for example “(1,0.5,0.2,1)”. For 2D Textures, the default value is either an empty string, or one of the built-in default Textures: “white” (RGBA: 1,1,1,1), “black” (RGBA: 0,0,0,0), “gray” (RGBA: 0.5,0.5,0.5,0.5), “bump” (RGBA: 0.5,0.5,1,0.5) or “red” (RGBA: 1,0,0,0). For non–2D Textures (Cube, 3D, 2DArray) the default value is an empty string. When a Material does not have a Cubemap/3D/Array Texture assigned, a gray one (RGBA: 0.5,0.5,0.5,0.5) is used. */ } ▲代碼結束
第3.3步:查看效果:
以下提供一些學習筆記。
關於着色器的性能的介紹:
http://www.ceeger.com/Components/shader-Performance.html
常規着色器的性能比較:
Unlit<頂點光照<漫反射<高光<視差;
漫反射:
光照強度只和物體、光源有關,即隨着物體表面和光的夾角的變小而變小,鏡頭的移動和旋轉不改變光照強度。
下面的兩種模型是高光計算模型。
Phong光照模型:
Specular=Ks*lightColor*(dot(視點方向,反射光方向))的shininess次方
其中的反射光方向R的計算用到了巧算公式。
Blinn-Phong光照模型:
Specular=Ks*lightColor*(dot(法方向N,視點方向 - 光入射方向))的shininess次方
以上知識點參考:http://www.cnblogs.com/bluebean/p/5299358.html
高光着色需要的紋理要帶有alpha通道,用作上述shininess。
Lambertian反射模型:
(參考http://blog.csdn.net/u010922186/article/details/40680913)
最終表面 = 放射光(發光色) + 環境光(環境光色的若干倍) + 漫反射光(光源顏色*max(dot(法向量N, 指向光源向量L), 0)的若干倍) + 鏡面反射(上述高光模型)
正切空間:是指Z軸定義為表面指向外面的坐標系,法線貼圖就是在正切空間中應用的。
法線貼圖着色器應用了法線貼圖和無alpha的基本紋理。法線貼圖着色器僅僅改動了Diffuse着色器中的法方向。因此和攝像機的移動和旋轉無關。
法線貼圖高光着色器:
非常簡單,僅僅是高光着色和法線貼圖着色的融合,即需要一個基本紋理(帶有alpha通道表示高光貼圖)以及法。
視差漫反射着色器:
需要的資源有一個基本的紋理(無alpha),一個法線貼圖,一個高度紋理(在alpha通道帶有視差深度)
高度有什么用?參考:http://blog.chinaunix.net/uid-26651460-id-3198307.html
視差高光貼圖着色器:
需要的資源有一個基本的紋理(有alpha表示高光貼圖),一個法線貼圖,一個高度紋理(在alpha通道帶有視差深度)
貼花着色器:
就是在原有基礎上貼上一層紋理。
——小江村兒的文傑 zouwj5@qq.com