Unity Shader開發(fā)

一.什么是Shader

Shader(著色器),是在GPU運行的程序,通過數學計算將各種屬性(顏色,光照,陰影,紋理等)渲染成物體表面可見的狀態(tài)。在shader里我們可以自定義顯卡渲染畫面的算法,使畫面達到我們想要的效果(放兩張圖)。


二.Shader語言

Shader是GPU運行的程序,目前實現Shader?的語言主要有三種:

基于OpenGL的OpenGL Shader Language,簡稱GLSL。

基于DirectX的High?Level Shader Language,簡稱HLSL。

還有NVIDIA公司的高級圖形編程語言C?for?Graphic,簡稱CG。

三.Shader分類

頂點 shader:3D圖形由一個個三角面組成,頂點shader就是處理這些三角面上的頂點,做頂點變換,傳遞數據到fragment shader。

片元 shader:渲染實現的核心,以片元為單位,計算光照,陰影,著色等一序列渲染算法。

在DX中頂點shader叫做Vertex Shader,片元shader叫做Pixel Shader;在Opengl中頂點shader也叫Vertex Shader,但片元shader叫做Fragment Shader。

四.Unity Shader

圖形API有Opengl,Vulkan,Metal,DX等,顯卡有Intel,NVIDIA,ATI,Amd等 ,Shader編程語言有GLSL,HLSL,Cg等。

Unity為了跨平臺,封裝了一下圖形,顯卡,Shader的差異性,開發(fā)了一種便于書寫的Shader,又稱為ShaderLab。

Unity Shader有三種不同寫法:

Surface Shader表面著色器;Vertext/Fragment Shader ?頂點/片段著色器;

Fixed Function Shader固定管線著色器(已廢棄)。

Surface Shader是Unity對Vertex/Fragment Shader的又一層封裝,簡化開發(fā)邏輯,用少量的代碼來完成不同的光照計算以及跨平臺邏輯。但Surface Shader的局限性也很明顯,Vertex/Fragment Shader能實現的功能,Surface Shader不一定能實現,Vertex/Fragment Shader針對細節(jié)上更細膩的處理,比較底層,也符合標準shader的寫法。并且Unity2018推出的Shader Graph,生成的代碼也是Vertex/Fragment Shader形式,所以我覺得Vertex/Fragment Shader是Unity Shader最主流的寫法,本節(jié)重點介紹Vertex/Fragment Shader的開發(fā)過程。

五.Unity Shader結構

Unity?Vertex/Fragment Shader的標準結構如下圖所示

結構可拆分為以下幾個部分:Shader ?“name”;Properties;SubShader;FallBack

Shader "name"

Shader是一個關鍵字,后面"name"的內容表示具體路徑和名稱

Properties 屬性

材質球Inspector面板上需要顯示的參數,紋理等都是在Properties中進行定義設置。如果不需要顯示參數可以將Properties{}全部去掉,Properties是個可選項,盡管Properties{}刪除了但是不影響C#對shader的參數傳遞。

SubShaders?

Unity Shader是由一個或者多個SubShader組成的,當渲染模型時,會在Unity Shader中尋找在當前顯卡上運行效果最好的SubShader來使用,例如做了一個效果很好的Shader,但是只能在高配顯卡上才能有較好的渲染表現,中低端機上渲染比較吃力,這時我們可以在Shader內做三個SubShader,分別對應于高,中,低不同的顯卡配置。

SubShaders架構細分包括Tags,渲染設置項,一個或多個Pass。

Tags用來控制引擎如何以及何時被渲染,Unity預定義Tag有以下幾種:

RenderType Tag;Quene Tag;DisableBatching Tag;ForceNoShadowCasting Tag;IgnoreProjector Tag;?CanUseSpriteAtlas Tag;PreviewType Tag

RenderType Tag

RenderType標簽將shader分類為若干個預定以組,Unity可以在運行時替換符合特定RenerType的所有shader。這個功能主要通過Camera.RenderWithShader或Camera.SetReplacementShader函數實現,這兩個函數都以1個shader和1個replacementTag作為參數,shader是給定的替換著色器,replacementTag是被替換著色器的標簽值。

Quene Tag

Quene 標簽用來確定對象的繪制順序。在shader中決定其渲染對象屬于哪個渲染隊列,提高渲染效率,保證渲染正確性。

在Unity中有5個預定以的渲染隊列,分別如下表示:

Unity在內部使用一些整數索引來表示每個渲染隊列,索引號越小越早被渲染,遵循3D渲染的基本規(guī)則:

1.先渲染不透明物體,把不透明物體按與攝像機距離的遠近進行排序,從前往后渲染,并開啟深度測試和深度寫入。

2.半透明物體按與攝像機距離的遠近進行排序,然后從后往前渲染,并開啟深度測試,關閉深度寫入。

DisableBatching Tag

