一、一些基本感念
1.1 Shader和Material的基本概念
Shader(著色器)實際上就是一小段程序夷蚊,它負責將輸入的Mesh(網(wǎng)格)以指定的方式和輸入的貼圖或者顏色等組合作用娱颊,然后輸出傲诵。繪圖單元可以依據(jù)這個輸出來將圖像繪制到屏幕上。輸入的貼圖或者顏色等箱硕,加上對應的Shader拴竹,以及對Shader的特定的參數(shù)設(shè)置,將這些內(nèi)容(Shader及輸入?yún)?shù))打包存儲在一起剧罩,得到的就是一個Material(材質(zhì))栓拜。之后,我們便可以將材質(zhì)賦予合適的renderer(渲染器)來進行渲染(輸出)了斑响。
Shader只是一段規(guī)定好輸入(顏色菱属,貼圖等)和輸出(渲染器能夠讀懂的點和顏色的對應關(guān)系)的程序。而Shader開發(fā)者要做的就是根據(jù)輸入舰罚,進行計算變換纽门,產(chǎn)生輸出而已。
二营罢、Unity中Shader的三種基本類型
計算機圖形學中的渲染管線一般可以分為兩種類型:
1.固定功能渲染管線(fixed-functionrendering pipelines)
2.可編程渲染管線(programmablerendering pipelines)
Unity中Shader分為三種基本類型:
1.固定功能著色器(Fixed Function Shader)
2.表面著色器(Surface Shader)
3.頂點著色器&片段著色器(Vertex Shader & Fragment Shader)
固定功能著色器便是我們所說的固定功能渲染管線(fixed-functionrendering pipelines)的具體表現(xiàn)赏陵,而表面著色器、頂點著色器以及片段著色器便屬于可編程渲染管線饲漾。
2.1 固定功能著色器
Unity為Shader的書寫自帶的一層殼
2.2 表面著色器
Unity自己發(fā)揚光大的一項使Shader的書寫門檻降低和更易用的技術(shù)
2.3 頂點著色器和片段著色器
頂點著色器:產(chǎn)生紋理坐標蝙搔,顏色,點大小考传,霧坐標吃型,然后把它們傳遞給裁剪階段。
片段著色器:進行紋理查找僚楞,決定什么時候執(zhí)行紋理查找勤晚,是否進行紋理查找,及把什么作為紋理坐標
2.4 區(qū)分Shader類型
沒有嵌套CG語言泉褐,也就是代碼段中沒有CGPROGARAM和ENDCG關(guān)鍵字的赐写,就是固定功能著色器。
嵌套了CG語言膜赃,代碼段中有surf函數(shù)的挺邀,就是表面著色器。
嵌套了CG語言,代碼段中有#pragma vertex name和 #pragma fragment frag聲明的端铛,就是頂點著色器&片段著色器泣矛。
三、 Shader賦給Material的方法
1.拖拽
2.在Material的Inspector面板中選擇
四沦补、Shader的基本框架
Unity中Shader整體的框架寫法可以用如下的形式來概括:
Shader "name" { [Properties] SubShaders[Fallback] }
ps:所有用于這個著色器的代碼必須放置在之后的大括號中:{ }(稱為“塊”)乳蓄。該名字應該是短且描述性的文字。它并不需要和shader文件名相同夕膀。而想要把著色器加入到Unity的子菜單里,名字需要用斜線(/)美侦。
首先是一些屬性定義产舞,用來指定這段代碼將有哪些輸入。接下來是一個或者多個的子著色器菠剩,在實際運行中易猫,哪一個子著色器被使用是由運行的平臺所決定的。子著色器是代碼的主體具壮,每一個子著色器中包含一個或者多個的Pass准颓。在計算著色時,平臺先選擇最優(yōu)先可以使用的著色器棺妓,然后依次運行其中的Pass攘已,然后得到輸出的結(jié)果。最后指定一個Fallback怜跑,即備胎样勃,用來處理所有SubShader都不能運行的情況。
ps:在實際進行表面著色器的開發(fā)時性芬,我們就是直接在SubShader這個層次上寫代碼峡眶,系統(tǒng)會將把我們的代碼編譯成若干個合適的Pass。
ps:SubShader在UnityShader的代碼段中必須有且至少有一個植锉,而properties和fallback對于追求簡單的Shader辫樱,是可以不寫出來的。而復雜一點的Shader俊庇,當然各種properties狮暑、fallback什么的肯定都有,甚至有多個SubShader暇赤,而每個SubShader中又有多個Pass心例。
五、Properties屬性相關(guān)
properties一般定義在著色器的起始部分鞋囊,我們可以在Shader書寫的時候定義多種多樣的屬性止后,而使用Shader的時候可以直接在材質(zhì)檢視面板(Material Inspector)里編輯這些屬性,取不同的值或者紋理。
ps:Properties塊內(nèi)的語法都是單行的译株。每個屬性都是由內(nèi)部名稱開始瓜喇,后面括號中是顯示在檢視面板(Inspector)中的名字和該屬性的類型。等號后邊跟的是默認值歉糜。
5.1 Properties屬性相關(guān)代碼列舉
Properties { Property [Property ...] }
定義屬性塊乘寒,其中可包含多個屬性,其定義如下:
name ("display name", Range (min, max)) =number
定義浮點數(shù)屬性匪补,在檢視器中可通過一個標注最大最小值的滑條來修改伞辛。
name ("display name", Color) =(number,number,number,number)
定義顏色屬性
name ("display name", 2D) = "name" {options }
定義2D紋理屬性
name ("display name", Rect) = "name"{ options }
定義長方形(非2次方)紋理屬性
name ("display name", Cube) = "name"{ options }
定義立方貼圖紋理屬性
name ("display name", Float) = number
定義浮點數(shù)屬性
name ("display name", Vector) =(number,number,number,number)
定義一個四元素的容器(相當于Vector4)屬性
5.2 一些細節(jié)
包含在著色器中的每一個屬性通過name索引(在Unity中, 通常使用下劃線來開始一個著色器屬性的名字)。屬性會將display name顯示在材質(zhì)檢視器中夯缺,還可以通過在等符號后為每個屬性提供缺省值蚤氏。
對于Range和Float類型的屬性只能是單精度值。
對于Color和Vector類型的屬性將包含4個由括號圍住的數(shù)描述踊兜。
對于紋理(2D, Rect, Cube) 缺省值既可以是一個空字符串也可以是某個內(nèi)置的缺省紋理:"white", "black", "gray" or"bump"
隨后在著色器中竿滨,屬性值通過[name]來訪問。
5.3 紋理屬性選項
name ("display name", 2D) ="name" { options }
包含在紋理屬性的大括號中的選項Options是可選的捏境∮谟危可能的選項有如下:
TexGen紋理生成類型。即紋理的自動生成紋理坐標時的模式垫言,可以是ObjectLinear, EyeLinear,SphereMap, CubeReflect, CubeNormal的其中之一;這些模式和OpenGL紋理生成模式相對應贰剥。注意如果使用自定義頂點程序,那么紋理生成將被忽略骏掀。
LightmapMode 光照貼圖模式鸠澈。如果我們給出這個選項崭庸,紋理將能被渲染器的光線貼圖屬性所影響酌儒。紋理不能被使用在材質(zhì)中与倡,而是取自渲染器的設(shè)定彪见。這個我們以后會講到腌歉。
六暇唾、光照进统、材質(zhì)與顏色
燈光和材質(zhì)參數(shù)常常被用來控制內(nèi)置的頂點光照乖寒。而Unity中的頂點光照也就是Direct3D/OpenGL標準的按每頂點計算的光照模型—— 光照打開時坡锡,光照受材質(zhì)塊蓬网,顏色材質(zhì)和平行高光命令的影響。
6.1 用于通道Pass中的代碼
這些代碼一般是寫在Pass{ }中的鹉勒,細節(jié)如下:
Color Color
設(shè)定對象的純色帆锋。顏色即可以是括號中的四值(RGBA),也可以是被方框包圍的顏色屬性名禽额。
Material { Material Block }
材質(zhì)塊被用于定義對象的材質(zhì)屬性锯厢。
Lighting On | Off
開啟光照皮官,也就是定義材質(zhì)塊中的設(shè)定是否有效。想要有效的話必須使用Lighting On命令開啟光照实辑,而顏色則通過Color命令直接給出捺氢。
SeparateSpecular On | Off
開啟獨立鏡面反射。這個命令會添加高光光照到著色器通道的末尾剪撬,因此貼圖對高光沒有影響摄乒。只在光照開啟時有效。
ColorMaterial AmbientAndDiffuse | Emission
使用每頂點的顏色替代材質(zhì)中的顏色集残黑。AmbientAndDiffuse 替代材質(zhì)的陰影光和漫反射值;Emission 替代 材質(zhì)中的光發(fā)射值馍佑。
6.2 材質(zhì)塊Material Block相關(guān)代碼
使用的地方是在SubShader中的一個Pass{ }中新開一個Material{ }塊,在這個Material{ }塊中進行這些語句的書寫梨水。這些代碼包含了包含材質(zhì)如何和光線產(chǎn)生作用的一些設(shè)置挤茄。這些屬性默認為值都被設(shè)定為黑色(也就是說不產(chǎn)生作用),一般情況下可以被忽略冰木。
Diffuse Color(R,G,B,A)
漫反射顏色構(gòu)成。這是對象的基本顏色笼恰。
Ambient Color(R,G,B,A)
環(huán)境色顏色構(gòu)成.這是當對象被RenderSettings.中設(shè)定的環(huán)境色所照射時對象所表現(xiàn)的顏色踊沸。
Specular Color(R,G,B,A)
對象反射高光的顏色。(R,G,B,A)四個分量分別代表紅綠藍和Alpha社证,取值為0到1之間逼龟。
Shininess Number
加亮時的光澤度,在0和1之間追葡。0的時候你會發(fā)現(xiàn)更大的高亮也看起來像漫反射光照腺律,1的時候你會獲得一個細微的亮斑。
Emission Color
自發(fā)光顏色宜肉,也就是當不被任何光照所照到時匀钧,對象的顏色。(R,G,B,A)四個分量分別代表紅綠藍和Alpha谬返,取值為0到1之間之斯。
打在對象上的完整光照顏色最終是:
FinalColor=Ambient * RenderSettings ambientsetting + (Light Color * Diffuse + Light Color Specular) + Emission
最終顏色=環(huán)境光反射顏色 渲染設(shè)置環(huán)境設(shè)置 (燈光顏色漫反射顏色+燈光顏色*鏡面反射顏色)+自發(fā)光
ps:方程式的燈光部分(也就是帶括號的部分)對所有打在對象上的光線都是重復使用的。而我們在寫Shader的時候常常會將漫反射和環(huán)境光光保持一致(所有內(nèi)置Unity著色器都是如此)
舉個栗子:
Shader "demo/Shader"
{
//properties
Properties
{
_Color ("主顏色", Color) = (2,2,1,0)
_SpecColor ("高光顏色", Color) = (2,2,2,1)
_Emission ("自發(fā)光顏色", Color) = (0,0,0,0)
_Shininess ("光澤度", Range (0.01, 1)) = 0.7
_MainTex ("基本紋理", 2D) = "white" {}
}
//subshader
SubShader
{
//pass
Pass
{
//material
Material
{
//可調(diào)節(jié)的漫反射光和環(huán)境光反射顏色
Diffuse [_Color]
Ambient [_Color]
//光澤度
Shininess [_Shininess]
//高光顏色
Specular [_SpecColor]
//自發(fā)光顏色
Emission [_Emission]
}
//開啟光照
Lighting On
//開啟獨立鏡面反射
SeparateSpecular On
//設(shè)置紋理并進行紋理混合
SetTexture [_MainTex]
{
Combine texture * primary DOUBLE, texture * primary
}
}
}
}
產(chǎn)物如下