unityShader
這篇文章是我在學(xué)習(xí)蠻牛的一套關(guān)于Shader教程(http://www.unitytrain.cn/course/96)后的簡(jiǎn)單總結(jié),個(gè)人感覺(jué)這套教程并不是以高級(jí)Shader編程為目的的,更像是授人以漁的宗旨。下面我會(huì)分為三個(gè)部分:Shader簡(jiǎn)述、圖形學(xué)基礎(chǔ),Cg簡(jiǎn)介為大家介紹Shader的相關(guān)內(nèi)容,也算是做一個(gè)總結(jié)。
一:Shader簡(jiǎn)述
??? a.先說(shuō)一下GPU與CPU的區(qū)別,簡(jiǎn)單說(shuō):GPU主要負(fù)責(zé)跟顯示相關(guān)的數(shù)據(jù)處理,而CPU主要負(fù)責(zé)操作系統(tǒng)和應(yīng)用程序。為什么不把顯示相關(guān)的數(shù)據(jù)直接交給CPU處理呢?下面附上解釋:
???? b.Shader分類。Shader中文翻譯為“著色器”,含義是:可編程圖形管線。主要分為:Vertex Shader和fragment Shader,即定點(diǎn)Shader和片段Shader。上面有一個(gè)概念是“圖形管線”,簡(jiǎn)單解釋就是:計(jì)算機(jī)處理圖形顯示的處理流水線。
????? c.Shader 的主流編程語(yǔ)言。主流的Shader編程語(yǔ)言主要有HLSL、GLSL、CG。下面簡(jiǎn)單說(shuō)一下區(qū)別:HLSL(High Level Shader Language)是微軟基于DX的作品,只能運(yùn)行在Windows平臺(tái)上。GLSL(OpenGL Shading Language),OpenGL著色語(yǔ)言,是用來(lái)在OpenGL中著色編程的語(yǔ)言(OpenGL是個(gè)定義了一個(gè)跨編程語(yǔ)言、跨平臺(tái)的編程接口規(guī)格的專業(yè)的圖形程序接口),是跨平臺(tái)的著色器語(yǔ)言。到這里,我們已經(jīng)可以發(fā)現(xiàn)有一個(gè)比較麻煩的問(wèn)題出現(xiàn)了,就是我們底層圖形驅(qū)動(dòng)限制了上層的編程語(yǔ)言,一旦想要改動(dòng)圖形驅(qū)動(dòng)庫(kù),那就不得不重寫整個(gè)Shader Files,此時(shí)CG就應(yīng)運(yùn)而生了,CG在HLSL和GLSL上做了進(jìn)一步封裝,屏蔽了上層的著色器語(yǔ)言對(duì)底層圖形庫(kù)的依賴。
????? d.Unity Shader。ShaderLab其實(shí)是Unity對(duì)Shader語(yǔ)法結(jié)構(gòu)的一種包裝,其中支持三種Shader:surface Shader、Vertex and Fragment Shader 和 Fixed function shader 。Fixed function shader 是一種比較“保守”的Shader(兼容性最好),vertex and fragment Shader可以只用HLSL或GLSL或CG語(yǔ)言區(qū)編寫,surface shader是對(duì)Vertex and fragment的一種語(yǔ)法包裝,最終也會(huì)被翻譯中Vertex and fragment Shader。(以上更具體信息的可以參考官方文檔http://docs.unity3d.com/Manual/index.html)
二:圖形學(xué)基礎(chǔ)
???? 個(gè)人感覺(jué)這一小節(jié)的內(nèi)容對(duì)于未接觸過(guò)圖形學(xué)的人來(lái)說(shuō)是挺有價(jià)值的,掃清了以前對(duì)于在Untiy中的坐標(biāo)轉(zhuǎn)換和渲染過(guò)程等的盲點(diǎn)。下面分兩個(gè)小節(jié)去描述該部分的內(nèi)容。
??? a.3D數(shù)學(xué)基礎(chǔ)。其實(shí)3D數(shù)學(xué)無(wú)非就是矩陣的相關(guān)操作,對(duì)于學(xué)過(guò)線代的同學(xué)肯定都不是問(wèn)題,這里我就簡(jiǎn)單介紹一下。
??? 1.坐標(biāo)系與向量。3D分為左手和右手坐標(biāo)系,可以參考(http://www.cnblogs.com/mythou/p/3327046.html),示意圖如下:
??? 2.向量相關(guān)的東西就不啰嗦了,比較重要的就是向量點(diǎn)乘和叉乘,這里附上參考文章(http://blog.csdn.net/augusdi/article/details/20037851)。
??? 3.矩陣相關(guān)。在3D數(shù)學(xué)中,矩陣往往代表著一種變換,這也是坐標(biāo)系轉(zhuǎn)換所依賴的數(shù)學(xué)原理。大家在Unity中肯定都聽(tīng)過(guò)“MVP矩陣”,MVP矩陣其實(shí)就是一種通過(guò)矩陣操作實(shí)現(xiàn)坐標(biāo)系的轉(zhuǎn)換一種方式。Unity中,有3中四種坐標(biāo)系:模型坐標(biāo)系、世界坐標(biāo)系、攝像機(jī)坐標(biāo)系、屏幕坐標(biāo)系。這其實(shí)是3D圖像顯示的一個(gè)流程:從模型本身坐標(biāo)利用_ObjectToWorld(即M矩陣)轉(zhuǎn)換到世界坐標(biāo)系,再利用_WorldToCamera(即V矩陣)從世界坐標(biāo)系轉(zhuǎn)換到攝像機(jī)坐標(biāo)系,最后利用_Projection(P矩陣)實(shí)現(xiàn)從攝像機(jī)到屏幕坐標(biāo)系的轉(zhuǎn)換,并最終把3D圖像顯示在屏幕上,下面附上一篇百度文庫(kù)的資料(http://wenku.baidu.com/link?url=A3AGV805UK5rcsEjkaL1h6QjnxsktvCscyNJqaHvfe2cIhwXMam6ZzH4Gxbu_XB7Jd7ripxjd0eR51Q6cPt9xPxTiX3MeHtFaWkwexBlZti)。
矩陣幾種重要的操作有:矩陣的行列式、矩陣的轉(zhuǎn)置、矩陣四則運(yùn)算、矩陣逆……這些知識(shí)這里就不啰嗦了,下面簡(jiǎn)單介紹一下幾種常見(jiàn)矩陣變換。
繞坐標(biāo)軸旋轉(zhuǎn)矩陣:
縮放矩陣:
投影矩陣
平移矩陣
以上是幾種比較常用的矩陣,更多的信息就得靠度娘和Google了。
???? b.下面介紹幾個(gè)簡(jiǎn)單的圖形學(xué)的應(yīng)用:光照剔除,漫反射和高光的實(shí)現(xiàn)方式。
???? 1.光照剔除。到這里必須了解“法線的概念”(始終垂直于某平面的虛線),我們的視角即從物體到攝像機(jī)的向量,如果法線N與視線E形成的角度小于90度,那么觀察者應(yīng)是大約是在正面,反之大于90度應(yīng)在該面的反面,此時(shí)應(yīng)是無(wú)法觀察到物體的(法線的求得使用向量差乘,角度計(jì)算可以使用向量的點(diǎn)乘),這時(shí)候就需要將其剔除了,下面兩幅圖簡(jiǎn)單說(shuō)明一下:
???? 2.漫反射(Diffuse 是投射在幾盒體表面上的光向各個(gè)方向反射的現(xiàn)象),可以簡(jiǎn)單理解成光照對(duì)物體表面顏色的影響(在Unity中默認(rèn)的Shader其實(shí)就是漫反射加環(huán)境光的綜合作用)。那么該怎樣計(jì)算光照對(duì)物體顏色的影響程度呢?此時(shí)還是需要用到法線,我們使用法線和光向量(必須先標(biāo)準(zhǔn)化)的點(diǎn)乘作為影響該區(qū)域顏色的因子,這樣再乘以該光源的顏色信息就可以得到對(duì)應(yīng)受光照影響后的顏色了,下面用簡(jiǎn)圖說(shuō)明一下:
??? 3.高光(Specular 光源照射到物體然后反射到人的眼睛里時(shí),物體上最亮的那個(gè)點(diǎn)就是高光),從定義就可以得出高光其實(shí)和反射光與視角相互作用形成的,同樣的我們?cè)谟?jì)算高光也是利用同樣的原理:由入射光求反射光、再計(jì)算反射光和視向量的點(diǎn)乘得出影響因子,最后算出高光強(qiáng)度,簡(jiǎn)圖說(shuō)明一下:
以上是三種比較常見(jiàn)的光照相關(guān)的知識(shí),更多資料只能依靠度娘了……
???? 三、最后一部分的內(nèi)容就簡(jiǎn)單介紹一下Unity Shader 的語(yǔ)法基礎(chǔ)和一個(gè)Demo,更具體的還是要參考Unity官方文檔。
???? a.ShaderLab 語(yǔ)法基礎(chǔ)。Unity 其實(shí)是支持上述三種Shader的,此處介紹的是Vertex and fragment Shader ,用的是CG語(yǔ)法。下面先貼一段Untiy 默認(rèn)的
?
//Shader 文件在選擇面板以樹(shù)狀結(jié)構(gòu)組織的 Shader "Hidden/NewImageEffectShader" {//這個(gè)申明程序中所需要的變量信息 Properties{//_MainTex 變量名 ; “Texture” 在Inspector面板上顯示的名稱 ; 2D 指變量類型 // "white" 變量默認(rèn)值 _MainTex ("Texture", 2D) = "white" {}}// Shader 語(yǔ)法塊,一個(gè)Shader程序至少有一個(gè)SubShader,系統(tǒng)在渲染時(shí)會(huì)依次調(diào)用,// 直到找到匹配的SubShader,否則使用最后默認(rèn)指定的Shader SubShader{// Cull Off:關(guān)閉陰影剔除 、 ZWrite : 要將像素的深度寫入深度緩存中 // Test Always:將當(dāng)前深度值寫到顏色緩沖中 Cull Off ZWrite Off ZTest Always//渲染通道,固定寫法 Pass{//Shader 代碼段開(kāi)始 CGPROGRAM//指定頂點(diǎn)Shader入口#pragma vertex vert//指定片段程序入口#pragma fragment frag //引用Unity內(nèi)置的一些定義#include "UnityCG.cginc"//自定義結(jié)構(gòu)體struct appdata{ //float4 4維向量、POSITION 語(yǔ)義,相當(dāng)于告訴渲染引擎,這個(gè)變量是代表什么含義 float4 vertex : POSITION;//TEXCOORD0 紋理語(yǔ)義 float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};//Vertex Shader 對(duì)應(yīng)的入口v2f vert (appdata v) //appdata v 作為參數(shù),渲染引擎會(huì)把對(duì)應(yīng)語(yǔ)義的信息傳遞進(jìn)來(lái),此處會(huì)傳遞頂點(diǎn)的位置信息和紋理信息 {v2f o;//傳遞進(jìn)來(lái)的頂點(diǎn)坐標(biāo)是模型坐標(biāo)系中的坐標(biāo)值,需要經(jīng)過(guò)矩陣轉(zhuǎn)換車成屏幕坐標(biāo)o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);o.uv = v.uv;//將計(jì)算后的結(jié)果輸出給渲染引擎,底層會(huì)根據(jù)具體的語(yǔ)義去做對(duì)應(yīng)的處理return o;}//在Properties 中定義的變量需要在此申明一下才能在程序中使用 sampler2D _MainTex;//fragment Shader 對(duì)應(yīng)的入口 fixed4 frag (v2f i) : SV_Target{fixed4 col = tex2D(_MainTex, i.uv);// just invert the colorscol = 1 - col;return col;}ENDCG}} //當(dāng)上述的SubShader無(wú)法匹配硬件環(huán)境時(shí),會(huì)調(diào)這個(gè)指定的默認(rèn)ShaderFallback "Mobile/VertexLit" }以上就是對(duì)Unity中的Vertex and fragment 中使用CG 語(yǔ)法的簡(jiǎn)單敘述,下面貼上一個(gè)Demo
二:Shader Demo,這里貼上一個(gè)簡(jiǎn)單的Demo,Demo的整個(gè)是一個(gè)Plane,沒(méi)有使用任何的貼圖,僅僅是使用Shader 改變其頂點(diǎn)和顏色信息實(shí)現(xiàn)的。下面是Demo的截圖
下面貼上該Shader 的源碼
Shader "Cus/Demo_3" {Properties{_MainTex ("Texture", 2D) = "white" {}}SubShader{// No culling or depth Cull Off ZWrite Off ZTest AlwaysPass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"//自定義結(jié)構(gòu)體,包含位置和顏色語(yǔ)義struct v2f{float4 pos : POSITION;float4 col : COLOR;};//Vertex shader入口,顏色信息也在此一并處理了 v2f vert (appdata_base v){v2f o;//計(jì)算旋轉(zhuǎn)角度,利用_SinTime.w為旋轉(zhuǎn)角度加上周期變換性質(zhì)(_SinTime 是Unity提供的內(nèi)置變量)float angle = length(v.vertex)* _SinTime.w;//繞Y軸旋轉(zhuǎn)矩陣float4x4 RM={float4(cos(angle) , 0 , sin(angle) , 0),float4(0 , 1 ,0 , 0),float4(-1 * sin(angle) , 0 , cos(angle),0),float4(0 , 0 ,0 ,1)};//利用RM矩陣影響頂點(diǎn)位置信息float4 pos = mul(RM , v.vertex);//把頂點(diǎn)信息轉(zhuǎn)換到世界坐標(biāo)系中o.pos = mul(UNITY_MATRIX_MVP, pos);//由頂點(diǎn)到中心點(diǎn)的距離決定顏色信息angle = abs(sin(length(v.vertex)));o.col = float4(angle , 1 , 0 ,1);return o;}//片段程序中直接返回頂點(diǎn)Shader中計(jì)算得到的顏色信息 float4 frag (v2f v) : color{return v.col;}ENDCG}} }ok,到這里這篇分享就結(jié)束了,下面附上一個(gè)用C#寫的模擬3D圖像渲染過(guò)程的Demo和上述Shader 的Demo(鏈接:http://pan.baidu.com/s/1c0Yk3KG 密碼:1j1k)
總結(jié)
以上是生活随笔為你收集整理的unityShader的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 交际中你所不知道的说话的12个技巧!
- 下一篇: 社交中的黄金法则,你要细细体会品味