禁用批處理,有三個標簽設置值: True,False(默認值),LODFading(當LOD衰減活動時禁用批處理)

ForceNoShadowCasting Tag

強制沒有陰影投射,有兩個標簽設置值:True,False(默認值)?

IgnoreProjector Tag

忽略投影機,有兩個標簽設置值:True,False(默認值)?

CanUseSpriteAtlas Tag

是否可以使用Sprite圖集,有兩個標簽設置值:True,False(默認值)?

PreviewType Tag

在inspector面板視圖下材質球的預覽樣式,有三個標簽值:

Spheres(默認值,材質顯示為球體),Plane(材質顯示為平面),Skybox(材質顯示為天空球)

渲染狀態(tài)(可寫Pass外,也可寫Pass內)

culling階段

Cull控制渲染的哪一面被剔除,有三個不同設置:Back(默認,剔除渲染模型的背面),Front(剔除渲染模型的正面),Off(背面和正面都渲染)

深度測試階段

ZWrite

控制是否寫入深度緩沖,有兩個不同設置:On(默認,寫入深度緩沖),Off(不寫入深度緩沖)

ZTest 控制深度測試邏輯,有以下幾個不同設置:

Greater , GEqual , Less , LEqual(默認值) , Equal , NotEqual , Always , Off。ZTest Off 等同于 ZTest Always

Blending階段

渲染圖形時,在片元通過深度測試和模版測試后,像素將寫入到屏幕。這些像素與已有像素的混合合方式由 Blend 命令控制,Blending主要用于生成透明對象。Blend有幾個以下不同設置:

Blend Off:默認值,關閉混合:

Blend SrcFactor DstFactor: 生成顏色乘以SrcFactor,緩沖區(qū)中的顏色乘以DstFactor,然后將這個值相加

Blend SrcFactor DstFactor, SrcFactorA DstFactorA:功能同上,SrcFactor DstFactor控制RGB混合系數,SrcFactorA DstFactorA控制Alpha(A)通道的混合系數。

BlendOp Op:執(zhí)行不同的混合操作,Op為不同的混合運算,

Op運算語法有以下5個:

Add(默認值,將源顏色和目標顏色相加),Sub(將源顏色減去目標顏色色),RevSub(將目標顏色減去源顏色),Min(源顏色和目標顏色取小值),Max(源顏色和目標顏色取大值)

BlendOp?OpColor, OpAlpha:功能同上。

Unity內部自定義了一些常見的混合類型:

Blend SrcAlpha OneMinusSrcAlpha (傳統(tǒng)透明度);

Blend One OneMinusSrcAlpha (預乘透明度);

Blend One One ( 加法);

Blend OneMinusDstColor One ( 軟加法);

Blend DstColor Zero (乘法);

Blend DstColor SrcColor ( 2x 乘法)

對應的系數說明如下:


Stencil測試階段:

如果開啟模版測試,GPU會首先讀取模版緩沖區(qū)里該片元位置的模版值,然后將該值和讀取到的參考值進行比較,若沒有通過測試,該片元就會被舍棄掉,但不管片元有沒有通過測試,我們都可以根據模版測試的結果來修改模版緩沖區(qū),常用的模版緩沖配置如下:

其Comparison Function如下:

Stencil Operation如下

Pass

pass是Unity Shader中最重要的組成部分,包含渲染的核心——著色器。

pass的結構包含以下:

? ?Name "name": 定義Pass名稱(可選項),便于以后在其他SubShader當中復用該Pass。

? ?Tags:同SubShader Tag;但有些Unity內置的Tag不能放在SubShader里,只能放在Pass內才能生效,比如:

? ? LightMode,PassFlags,RequireOptions。

? ? LightMode:支持以下幾種Tag設置

? ? ?Always(總是渲染,不處理光照);

? ? ?ForwardBase(在前向渲染管線中使用,處理環(huán)境光,直射光,頂點光照)

? ? ?ForwardAdd(在前向渲染管線中使用,處理像素光源)

? ? ?Deferred(在延遲渲染管線中使用,G—Buffer渲染)

?渲染狀態(tài):同SubShader 渲染狀態(tài)。


頂點/片元著色器

用“CGPROGRAM和ENDCG或者HLSLPROGRAM和ENDHLSL”指令包圍的代碼即頂點著色器和片元著色器,代碼結構如下

#pragma vertex聲明頂點著色器函數

#pragma fragment聲明片元著色器函數

a2v結構體表示應用程序傳遞到頂點著色器的模型數據,數據類型如下:

v2f結構體表示把頂點著色器的數據傳遞到片元著色器

vert函數主要作用是頂點變換,把模型坐標從本地空間轉到裁剪空間,并將頂點數據傳遞到片元著色器。

frag函數主要作用是做片元映射和著色,自定義光照模型,根據uv讀取紋理貼圖顏色,并輸出片元數據到測試階段。

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容