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