Unity Shader是着色器,將紋理、網格信息輸入,得到材質的一段程序,具體是個什麼東西,還需要親自實踐才知道。一個Unity大神推薦我:如果要學計算機圖形編程(遊戲編程的基礎),可以先學習UnityShader,往後再學習OpenGL和DX。不說廢話,依我的風格,都是直接看實例,筆者的教程偏向於傻瓜式的,應該適合入門。
前提:安裝了Unity和VS,並且有3天的Unity使用經驗。
第一步:打開新工程。在內容瀏覽器中創建一個Shader。
命名爲:
第二步:雙擊打開查看:
Shader "Custom/Shad0" { 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 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM // Physically based Standard lighting model, and enable shadows on all light types #pragma surface surf Standard fullforwardshadows // Use shader model 3.0 target, to get nicer looking lighting #pragma target 3.0 sampler2D _MainTex; struct Input { float2 uv_MainTex; }; half _Glossiness; half _Metallic; fixed4 _Color; void surf (Input IN, inout SurfaceOutputStandard o) { // Albedo comes from a texture tinted by color fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; // Metallic and smoothness come from slider variables o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }
當然,你一開始看不懂,請逐行逐行看我的解釋,下文中的代碼和上文中的一樣,只是加入了詳細的註釋:
/*首行聲明瞭一個Shader,命名爲Shad0,存放在路徑Custom下(這個路徑在哪裏不是重點,它歸類在自定義中),看上去是不是挺像結構體的聲明*/ Shader "Custom/Shad0" { /* 在將第一塊內容之前,請先去了解一下UV紋理。簡單來說:A是一張圖片(稱A爲紋理),B是一張座標信息(稱B爲UV),用B來取A就是紋理貼圖的精髓了,舉個簡單的例子: A的色彩如下: 紅 黃 藍 綠 B的座標信息如下: (0,0) (1,1) (1,1) (0,1) 那麼取出來得到的紋理貼圖就是: 紅 綠 綠 黃 這樣子,是不是很無聊?當這上面的點數達到很大的量級時,就很有意義了。 沒完,你還需要了解鏡面高光和金屬度的概念,自行百度(或者先跳過這個知識點繼續往下看)。 */ /*第一塊:屬性聲明*/ Properties { _Color ("Color", Color) = (1,1,1,1) /*用_XX的聲明方法來聲明的變量就是稱爲屬性了,這一句的語法是: _XXX (展示名, 數據類型) = 默認值 展示名是在Unity中可見的名稱,Color其實是一種數據類型(就像int那樣,只是後者很簡單,是基本數據類型)。 數據類型有哪些(參考上述博文): Color - 一種顏色,由RGBA(紅綠藍和透明度)四個量來定義; 2D - 一張2的階數大小(256,512之類)的貼圖。這張貼圖將在採樣後被轉爲對應基於模型UV的每個像素的顏色,最終被顯示出來; Rect - 一個非2階數大小的貼圖; Cube - 即Cube map texture(立方體紋理),簡單說就是6張有聯繫的2D貼圖的組合,主要用來做反射效果(比如天空盒和動態反射),也會被轉換爲對應點的採樣; Range(min, max) - 一個介於最小值和最大值之間的浮點數,一般用來當作調整Shader某些特性的參數(比如透明度渲染的截止值可以是從0至1的值等); Float - 任意一個浮點數; Vector - 一個四維數; 請看默認值(1,1,1,1),形如(g,b,a,A),其中的透明度A爲0時,表示透明,爲1時,表示完全不透明,所以應該稱之爲不透明度。 */ _MainTex ("Albedo (RGB)", 2D) = "white" {} /*這裏表示一張圖片,這張圖片在這裏僅僅用空白來表示*/ _Glossiness ("Smoothness", Range(0,1)) = 0.5 /*高光設置爲.5*/ _Metallic ("Metallic", Range(0,1)) = 0.0 /*金屬度*/ } /*第二塊內容:什麼是SubShader,如果你用過虛幻4,就能夠很容易理解,其實SubShader對應了UE4中的材質表達式。 UE4中的材質表達式或者Unity中的shader本質是什麼?簡單來說就是將圖片通過處理得到另一張圖片(比如用圖片+UV信息 -> 紋理貼圖的過程)。 SubShader其實就是定義了圖片處理過程。 */ SubShader { /*Tags規定了混合模型。什麼是混合模型?請看下面的附圖1,當然,混合模型是UE4中的概念。
附圖1:
這裏貼一段相比Unity更爲正確的解釋: Background - 最早被調用的渲染,用來渲染天空盒或者背景 Geometry - 這是默認值,用來渲染非透明物體(普通情況下,場景中的絕大多數物體應該是非透明的) AlphaTest - 用來渲染經過Alpha Test的像素,單獨爲AlphaTest設定一個Queue是出於對效率的考慮 Transparent - 以從後往前的順序渲染透明物體 Overlay - 用來渲染疊加的效果,是渲染的最後階段(比如鏡頭光暈等特效) */ Tags { "RenderType"="Opaque" } /*LOD表示細節呈現級別(也即是畫質,即粗糙/細膩程度) 當機器很差的時候,差到其評估值小於200時,本材質無效(也就是本shader罷工)。當機器的性能不錯,大於200時,本shader繼續工作。就是這麼有個性。 彆氣餒,下面的內容是最重要的。 */ LOD 200 /*這是一個標記:CGPROGRAM,表示這是一段computer graph編程*/ CGPROGRAM // Physically based Standard lighting model, and enable shadows on all light types #pragma surface surf Standard fullforwardshadows /*請看這個奇怪的函數聲明: #pragma surface表面着色器 surffunction着色器的代碼(在本例子中就是下面的surf) lightModel(光照模型,這個概念先跳過) [可選參數] */ // Use shader model 3.0 target, to get nicer looking lighting #pragma target 3.0 /* 用筆者的話來說:sampler2D就是一張圖片……(還記得嗎,就是上文說的A圖片) 貼一段介紹: 接下來一句sampler2D _MainTex;,sampler2D是個啥? 其實在CG中,sampler2D就是和texture所綁定的一個數據容器接口。 等等..這個說法還是太複雜了,簡單理解的話,所謂加載以後的texture(貼圖)說白了不過是一塊內存存儲的, 使用了RGB(也許還有A)通道,且每個通道8bits的數據。而具體地想知道像素與座標的對應關係,以及獲取這些數據, 我們總不能一次一次去自己計算內存地址或者偏移,因此可以通過sampler2D來對貼圖進行操作。 更簡單地理解,sampler2D就是GLSL中的2D貼圖的類型,相應的, 還有sampler1D,sampler3D,samplerCube等等格式。 解釋通了sampler2D是什麼之後, 還需要解釋下爲什麼在這裏需要一句對_MainTex的聲明, 之前我們不是已經在Properties裏聲明過它是貼圖了麼。 答案是我們用來實例的這個shader其實是由兩個相對獨立的塊組成的, 外層的屬性聲明,回滾等等是Unity可以直接使用和編譯的ShaderLab; 而現在我們是在CGPROGRAM...ENDCG這樣一個代碼塊中,這是一段CG程序。 對於這段CG程序,要想訪問在Properties中所定義的變量的話,必須使用和之前變量相同的名字進行聲明!【注意這裏!!!】 於是其實sampler2D _MainTex;做的事情就是再次聲明並鏈接了_MainTex, 使得接下來的CG程序能夠使用這個變量。*/ sampler2D _MainTex; /*這是一個非常簡單的結構體,稱爲Input,其中有一個float2數據類型,這是一個二維float矢量,也就是(a,b)這樣的。*/ struct Input { float2 uv_MainTex; }; /*在堅持一下,這裏還有幾個變量:half類型的兩個,fixed4類型的一個, half類型表示半精度浮點數,計算性能好但是精度低,和float和double是同類型的浮點數; fixed4不詳,但是大意是四維的矢量*/ half _Glossiness;//必須使用和之前變量相同的名字進行聲明!【注意這裏!!!】 half _Metallic;//必須使用和之前變量相同的名字進行聲明!【注意這裏!!!】 fixed4 _Color;//必須使用和之前變量相同的名字進行聲明!【注意這裏!!!】 /*核心的處理函數:surf,輸入一張二維浮點信息,也即是上面的uv_MainTex, 輸出一個o表示材質(inout像c++裏面的按照引入傳入,雖說沒有返回,但是也有信息傳出的效果)*/ void surf (Input IN, inout SurfaceOutputStandard o) { // Albedo comes from a texture tinted by color fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; /*看這裏:tex2D就是前面說的"利用UV去取圖片獲得紋理貼圖"的做法,然後再乘以_Color, 這裏用到了乘法的顏色算法,自己體會(這個_Color默認值爲1,1,1,1,所以默認下不影響) 筆者到這裏可以知道:fixed4表示一種四維矢量(用來表示顏色就挺合適的。此外,它是定點型小數而非浮點型小數) */ o.Albedo = c.rgb; /* inout SurfaceOutputStandard o 這個結構有哪些包含的變量呢: struct SurfaceOutput { half3 Albedo; //像素的顏色 half3 Normal; //像素的法向值 half3 Emission; //像素的發散顏色 half Specular; //像素的鏡面高光 half Gloss; //像素的發光強度 half Alpha; //像素的透明度 }; */ // Metallic and smoothness come from slider variables o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = c.a; } ENDCG /*結束CG編碼*/ } FallBack "Diffuse" //這裏還不太明白,先放着。 }
第三步:看完之後再重新看看沒有註釋的代碼,整理十分鐘,然後繼續。
第四步:那篇參考的教程到這裏就完了,我補上結尾:
導入一張圖片:
第五步:創建材質Material,
在細節裏面選擇shader:
是不是很懵逼,爲什麼要這麼做?還記得嗎,shader的本質是將圖片轉化爲Material的算法。
第六步:選擇一張圖片:
然後在右下方看到效果:(點箭頭處切換預覽樣式)
第七步:隨便新建一些物體,然後放入這個材質:
等等:好像沒有反應?因爲沒有光線,加入直射光即可看到效果:
——原創 小江村兒的文傑 [email protected] 2017年7月21日22:29:44
更多:http://www.cnblogs.com/JackSamuel/default.html?page=2