歡迎前往個(gè)人博客 駑馬點(diǎn)滴 和視頻空間 嗶哩嗶哩-《挨踢日志》
以渲染模型為例子纫溃,講述了在沒有 Unity 編輯器情形下進(jìn)行渲染的偽代碼:
加載頂點(diǎn)著色器巍沙、片元著色器 -> 加載到 GPU 中 -> 設(shè)置頂點(diǎn)數(shù)據(jù) -> 設(shè)置紋理數(shù)據(jù) -> 設(shè)置 MVP 矩陣 -> 設(shè)置是否混合 -> 深度測(cè)試 -> 其他設(shè)置
這樣的設(shè)置需要管理多個(gè)文件、函數(shù)等象浑,對(duì)開發(fā)者負(fù)擔(dān)比較重蔫饰。
為了解決上面對(duì)問題,Unity 提供了 Unity Shader 讓開發(fā)者更加輕松的管理著色器代碼和渲染設(shè)置愉豺。
3.1 Unity Shader 概述
3.1.1 一對(duì)好兄弟:材質(zhì)和 Unity Shader
Unity 中需要配合使用材質(zhì)(Material)和 Unity Shader 才能達(dá)到需要的效果篓吁。
一個(gè)常見的流程:
- 創(chuàng)建一個(gè)材質(zhì);
- 創(chuàng)建一個(gè) Unity Shader蚪拦;
- 將 Unity Shader 賦給材質(zhì)杖剪;
- 將材質(zhì)賦給需要渲染的對(duì)象冻押;
- 在材質(zhì)面板中調(diào)整 Unity Shader 的屬性,以得到滿意的效果摘盆;
3.1.2 Unity 中的材質(zhì)
材質(zhì)如何創(chuàng)建翼雀?
- Project 視圖->右鍵->Create->Material (推薦做法)
- Unity 菜單欄->Assets->Create->Material
備注:兩個(gè)彈窗是一樣的。
選中創(chuàng)建的材質(zhì)孩擂,會(huì)出現(xiàn)對(duì)應(yīng)的面板狼渊,方便調(diào)整材質(zhì)的參數(shù)。
3.1.3 Unity 中的 Shader
Unity 中的 Shader 有 4 類:
- Standard Surface Shader 包含了標(biāo)準(zhǔn)光照模型的表面著色器模板类垦;
- Unlit Shader 不含光照的 Shader
- Image Effect Shader 為屏幕后處理效果服務(wù)
- Compute Shader 主要用于和渲染無(wú)關(guān)的 GPU 計(jì)算(利用 GPU 并行性)
3.2 Unity Shader 的基礎(chǔ) ShaderLab
ShaderLab 是 Unity Shader 的說(shuō)明性語(yǔ)言狈邑。結(jié)構(gòu)如下:
Shader "ShaderName" {
Properties {
// 屬性
}
SubShader {
// 顯卡 A 使用的著色器
}
SubShader {
// 顯卡 B 使用的著色器
}
Fallback "VertexLit"
}
Unity 會(huì)將 Unity Shader 編譯成真正的代碼和 Shader 文件,開發(fā)人員只需要和 Unity Shader 打交道蚤认。
3.3 Unity Shader 的結(jié)構(gòu)
3.3.1 給我們的 Unity Shader 起個(gè)名字
如果創(chuàng)建的 Shader 形如:
Shader "Custom/MyShader" {}
那么在材質(zhì)面板上選擇 Shader 的時(shí)候米苹,其路徑為: Shader -> Custom -> MyShader
3.3.2 材質(zhì)和 Unity Shader 的橋梁:Properties
Properties {
Name1 ("display name1", PropertyType1) = DefaultValue1
Name2 ("display name2", PropertyType2) = DefaultValue2
}
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
}
Properties 語(yǔ)義塊支持的屬性類型:
_Int("Int", Int) = 2
_Float("Float", Float) = 1.5
_Range("Range", Range(0.0, 5.0)) = 3.0
_Color("Color", Color) = (1,1,1,1)
_Vector("Vector", Vector) = (2,3,6,1)
_2D("2D", 2D) = ""{}
_Cube("Cube", Cube) = "white" {}
_3D("3D", 3D) = "black"{}
為了在 Shader 中使用這些屬性,需要在 Cg 代碼片中定義這些屬性類型相匹配的變量砰琢。
Properties 語(yǔ)義塊的作用僅僅是為了讓這些屬性可以出現(xiàn)在材質(zhì)面板中蘸嘶。
3.3.3 重量級(jí)成員 SubShader
一個(gè) Unity Shader 可以有多個(gè) SubShader 語(yǔ)義塊。Unity 加載 Unity Shader 時(shí)陪汽,會(huì)掃描所有的 SubShader 训唱,選擇第一個(gè)能夠在目標(biāo)平臺(tái)上運(yùn)行的 SubShader。否則將使用 Fallback 指定的 Unity Shader挚冤】鲈觯——這樣可以針對(duì)不同顯卡的設(shè)備進(jìn)行有針對(duì)性的表現(xiàn)。
SubShader 的格式如下:
[Tags]
[RenderSetup]
Pass {
}
// .......
Pass 可以有多個(gè)训挡,但是多個(gè) Pass 會(huì)造成渲染性能下降——盡量使用最少數(shù)目的 Pass澳骤。
[RenderSetup] 是可選狀態(tài),包括剔除模式澜薄、深度測(cè)試为肮、深度寫入、混合模式相關(guān)的內(nèi)容表悬。(具體的參數(shù)暫時(shí)不需要了解弥锄,后續(xù)深入學(xué)習(xí))
[Tags] 是一個(gè)鍵值對(duì),鍵和值都是字符串蟆沫。
Tags { "TagName1" = "Value1" "TagName2" = "Value2" }
包括以下標(biāo)簽:
Queue——控制渲染順序 Tags {"Queue"="Transparent"}
RenderType——對(duì)著色器進(jìn)行分類 Tags {"RenderType"="Opaque"}
DisableBatching——是否禁用批處理 Tags {"DisableBatching"="True"}
ForceNoShaderCasting——強(qiáng)制沒有投射陰影 Tags {"ForceNoShaderCasting"="True"}
IgnoreProjector——是否忽略 Projector 的影響(通常用于半透明物體) Tags {"IgnoreProjector"="True"}
CanUseSpriteAtlas——當(dāng)該 SubShader 用于精靈時(shí)籽暇,該標(biāo)簽設(shè)置為 False Tags {"CanUseSpriteAtlas"="False"}
PreviewType——指明材質(zhì)面板將如何預(yù)覽該材質(zhì)(默認(rèn)是一個(gè)球形,可以改為 "Plane"饭庞、"SkyBox") Tags {"PreviewType"="Plane"}
Pass 語(yǔ)義塊
UsePass:復(fù)用其他 Unity Shader 中的 Pass戒悠。 用法: UsePass "MyShader/MYPASSNAME"
GrabPass:該 Pass 抓取屏幕并將結(jié)果儲(chǔ)存在一張紋理中,用于后續(xù)的 Pass 處理舟山。
3.4 Unity Shader 的形式
Unity 中主要可以使用 3 種形式來(lái)便攜 Unity Shader
- 表面著色器
- 頂點(diǎn)/片元著色器
- 固定函數(shù)著色器
無(wú)論哪種著色器绸狐,真正意義上的 Shader 代碼都需要包含在 ShaderLab 語(yǔ)義塊中:
Shader "MyShader" {
Properties {
// 所需的各種屬性
}
SubShader {
// 真正意義上的 Shader 代碼出現(xiàn)在此處
// 表面著色器
// 頂點(diǎn)/片元著色器
// 固定函數(shù)著色器
}
}
3.4.1 表面著色器
表面著色器(Surface Shader)是 Unity 自己創(chuàng)造的一種著色器代碼類型卤恳。特點(diǎn)是:需要的代碼量少,渲染代價(jià)比較大寒矿,多光照?qǐng)鼍跋率褂谩?/p>
Shader "Custom/Simple Surface Shader" {
SubShader {
Tags { "RenderType"="Opaque"}
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float4 color : COLOR;
};
void surf(Input IN, inout SurfaceOutput o){
o.Albedo = 1;
}
ENDCG
}
Fallback "Diffuse"
}
注意點(diǎn): Cg/HLSL 語(yǔ)言和原生的基本一致突琳,但少數(shù)原生函數(shù)和用法 Unity 沒有支持。
3.4.2 頂點(diǎn)/片元著色器
頂點(diǎn)/片元著色器的代碼要寫在 CGPROGRAM 和 ENDCG 之間符相。我們可能要編寫更多的代碼拆融,但是靈活性最高。
Shader "Custom/Simple VertexFragment Shader" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 vert(float4 v : POSITION) : SV_POSITION {
return mul (UNITY_MATRIX_MVP, v);
}
fixed4 frag() : SV_Target {
return fixed4(1.0,0.0,0.0,1.0);
}
ENDCG
}
}
}
3.4.3 固定函數(shù)著色器 Fixed Function Shader
固定著色器必須使用 ShaderLab 語(yǔ)法啊终。后續(xù)基本不實(shí)用镜豹。
3.4.4 選擇哪種形式的 Unity Shader
- 除非明確需要使用到固定函數(shù)著色器,否則一般不使用蓝牲;
- 如果需要和各種光源打交道趟脂,那么使用表面著色器。但是需要小心移動(dòng)平臺(tái)的性能表現(xiàn)例衍;
- 如果光源比較少昔期,比如只有一個(gè)平行光,那么使用頂點(diǎn)/片元著色器是一個(gè)更好的選擇佛玄;
- 如果有很多需要自定義的渲染效果镇眷,請(qǐng)選擇頂點(diǎn)/片元著色器。
3.5 本書使用的 Unity Shader 的形式
本書重點(diǎn)使用頂點(diǎn)/片元著色器進(jìn)行 Unity Shader 的編寫翎嫡。
歡迎前往個(gè)人博客 駑馬點(diǎn)滴 和視頻空間 嗶哩嗶哩-《挨踢日志》