本文出處:http://blog.csdn.net/lcbcsdn/article/details/46848125
(1)數學函數
函數 | 功能描述 |
---|---|
abs(x) | 返回輸入參數的絕對值 |
acos(x) | 反餘切函數,輸入參數範圍爲[-1,1], 返回[0,π]區間的角度值 |
all(x) | 如果輸入參數均不爲0,則返回ture; 否則返回flase。&&運算 |
any(x) | 輸入參數只要有其中一個不爲0,則返回true。 |
asin(x) | 反正弦函數,輸入參數取值區間爲,返回角度值範圍爲, |
atan(x) | 反正切函數,返回角度值範圍爲 |
atan2(y,x) | 計算y/x的反正切值。實際上和atan(x)函數功能完全一樣,至少輸入參數不同。atan(x) = atan2(x, float(1))。 |
ceil(x) | 對輸入參數向上取整。例如: ceil(float(1.3)) ,其返回值爲2.0 |
clamp(x,a,b) | 如果x值小於a,則返回a; 如果x值大於b,返回b; 否則,返回x。 |
cos(x) | 返回弧度x的餘弦值。返回值範圍爲 |
cosh(x) | 雙曲餘弦(hyperbolic cosine)函數,計算x的雙曲餘弦值。 |
cross(A,B) | 返回兩個三元向量的叉積(cross product)。注意,輸入參數必須是三元向量! |
degrees(x) | 輸入參數爲弧度值(radians),函數將其轉換爲角度值(degrees) |
determinant(m) | 計算矩陣的行列式因子。 |
dot(A,B) | 返回A和B的點積(dot product)。參數A和B可以是標量,也可以是向量(輸入參數方面,點積和叉積函數有很大不同)。 |
exp(x) | 計算的值,e=2.71828182845904523536 |
exp2(x) | 計算的值 |
floor(x) | 對輸入參數向下取整。例如floor(float(1.3))返回的值爲1.0;但是floor(float(-1.3))返回的值爲-2.0。該函數與ceil(x)函數相對應。 |
fmod(x,y) | 返回x/y的餘數。如果y爲0,結果不可預料。 |
frac(x) | 返回標量或矢量的小數 |
frexp(x, out i) | 將浮點數x分解爲尾數和指數,即, 返回m,並將指數存入i中;如果x爲0,則尾數和指數都返回0 |
isfinite(x) | 判斷標量或者向量中的每個數據是否是有限數,如果是返回true;否則返回false; |
isinf(x) | 判斷標量或者向量中的每個數據是否是無限,如果是返回true;否則返回false; |
isnan(x) | 判斷標量或者向量中的每個數據是否是非數據(not-a-number NaN),如果是返回true;否則返回false; |
ldexp(x, n) | 計算的值 |
lerp(a, b, f) | 計算或者的值。即在下限a和上限b之間進行插值,f表示權值。注意,如果a和b是向量,則權值f必須是標量或者等長的向量。 |
lit(NdotL, NdotH, m) | N表示法向量; L表示入射光向量; H表示半角向量; m表示高光係數。 函數計算環境光、散射光、鏡面光的貢獻,返回的4元向量。 X位表示環境光的貢獻,總是1.0; Y位代表散射光的貢獻,如果 ,則爲0;否則爲 Z位代表鏡面光的貢獻,如果 或者,則位0;否則爲; W位始終位1.0 |
log(x) | 計算的值,x必須大於0 |
log2(x) | 計算的值,x必須大於0 |
log10(x) | 計算的值,x必須大於0 |
max(a, b) | 比較兩個標量或等長向量元素,返回最大值。 |
min(a,b) | 比較兩個標量或等長向量元素,返回最小值。 |
modf(x, out ip) | 把x分解成整數和分數兩部分,每部分都和x有着相同的符號,整數部分被保存在ip中,分數部分由函數返回 |
mul(M, N) | 矩陣M和矩陣N的積,計算方法如下 |
mul(M, v) | 矩陣M和列向量v的積,公式如下 |
mul(v, M) | 行向量v和矩陣M的積,公式如下 |
noise(x) | 根據它的參數類型,這個函數可以是一元、二元或三元噪音函數。返回的值在0和1之間,並且通常與給定的輸入值一樣 |
pow(x, y) | |
radians(x) | 函數將角度值轉換爲弧度值 |
round(x) | 返回四捨五入值。 |
rsqrt(x) | x的平方根的倒數,x必須大於0 |
saturate(x) | 把x限制到[0,1]之間 |
sign(x) | 如果則返回1;否則返回0 |
sin(x) | 輸入參數爲弧度,計算正弦值,返回值範圍 爲[-1,1] |
sincos(float x, out s, out c) | 該函數是同時計算x的sin值和cos值,其中s=sin(x),c=cos(x)。該函數用於“同時需要計算sin值和cos值的情況”,比分別運算要快很多! |
sinh(x) | 計算x的雙曲正弦 |
smoothstep(min, max, x) | 值x位於min、max區間中。如果x=min,返回0;如果x=max,返回1;如果x在兩者之間,按照下列公式返回數據: |
step(a, x) | 如果,返回0;否則,返回1 |
sqrt(x) | 求x的平方根,,x必須大於0 |
tan(x) | 計算x正切值 |
tanh(x) | 計算x的雙曲線切線 |
transpose(M) | 矩陣M的轉置矩陣 如果M是一個AxB矩陣,M的轉置是一個BxA矩陣,它的第一列是M的第一行,第二列是M的第二行,第三列是M的第三行,等等 |
(2)幾何函數
函數 | 功能描述 |
---|---|
distance(pt1, pt2) | 兩點之間的歐幾里德距離(Euclidean distance) |
faceforward(N,I,Ng) | 如果,返回N;否則返回-N。 |
length(v) | 返回一個向量的模,即sqrt(dot(v,v)) |
normalize(v) | 返回v向量的單位向量 |
reflect(I, N) | 根據入射光纖方向I和表面法向量N計算反射向量,僅對三元向量有效 |
refract(I,N,eta) | 根據入射光線方向I,表面法向量N和折射相對係數eta,計算折射向量。如果對給定的eta,I和N之間的角度太大,返回(0,0,0)。 只對三元向量有效 |
(3)紋理映射函數
函數 | 功能描述 |
---|---|
tex1D(sampler1D tex, float s) | 一維紋理查詢 |
tex1D(sampler1D tex, float s, float dsdx, float dsdy) | 使用導數值(derivatives)查詢一維紋理 |
Tex1D(sampler1D tex, float2 sz) | 一維紋理查詢,並進行深度值比較 |
Tex1D(sampler1D tex, float2 sz, float dsdx,float dsdy) | 使用導數值(derivatives)查詢一維紋理, 並進行深度值比較 |
Tex1Dproj(sampler1D tex, float2 sq) | 一維投影紋理查詢 |
Tex1Dproj(sampler1D tex, float3 szq) | 一維投影紋理查詢,並比較深度值 |
Tex2D(sampler2D tex, float2 s) | 二維紋理查詢 |
Tex2D(sampler2D tex, float2 s, float2 dsdx, float2 dsdy) | 使用導數值(derivatives)查詢二維紋理 |
Tex2D(sampler2D tex, float3 sz) | 二維紋理查詢,並進行深度值比較 |
Tex2D(sampler2D tex, float3 sz, float2 dsdx,float2 dsdy) | 使用導數值(derivatives)查詢二維紋理,並進行深度值比較 |
Tex2Dproj(sampler2D tex, float3 sq) | 二維投影紋理查詢 |
Tex2Dproj(sampler2D tex, float4 szq) | 二維投影紋理查詢,並進行深度值比較 |
texRECT(samplerRECT tex, float2 s) | 二維非投影矩形紋理查詢(OpenGL獨有) |
texRECT (samplerRECT tex, float3 sz, float2 dsdx,float2 dsdy) | 二維非投影使用導數的矩形紋理查詢(OpenGL獨有) |
texRECT (samplerRECT tex, float3 sz) | 二維非投影深度比較矩形紋理查詢(OpenGL獨有) |
texRECT (samplerRECT tex, float3 sz, float2 dsdx,float2 dsdy) | 二維非投影深度比較並使用導數的矩形紋理查詢(OpenGL獨有) |
texRECT proj(samplerRECT tex, float3 sq) | 二維投影矩形紋理查詢(OpenGL獨有) |
texRECT proj(samplerRECT tex, float3 szq) | 二維投影矩形紋理深度比較查詢(OpenGL獨有) |
Tex3D(sampler3D tex, float s) | 三維紋理查詢 |
Tex3D(sampler3D tex, float3 s, float3 dsdx, float3 dsdy) | 結合導數值(derivatives)查詢三維紋理 |
Tex3Dproj(sampler3D tex, float4 szq) | 查詢三維投影紋理,並進行深度值比較 |
texCUBE(samplerCUBE tex, float3 s) | 查詢立方體紋理 |
texCUBE (samplerCUBE tex, float3 s, float3 dsdx, float3 dsdy) | 結合導數值(derivatives)查詢立方體紋理 |
texCUBEproj (samplerCUBE tex, float4 sq) | 查詢投影立方體紋理 |
在這個表中,每個函數第二個參數的名字指明瞭在執行紋理查詢的時候,它的值是如果被使用的:
- s表示這是一個一元、二元或三元紋理座標。
- z表示這是一個用來進行陰影貼圖查找的深度比較值。
- q表示這是一個透視值,在進行紋理查找之前,它被用來除以紋理座標(s)。
當你使用的紋理函數允許你指定一個深度比較值的時候,與之相關聯的紋理單元必須被設置成深度比較紋理。否則,深度比較實際上不會被執行。
(4)偏導函數
函數 | 功能描述 |
---|---|
ddx(a) | 近似a關於屏幕空間x軸的偏導數 |
ddy(a) | 近似a關於屏幕空間y軸的偏導數 |
(5)調試函數
函數 | 功能描述 |
---|---|
void debug(float4 x) | 如果在編譯時設置了DEBUG,片段着 色程序中調用該函數可以將值x作爲COLOR語義的最終輸出;否則該函數什麼也不做。 |
Unity ShaderLab學習總結
Why Bothers?
爲什麼已經有ShaderForge這種可視化Shader編輯器、爲什麼Asset Store已經有那麼多炫酷的Shader組件可下載,還是有必要學些Shader的編寫?
2014-0718-1607-11-33.png
- 因爲上面這些Shader工具/組件最終都是以Shader文件的形式而存在。
- 需要開發人員/技術美術有能力對Shader進行功能分析、效率評估、選擇、優化、兼容、甚至是Debug。
- 對於特殊的需求,可能還是直接編寫Shader比較實際、高效。
總之,Shader編寫是重要的;但至於緊不緊急,視乎項目需求。
涉及範圍
本文只討論Unity ShaderLab相關的知識和使用方法。但,
- 既不討論渲染相關的基礎概念;
- 基礎概念可參考Rendering Pipeline Overview等文章。
- 作爲移動設備GPU和桌面GPU的最大不同點,tile-based deferred rendering (Wiki,PowerVR/Mali/Adreno)也是重要的概念。
其大幅減少帶寬消耗、會進行Early-Z測試嘗試減少Overdraw(依賴於渲染物體提交順序由前至後)。
其中PowerVR的Hidden Surface Removal做到像素級別的Overdraw減少(不用依賴於渲染物體提交順序由前至後)。
- 也不討論具體的渲染技巧。
參考資源
- Youtube:https://www.youtube.com/watch?v=hDJQXzajiPg (包括part1-6)。視頻是最佳的入門方式沒有之一,所以牆裂建議就算不看下文的所有內容,都要去看一下part1。
- 書籍:《Unity 3D ShaderLab開發實戰詳解》
- Unity各種官方文檔
使用Shader
2014-0720-1007-25-36.png
如上圖,一句話總結:
- GameObject裏有MeshRenderer,
- MeshRenderer裏有Material列表,
- 每個Material裏有且只有一個Shader;
- Material在編輯器暴露該Shader的可調屬性。
所以關鍵是怎麼編寫Shader。
Shader基礎
編輯器
使用MonoDevelop這反人類的IDE來編寫Shader居然是讓人滿意的。有語法高亮,無語法提示。
如果習慣VisualStudio,可以如下實現.Shader文件的語法高亮。
- 下載作者donaldwu自己添加的關鍵詞文件usertype.dat。其包括了Unity ShaderLab的部分關鍵字,和HLSL的所有關鍵字。關鍵字以後持續添加中。
- 將下載的usertype.dat放到Microsoft Visual Studio xx.x\CommonX\IDE\文件夾下;
- 打開VS,工具>選項>文本編輯器>文件擴展名,擴展名裏填“shader”,編輯器選VC++,點擊添加;
- 重啓VS,Done。
Shader
-
Shader "ShaderLab Tutorials/TestShader"
-
{
-
// ...
-
}
2014-0720-1707-17-42.png
Shader的名字會直接決定shader在material裏出現的路徑
SubShader
-
Shader "ShaderLab Tutorials/TestShader" {
-
SubShader
-
{
-
//...
-
}
-
}
一個Shader有多個SubShader。一個SubShader可理解爲一個Shader的一個渲染方案。即SubShader是爲了針對不同的渲染情況而編寫的。每個Shader至少1個SubShader、理論可以無限多個,但往往兩三個就足夠。
一個時刻只會選取一個SubShader進行渲染,具體SubShader的選取規則包括:
- 從上到下選取
- SubShader的標籤、Pass的標籤
- 是否符合當前的“Unity渲染路徑”
- 是否符合當前的ReplacementTag
- SubShader是否和當前的GPU兼容
- 等
按此規則第一個被選取的SubShader將會用於渲染,未被選取的SubShader在這次渲染將被忽略。
SubShader的Tag
-
Shader "ShaderLab Tutorials/TestShader" {
-
SubShader
-
{
-
Tags { "Queue"="Geometry+10" "RenderType"="Opaque" }
-
//...
-
}
-
}
SubShader內部可以有標籤(Tags)的定義。Tag指定了這個SubShader的渲染順序(時機),以及其他的一些設置。
"RenderType"
標籤。Unity可以運行時替換符合特定RenderType的所有Shader。Camera.RenderWithShader
或Camera.SetReplacementShader
配合使用。Unity內置的RenderType包括:"Opaque"
:絕大部分不透明的物體都使用這個;"Transparent"
:絕大部分透明的物體、包括粒子特效都使用這個;"Background"
:天空盒都使用這個;"Overlay"
:GUI、鏡頭光暈都使用這個;- 用戶也可以定義任意自己的
RenderType
這個標籤所取的值。 - 應注意,
Camera.RenderWithShader
或Camera.SetReplacementShader
不要求標籤只能是RenderType
,RenderType
只是Unity內部用於Replace的一個標籤而已,你也可以自定義自己全新的標籤用於Replace。
比如,你爲自己的ShaderA.SubShaderA1(會被Unity選取到的SubShader,常爲Shader文件中的第一個SubShader)增加Tag爲"Distort"="On"
,然後將"Distort"
作爲參數replacementTag
傳給函數。此時,作爲replacementShader
實參的ShaderB.SubShaderB1中若有也有一模一樣的"Distort"="On"
,則此SubShaderB1將代替SubShaderA1用於本次渲染。 - 具體可參考Rendering with Replaced Shaders
"Queue"
標籤。定義渲染順序。預製的值爲"Background"
。值爲1000。比如用於天空盒。"Geometry"
。值爲2000。大部分物體在這個隊列。不透明的物體也在這裏。這個隊列內部的物體的渲染順序會有進一步的優化(應該是從近到遠,early-z test可以剔除不需經過FS處理的片元)。其他隊列的物體都是按空間位置的從遠到近進行渲染。"AlphaTest"
。值爲2450。已進行AlphaTest的物體在這個隊列。"Transparent"
。值爲3000。透明物體。"Overlay"
。值爲4000。比如鏡頭光暈。- 用戶可以定義任意值,比如
"Queue"="Geometry+10"
"ForceNoShadowCasting"
,值爲"true"
時,表示不接受陰影。"IgnoreProjector"
,值爲"true"
時,表示不接受Projector組件的投影。
另,關於渲染隊列和Batch的非官方經驗總結是,一幀的渲染隊列的生成,依次決定於每個渲染物體的:
- Shader的RenderType tag,
- Renderer.SortingLayerID,
- Renderer.SortingOrder,
- Material.renderQueue(默認值爲Shader裏的"Queue"),
- Transform.z(ViewSpace)(默認爲按z值從前到後,但當Queue是“Transparent”的時候,按z值從後到前)。
這個渲染隊列決定了之後(可能有dirty flag的機制?)渲染器再依次遍歷這個渲染隊列,“同一種”材質的渲染物體合到一個Batch裏。
Pass
-
Shader "ShaderLab Tutorials/TestShader" {
-
SubShader {
-
Pass
-
{
-
//...
-
}
-
}
-
}
一個SubShader(渲染方案)是由一個個Pass塊來執行的。每個Pass都會消耗對應的一個DrawCall。在滿足渲染效果的情況下儘可能地減少Pass的數量。
Pass的Tag
-
Shader "ShaderLab Tutorials/TestShader" {
-
SubShader {
-
Pass
-
{
-
Tags{ "LightMode"="ForwardBase" }
-
//...
-
}
-
}
-
}
和SubShader有自己專屬的Tag類似,Pass也有Pass專屬的Tag。
其中最重要Tag是 "LightMode"
,指定Pass和Unity的哪一種渲染路徑(“Rendering Path”)搭配使用。除最重要的ForwardBase
、ForwardAdd
外,這裏需額外提醒的Tag取值可包括:
Always
,永遠都渲染,但不處理光照ShadowCaster
,用於渲染產生陰影的物體ShadowCollector
,用於收集物體陰影到屏幕座標Buff裏。
其他渲染路徑相關的Tag詳見下面章節“Unity渲染路徑種類”。
具體所有Tag取值,可參考ShaderLab syntax: Pass Tags。
FallBack
-
Shader "ShaderLab Tutorials/TestShader"{
-
SubShader { Pass {} }
-
FallBack "Diffuse" // "Diffuse"即Unity預製的固有Shader
-
// FallBack Off //將關閉FallBack
-
}
當本Shader的所有SubShader都不支持當前顯卡,就會使用FallBack語句指定的另一個Shader。FallBack最好指定Unity自己預製的Shader實現,因其一般能夠在當前所有顯卡運行。
Properties
-
Shader "ShaderLab Tutorials/TestShader"
-
{
-
Properties {
-
_Range ("My Range", Range (0.02,0.15)) = 0.07 // sliders
-
_Color ("My Color", Color) = (.34, .85, .92, 1) // color
-
_2D ("My Texture 2D", 2D) = "" {} // textures
-
_Rect("My Rectangle", Rect) = "name" { }
-
_Cube ("My Cubemap", Cube) = "name" { }
-
_Float ("My Float", Float) = 1
-
_Vector ("My Vector", Vector) = (1,2,3,4)
-
// Display as a toggle.
-
[Toggle] _Invert ("Invert color?", Float) = 0
-
// Blend mode values
-
[Enum(UnityEngine.Rendering.BlendMode)] _Blend ("Blend mode", Float) = 1
-
//setup corresponding shader keywords.
-
[KeywordEnum(Off, On)] _UseSpecular ("Use Specular", Float) = 0
-
}
-
// Shader
-
SubShader{
-
Pass{
-
//...
-
uniform float4 _Color;
-
//...
-
float4 frag() : COLOR{ return fixed4(_Color); }
-
//...
-
#pragma multi_compile __ _USESPECULAR_ON
-
}
-
}
-
//fixed pipeline
-
SubShader {
-
Pass{
-
Color[_Color]
-
}
-
}
-
}
- Shader在Unity編輯器暴露給美術的參數,通過Properties來實現。
- 所有可能的參數如上所示。主要也就Float、Vector和Texture這3類。
- 除了通過編輯器編輯Properties,腳本也可以通過
Material
的接口(比如SetFloat
、SetTexture
編輯) - 之後在Shader程序通過
[name]
(固定管線)或直接name
(可編程Shader)訪問這些屬性。 - 在每一個Property前面也能類似C#那樣添加Attribute,以達到額外UI面板功能。詳見MaterialPropertyDrawer.html。
Shader中的數據類型
有3種基本數值類型:float
、half
和fixed
。
這3種基本數值類型可以再組成vector和matrix,比如half3
是由3個half
組成、float4x4
是由16個float
組成。
float
:32位高精度浮點數。half
:16位中精度浮點數。範圍是[-6萬, +6萬],能精確到十進制的小數點後3.3位。fixed
:11位低精度浮點數。範圍是[-2, 2],精度是1/256。
數據類型影響性能
- 精度夠用就好。
- 顏色和單位向量,使用
fixed
- 其他情況,儘量使用
half
(即範圍在[-6萬, +6萬]內、精確到小數點後3.3位);否則才使用float
。
- 顏色和單位向量,使用
ShaderLab中的Matrix
當提到“Row-Major”、“Column-Major”,根據不同的場合,它們可能指不同的意思:
- 數學上的,主要是指矢量V是Row Vector、還是Column Vector。引用自[Game Engine Architecture 2nd Edition, 183]。留意到V和M的乘法,當是Row Vector的時候,數學上寫作VM,Matrix在右邊,Matrix的最下面一行表示Translate;當是Column Vector的時候,數學上寫作MtVt,Matrix在左邊並且需要轉置,Matrix最右面一列表示Translate。
- 訪問接口上的:Row-Major即MyMatrix[Row][Column]、Column-Major即MyMatrix[Column][Row]。HLSL/CG的訪問接口都是Row-Major,比如MyMatrix[3]返回的是第3行;GLSL的訪問接口是Column-Major,比如MyMatrix[3]返回的是第3列。
- 寄存器存儲上的:每個元素是按行存儲在寄存器中、還是按列存儲在寄存器中。需要關注它的一般情況舉例是,float2x3的MyMatrix,到底是佔用2個寄存器(Row-Major)、還是3個寄存器(Column-Major)。在HLSL裏,可以通過#pragmapack_matrix設定row_major或者column_major。
上述情況,互不相干。
然後,ShaderLab中,數學上是Column Vector、訪問接口上是Row-Major、存儲上是(尚未查明)。另外,ShaderLab在World Space是左手座標系、View Space是右手座標系、在Normalized Device Coordinates裏是左手座標系。
-
v2f vert (appdata v)
-
{
-
v2f o;
-
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
-
// 1 、2、3是等價的,和4是不等價的
-
// 因爲是M在左、V在右,所以是Column Vector
-
// 因爲是HLSL/CG語言,所以是訪問方式是Row-Major
-
o.rootInView = mul(UNITY_MATRIX_MV, float4(0, 0, 0, 1)); // 1
-
o.rootInView = float4(UNITY_MATRIX_MV[0].w, UNITY_MATRIX_MV[1].w, UNITY_MATRIX_MV[2].w, 1); // 2
-
o.rootInView = UNITY_MATRIX_MV._m03_m13_m23_m33; // 3
-
//o.rootInView = UNITY_MATRIX_MV[3]; // 4
-
return o;
-
}
-
fixed4 frag (v2f i) : SV_Target
-
{
-
// 因爲是ViewSpace是右手座標系,所以當root在view前面的時候,z是負數,所以需要-z才能正確顯示顏色
-
fixed4 col = fixed4(i.rootInView.x, i.rootInView.y, -i.rootInView.z, 1);
-
return col;
-
}
-
struct appdata
-
{
-
float4 vertex : POSITION;
-
};
-
struct v2f
-
{
-
float4 rootInView : TEXCOORD0;
-
float4 vertex : SV_POSITION;
-
};
Shader形態
Shader形態之1:固定管線
固定管線是爲了兼容老式顯卡。都是頂點光照。之後固定管線可能是被Unity拋棄的功能,所以最好不學它、當它不存在。特徵是裏面出現了形如下面Material
塊、沒有CGPROGRAM
和ENDCG
塊。
-
Shader "ShaderLab Tutorials/TestShader"
-
{
-
Properties {
-
_Color ("My Color", Color) = (.34, .85, .92, 1) // color
-
}
-
// Fixed Pipeline
-
SubShader
-
{
-
Pass
-
{
-
Material{
-
Diffuse [_Color]
-
Ambient [_Color]
-
}
-
Lighting On
-
}
-
}
-
}
Shader形態之2:可編程Shader
-
Shader "ShaderLab Tutorials/TestShader"
-
{
-
Properties {}
-
SubShader
-
{
-
Pass
-
{
-
// ... the usual pass state setup ...
-
CGPROGRAM
-
// compilation directives for this snippet, e.g.:
-
#pragma vertex vert
-
#pragma fragment frag
-
// the Cg/HLSL code itself
-
float4 vert(float4 v:POSITION) : SV_POSITION{
-
return mul(UNITY_MATRIX_MVP, v);
-
}
-
float4 frag() : COLOR{
-
return fixed4(1.0, 0.0, 0.0, 1.0);
-
}
-
ENDCG
-
// ... the rest of pass setup ...
-
}
-
}
-
}
- 功能最強大、最自由的形態。
- 特徵是在Pass裏出現
CGPROGRAM
和ENDCG
塊 - 編譯指令
#pragma
。詳見官網Cg snippets。其中重要的包括:
編譯指令 | 示例/含義 |
---|---|
#pragma vertex name #pragma fragment name |
替換name,來指定Vertex Shader函數、Fragment Shader函數。 |
#pragma target name |
替換name(爲2.0 、3.0 等)。設置編譯目標shader model的版本。 |
#pragma only_renderers name name ... #pragma exclude_renderers name name... |
#pragma only_renderers gles gles3 ,#pragma exclude_renderers d3d9 d3d11 opengl ,只爲指定渲染平臺(render platform)編譯 |
- 引用庫。通過形如
#include "UnityCG.cginc"
引入指定的庫。常用的就是UnityCG.cginc
了。其他庫詳見官網Built-in shader include files。 - ShaderLab內置值。Unity給Shader程序提供了便捷的、常用的值,比如下面例子中的
UNITY_MATRIX_MVP
就代表了這個時刻的MVP矩陣。詳見官網ShaderLab built-in values。 - Shader輸入輸出參數語義(Semantics)。在管線流程中每個階段之間(比如Vertex Shader階段和FragmentShader階段之間)的輸入輸出參數,通過語義字符串,來指定參數的含義。常用的語義包括:
COLOR
、SV_Position
、TEXCOORD[n]
。完整的參數語義可見HLSL Semantic(由於是HLSL的連接,所以可能不完全在Unity裏可以使用)。 - 特別地,因爲Vertex Shader的的輸入往往是管線的最開始,Unity爲此內置了常用的數據結構:
數據結構 | 含義 |
---|---|
appdata_base | vertex shader input with position, normal, one texture coordinate. |
appdata_tan | vertex shader input with position, normal, tangent, one texture coordinate. |
appdata_full | vertex shader input with position, normal, tangent, vertex color and two texture coordinates. |
appdata_img | vertex shader input with position and one texture coordinate. |
Shader形態之3:SurfaceShader
-
Shader "ShaderLab Tutorials/TestShader"
-
{
-
Properties { }
-
// 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"
-
}
- SurfaceShader可以認爲是一個光照Shader的語法糖、一個光照VS/FS的生成器。減少了開發者寫重複代碼的需要。
- 在手遊,由於對性能要求比較高,所以不建議使用SurfaceShader。因爲SurfaceShader是一個比較“通用”的功能,而通用往往導致性能不高。
- 特徵是在SubShader裏出現
CGPROGRAM
和ENDCG
塊。(而不是出現在Pass裏。因爲SurfaceShader自己會編譯成多個Pass。) - 編譯指令是:
#pragma surface surfaceFunction lightModel [optionalparams]
surfaceFunction
:surfaceShader函數,形如void surf (Input IN, inout SurfaceOutput o)
lightModel
:使用的光照模式。包括Lambert
(漫反射)和BlinnPhong
(鏡面反射)。- 也可以自己定義光照函數。比如編譯指令爲
#pragma surface surf MyCalc
- 在Shader裏定義
half4 LightingMyCalc (SurfaceOutput s, 參數略)
函數進行處理(函數名在簽名加上了“Lighting”)。 - 詳見Custom Lighting models in Surface Shaders
- 在Shader裏定義
- 也可以自己定義光照函數。比如編譯指令爲
- 你定義輸入數據結構(比如上面的
Input
)、編寫自己的Surface函數處理輸入、最終輸出修改過後的SurfaceOutput。SurfaceOutput的定義爲-
struct SurfaceOutput {
-
half3 Albedo; // 紋理顏色值(r, g, b)
-
half3 Normal; // 法向量(x, y, z)
-
half3 Emission; // 自發光顏色值(r, g, b)
-
half Specular; // 鏡面反射度
-
half Gloss; // 光澤度
-
half Alpha; // 不透明度
-
};
-
Shader形態之4:Compiled Shader
點擊a.shader
文件的“Compile and show code”,可以看到該文件的“編譯”過後的ShaderLab shader文件,文件名形如Compiled-a.shader
。
其依然是ShaderLab文件,其包含最終提交給GPU的shader代碼字符串。
先就其結構進行簡述如下,會發現和上述的編譯前ShaderLab結構很相似。
-
// Compiled shader for iPhone, iPod Touch and iPad, uncompressed size: 36.5KB
-
// Skipping shader variants that would not be included into build of current scene.
-
Shader "ShaderLab Tutorials/TestShader"
-
{
-
Properties {...}
-
SubShader {
-
// Stats for Vertex shader:
-
// gles : 14 avg math (11..19), 1 avg texture (1..2)
-
// metal : 14 avg math (11..17)
-
// Stats for Fragment shader:
-
// metal : 14 avg math (11..19), 1 avg texture (1..2)
-
Pass {
-
Program "vp" // vertex program
-
{
-
SubProgram "gles" {
-
// Stats: 11 math, 1 textures
-
Keywords{...} // keywords for shader variants ("uber shader")
-
//shader codes in string
-
"
-
#ifdef VERTEX
-
vertex shader codes
-
#endif
-
// Note, on gles, fragment shader stays here inside Program "vp"
-
#ifdef FRAGMENT
-
fragment shader codes
-
#endif
-
"
-
}
-
SubProgram "metal" {
-
some setup
-
Keywords{...}
-
//vertex shader codes in string
-
"..."
-
}
-
}
-
Program "fp" // fragment program
-
{
-
SubProgram "gles" {
-
Keywords{...}
-
"// shader disassembly not supported on gles" //(because gles fragment shader codes are in Program "vp")
-
}
-
SubProgram "metal" {
-
common setup
-
Keywords{...}
-
//fragment shader codes in string
-
"..."
-
}
-
}
-
}
-
}
-
...
-
}
Unity渲染路徑(Rendering Path)種類
概述
開發者可以在Unity工程的PlayerSettings設置對渲染路徑進行3選1:
- Deferred Lighting,延遲光照路徑。3者中最高質量地還原光照陰影。光照性能只與最終像素數目有關,光源數量再多都不會影響性能。
- Forward Rendering,順序渲染路徑。能發揮出Shader全部特性的渲染路徑,當然也就支持像素級光照。最常用、功能最自由,性能與光源數目*受光照物體數目有關,具體性能視乎其具體使用到的Shader的複雜度。
- Vertex Lit,頂點光照路徑。頂點級光照。性能最高、兼容性最強、支持特性最少、品質最差。
渲染路徑的內部階段和Pass的LightMode標籤
每個渲染路徑的內部會再分爲幾個階段。
然後,Shader裏的每個Pass,都可以指定爲不同的LightMode。而LightMode實際就是說:“我希望這個Pass在這個XXX渲染路徑的這個YYY子階段被執行”。
Deferred Ligting
渲染路徑內部子階段 | 對應的LightMode | 描述 |
---|---|---|
Base Pass | "PrepassBase" |
渲染物體信息。即把法向量、高光度到一張ARGB32的物體信息紋理上,把深度信息保存在Z-Buff上。 |
Lighting Pass | 無對應可編程Pass | 根據Base Pass得出的物體信息,在屏幕座標系下,使用BlinnPhong光照模式,把光照信息渲染到ARGB32的光照信息紋理上(RGB表示diffuse顏色值、A表示高光度) |
Final Pass | "PrepassFinal" |
根據光照信息紋理,物體再渲染一次,將光照信息、紋理信息和自發光信息最終混合。LightMap也在這個Pass進行。 |
Forward Rendering
渲染路徑內部子階段 | 對應的LightMode | 描述 |
---|---|---|
Base Pass | "ForwardBase" |
渲染:最亮一個的方向光光源(像素級)和對應的陰影、所有頂點級光源、LightMap、所有LightProbe的SH光源(Sphere Harmonic,球諧函數,效率超高的低頻光)、環境光、自發光。 |
Additional Passes | "ForwardAdd" |
其他需要像素級渲染的的光源 |
注意到的是,在Forward Rendering中,光源可能是像素級光源、頂點級光源或SH光源。其判斷標準是:
- 配製成“Not Important”的光源都是頂點級光源和SH光源
- 最亮的方向光永遠都是像素級光源
- 配置成“Important”的都是像素級光源
- 上面2種情況加起來的像素級光源數目小於“Quality Settings”裏面的“Pixel Light Count”的話,會把第1種情況的光源補爲額外的像素級光源。
另外,配置成“Auto”的光源有更復雜的判斷標註,截圖如下:
2014-0720-1607-31-40.png
具體可參考Forward Rendering Path Details。
Vertex Lit
渲染路徑內部子階段 | 對應的LightMode | 描述 |
---|---|---|
Vertex | "Vertex" |
渲染無LightMap物體 |
VertexLMRGBM | "VertexLMRGBM" |
渲染有RGBM編碼的LightMap物體 |
VertexLM | "VertexLM" |
渲染有雙LDR編碼的LightMap物體 |
不同LightMode的Pass的被選擇
一個工程的渲染路徑是唯一的,但一個工程裏的Shader是允許配有不同LightMode的Pass的。
在Unity,策略是“從工程配置的渲染路徑模式開始,按Deferred、Forward、VertxLit的順序,搜索最匹配的LightMode的一個Pass”。
比如,在配置成Deferred路徑時,優先選有Deferred相關LightMode的Pass;找不到纔會選Forward相關的Pass;還找不到,纔會選VertexLit相關的Pass。
再比如,在配置成Forward路徑時,優先選Forward相關的Pass;找不到纔會選VertexLit相關的Pass。
原文鏈接:http://www.jianshu.com/p/7b9498e58659
************轉http://www.tuicool.com/articles/ABNbyi*******************
因爲Unity中基礎的固定功能Shader的知識點基本上講完,下期開始就要準備講表面着色器(Surface Shader)了,所以在文章開頭,讓我們複習和更深入瞭解一下Unity中Shader的三種形態。
在Unity中,Shader便可以分成如下三種基本類型:
1. 固定功能着色器(FixedFunction Shader)
2. 表面着色器(SurfaceShader)
3. 頂點着色器&片段着色器(Vertex Shader & Fragment Shader)
顧名思義,其中的固定功能着色器便是我們所說的固定功能渲染管線(fixed-functionrenderingpipelines)的具體表現,而表面着色器、頂點着色器以及片段着色器便屬於可編程渲染管線。下面分別對其進行簡單的介紹。
1.1 Unity中的Shader形態之一:固定功能Shader
這裏的固定功能着色器可以說是Unity爲Shader的書寫自帶的一層殼,Unity已經在內部爲我們做了大量的工作,我們只要稍微記住一些關鍵字、一些規範就可以實現出很多不錯的效果。固定功能着色器是我們初學Unity Shader的最近幾篇文章中的主要學習對象。而後面的表面着色器、頂點着色器以及片段着色器就是在固定功能着色器的基礎上嵌套了CG語言的代碼而成的更加複雜的着色器。我們來看看他們的一些基本概念。
固定管線是爲了兼容老式顯卡。都爲頂點光照,就是我們前四篇文章加上這篇文章中講到的內容。
其特徵是裏面的核心是下面Material材質屬性塊、沒有CGPROGRAM和ENDCG塊,以及各種頂點着色和片段着色的宏命令。
一個光照材質完備版的固定功能Shader示例如下:
Shader "淺墨Shader編程/Volume5/固定功能的Shader示例" { //-------------------------------【屬性】----------------------------------------- Properties { _Color ("主顏色", Color) = (1,1,1,0) _SpecColor ("高光顏色", Color) = (1,1,1,1) _Emission ("自發光顏色", Color) = (0,0,0,0) _Shininess ("光澤度", Range (0.01, 1)) = 0.7 _MainTex ("基本紋理", 2D) = "white" {} } //--------------------------------【子着色器】-------------------------------- SubShader { //----------------通道--------------- Pass { //-----------材質------------ Material { //可調節的漫反射光和環境光反射顏色 Diffuse [_Color] Ambient [_Color] //光澤度 Shininess [_Shininess] //高光顏色 Specular [_SpecColor] //自發光顏色 Emission [_Emission] } //開啓光照 Lighting On //開啓獨立鏡面反射 SeparateSpecular On //設置紋理並進行紋理混合 SetTexture [_MainTex] { Combine texture * primary DOUBLE, texture * primary } } } }
1.2 Unity中的Shader形態之二:表面着色器SurfaceShader
這部分算是Unity微創新自創的一套着色器標準。
表面着色器(Surface Shader)這個概念更多的只是在Unity中聽說,可以說是Unity自己發揚光大的一項使Shader的書寫門檻降低和更易用的技術。我們會在接下來的學習中逐漸意識到Unity是如何爲我們把Shader的複雜性包裝起來,使其書寫的過程更便捷和易用
的。一些特性如下:
• SurfaceShader可以認爲是一個光照Shader的語法塊、一個光照VS/FS的生成器。減少了開發者寫重複代碼的需要。
• 特徵是在SubShader裏出現CGPROGRAM和ENDCG塊。(而不是出現在Pass裏。因爲SurfaceShader自己會編譯成多個Pass。)
• 編譯指令是:
#pragma surface surfaceFunction lightModel[optionalparams]
o surfaceFunction:surfaceShader函數,形如void surf (Input IN, inoutSurfaceOutput o)
o lightModel:使用的光照模式。包括Lambert(漫反射)和BlinnPhong(鏡面反射)。
也可以自己定義光照函數。比如編譯指令爲#pragma surface surf MyCalc
在Shader裏定義half4 LightingMyCalc (SurfaceOutputs, 參數略)函數進行處理(函數名在簽名加上了“Lighting”)。
• 我們自己定義輸入數據結構(比如上面的Input)、編寫自己的Surface函數處理輸入、最終輸出修改過後的SurfaceOutput。而SurfaceOutput的定義爲:
struct SurfaceOutput { half3 Albedo; // 紋理顏色值(r, g, b) half3 Normal; // 法向量(x, y, z) half3 Emission; // 自發光顏色值(r, g, b) half Specular; // 鏡面反射度 half Gloss; // 光澤度 half Alpha; // Alpha不透明度 };
上面是一些特性總結,讓我們看一個具體Shader示例:
Shader "淺墨Shader編程/Volume5/表面Shader示例 " { //-------------------------------【屬性】----------------------------------------- Properties { _MainTex ("【紋理】Texture", 2D) = "white" {} _BumpMap ("【凹凸紋理】Bumpmap", 2D) = "bump" {} _RimColor ("【邊緣顏色】Rim Color", Color) = (0.17,0.36,0.81,0.0) _RimPower ("【邊緣顏色強度】Rim Power", Range(0.6,9.0)) = 1.0 } //----------------------------【開始一個子着色器】--------------------------- SubShader { //渲染類型爲Opaque,不透明 Tags { "RenderType" = "Opaque" } //-------------------開始CG着色器編程語言段----------------- CGPROGRAM //使用蘭伯特光照模式 #pragma surface surf Lambert //輸入結構 struct Input { float2 uv_MainTex;//紋理貼圖 float2 uv_BumpMap;//法線貼圖 float3 viewDir;//觀察方向 }; //變量聲明 sampler2D _MainTex;//主紋理 sampler2D _BumpMap;//凹凸紋理 float4 _RimColor;//邊緣顏色 float _RimPower;//邊緣顏色強度 //表面着色函數的編寫 void surf (Input IN, inout SurfaceOutput o) { //表面反射顏色爲紋理顏色 o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb; //表面法線爲凹凸紋理的顏色 o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap)); //邊緣顏色 half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal)); //邊緣顏色強度 o.Emission = _RimColor.rgb * pow (rim, _RimPower); } //-------------------結束CG着色器編程語言段------------------ ENDCG } //“備胎”爲普通漫反射 Fallback "Diffuse" }
1.3 Unity中的Shader形態之三:可編程Shader
可編程Shader其實就是頂點着色器和片段着色器,這一部分和DirectX系的HLSL和CG着色器語言聯繫緊密。其實就是Unity給HLSL和CG報了一個ShaderLab的殼。
研究過Direct3D和OpenGL着色器編程的童鞋們一定對頂點着色器和片段着色器不陌生。我們來簡單介紹一下他們的用途。
頂點着色器:產生紋理座標,顏色,點大小,霧座標,然後把它們傳遞給裁剪階段。
片段着色器:進行紋理查找,決定什麼時候執行紋理查找,是否進行紋理查找,及把什麼作爲紋理座標。
可編程Shader的特點爲:
-
- 功能最強大、最自由的形態。
- 特徵是在Pass裏出現CGPROGRAM和ENDCG塊
- 編譯指令#pragma。詳見 官網Cg snippets 。其中重要的包括:
編譯指令 |
示例/含義 |
#pragma vertex name #pragma fragment name |
替換name,來指定Vertex Shader函數、Fragment Shader函數。 |
#pragma target name |
替換name(爲2.0、3.0等)。設置編譯目標shader model的版本。 |
#pragma only_renderers name name ... #pragma exclude_renderers name name... |
#pragma only_renderers gles gles3, #pragma exclude_renderers d3d9 d3d11 opengl, 只爲指定渲染平臺(render platform)編譯 |
-
- 關於引用庫。通過形如#include "UnityCG.cginc"引入指定的庫。常用的就是UnityCG.cginc了。其他庫詳見 官網Built-in shader include files 。
- ShaderLab內置值。Unity給Shader程序提供了便捷的、常用的值,比如下面例子中的UNITY_MATRIX_MVP就代表了這個時刻的MVP矩陣。詳見 官網ShaderLab built-in values 。
- Shader輸入輸出參數語義(Semantics)。在管線流程中每個階段之間(比如Vertex Shader階段和FragmentShader階段之間)的輸入輸出參數,通過語義字符串,來指定參數的含義。常用的語義包括:COLOR、SV_Position、TEXCOORD[n]。完整的參數語義可見 HLSL Semantic (由於是HLSL的連接,所以可能不完全在Unity裏可以使用)。
- 特別地,因爲Vertex Shader的的輸入往往是管線的最開始,Unity爲此內置了常用的數據結構:
數據結構 |
含義 |
appdata_base |
頂點着色器 輸入位置、法線以及一個紋理座標。 |
appdata_tan |
頂點着色器 輸入位置、法線、切線以及一個紋理座標。 |
appdata_full |
頂點着色器 輸入位置、法線、切線、頂點顏色以及兩個紋理座標。 |
appdata_img |
頂點着色器 輸入位置以及一個紋理座標。 |
讓我們用一個可編程着色器Shader示例結束此部分的講解:
Shader "淺墨Shader編程/Volume5/可編程Shader示例" { //-------------------------------【屬性】-------------------------------------- Properties { _Color ("Color", Color) = (1.0,1.0,1.0,1.0) _SpecColor ("Specular Color", Color) = (1.0,1.0,1.0,1.0) _Shininess ("Shininess", Float) = 10 } //--------------------------------【子着色器】-------------------------------- SubShader { //-----------子着色器標籤---------- Tags { "LightMode" = "ForwardBase" } //----------------通道--------------- Pass { //-------------------開始CG着色器編程語言段----------------- CGPROGRAM #pragma vertex vert #pragma fragment frag //---------------聲明變量-------------- uniform float4 _Color; uniform float4 _SpecColor; uniform float _Shininess; //--------------定義變量-------------- uniform float4 _LightColor0; //--------------頂點輸入結構體------------- struct vertexInput { float4 vertex : POSITION; float3 normal : NORMAL; }; //--------------頂點輸出結構體------------- struct vertexOutput { float4 pos : SV_POSITION; float4 col : COLOR; }; //--------------頂點函數-------------- vertexOutput vert(vertexInput v) { vertexOutput o; //一些方向 float3 normalDirection = normalize( mul( float4(v.normal, 0.0), _World2Object ).xyz ); float3 viewDirection = normalize( float3( float4( _WorldSpaceCameraPos.xyz, 1.0) - mul(_Object2World, v.vertex).xyz ) ); float3 lightDirection; float atten = 1.0; //光照 lightDirection = normalize(_WorldSpaceLightPos0.xyz); float3 diffuseReflection = atten * _LightColor0.xyz * max( 0.0, dot( normalDirection, lightDirection ) ); float3 specularReflection = atten * _LightColor0.xyz * _SpecColor.rgb * max( 0.0, dot( normalDirection, lightDirection ) ) * pow( max( 0.0, dot( reflect( -lightDirection, normalDirection ), viewDirection ) ), _Shininess ); float3 lightFinal = diffuseReflection + specularReflection + UNITY_LIGHTMODEL_AMBIENT; //計算結果 o.col = float4(lightFinal * _Color.rgb, 1.0);//顏色 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);//位置 return o; } //--------------片段函數--------------- float4 frag(vertexOutput i) : COLOR { return i.col; } //-------------------結束CG着色器編程語言段------------------ ENDCG } } //備胎 Fallback "Diffuse" }
OK,下面我們來看本次文章的主角——blending操作。
二、混合操作(Blending)
我們直奔主題吧。混合操作最常見的用途便是用來製作透明物體、或者是進行紋理的混合。它是Shader渲染的最後一步:
如上圖所示,正被渲染的像素經過頂點光照、頂點着色器、剔除和深度測試,霧效、Alpha測試等一系列操作之後,最後一步便是混合操作。這個時候計算結果即將被輸出到幀緩衝中。而混合操作,就是管理如何將這些像素輸出到幀緩存中的這樣一個過程——是直接替換原來的,是一加一的混合,還是有Alpha參與的不等比地混合等等。
混合操作有兩個對象:源和目標,因此也有兩個對應的因子,即源因子和目標因子(對應於下面講解的Blend SrcFactor DstFactor操作)。
而如果我們把RGB顏色通道和Alpha通道分開來操作的話,混合就有了4個操作對象(對應於下面講解的Blend SrcFactor DstFactor,SrcFactorA DstFactorA操作)。
2.1 混合操作相關的句法
Blend Off
Turn off blending 關閉混合
Blend SrcFactorDstFactor
基本的配置並啓動混操作。對產生的顏色乘以SrcFactor.對 已存在於屏幕的顏色乘以DstFactor,並且兩者將被疊加在一起。
Blend SrcFactorDstFactor, SrcFactorA DstFactorA
同上,但是使用不同的要素來混合alpha通道,也就是有了4個操作對象
BlendOp Add / Min | Max | Sub | RevSub
此操作不是Blend操作一樣添加混合顏色在一起,而是對它們做不同的操作。
而如下便是常用混合操作符(blend operations)的含義列舉:
Add |
將源像素和目標像素相加. |
Sub |
用源像素減去目標像素 |
RevSub |
用目標像素減去源像素 |
Min |
取目標像素和源像素顏色的較小者作爲結果 |
Max |
取目標像素和源像素顏色的較大者作爲結果 |
2.2 混合因子(Blend factors)列舉
以下所有的屬性都可作爲SrcFactor或DstFactor。其中,Source指的是被計算過的顏色,Destination是已經在屏幕上的顏色。
One | 值爲1,使用此因子來讓幀緩衝區源顏色或是目標顏色完全的通過。 |
Zero | 值爲0,使用此因子來刪除幀緩衝區源顏色或目標顏色的值。 |
SrcColor | 使用此因子爲將當前值乘以幀緩衝區源顏色的值 |
SrcAlpha | 使用此因子爲將當前值乘以幀緩衝區源顏色Alpha的值。 |
DstColor | 使用此因子爲將當前值乘以幀緩衝區源顏色的值。 |
DstAlpha | 使用此因子爲將當前值乘以幀緩衝區源顏色Alpha分量的值。 |
OneMinusSrcColor | 使用此因子爲將當前值乘以(1 -幀緩衝區源顏色值) |
OneMinusSrcAlpha | 使用此因子爲將當前值乘以(1 -幀緩衝區源顏色Alpha分量的值) |
OneMinusDstColor | 使用此因子爲將當前值乘以(1 –目標顏色值) |
OneMinusDstAlpha | 使用此因子爲將當前值乘以(1 –目標Alpha分量的值) |
2.3 常見的混合操作句法示例
上面都是一些句法和列表的列舉,往往會令人一頭霧水,下面這是一些示例,用其中的任何一句加在Pass中就可以實現對應的混合操作了:
Blend SrcAlpha OneMinusSrcAlpha // Alpha混合 Blend One One // 相加 Blend One OneMinusDstColor // 比較柔和的相加(SoftAdditive) Blend DstColor Zero // 乘法 Blend DstColor SrcColor // 2倍乘法
三、QianMo's Toolkit升級到v1.3
這次QianMo's Toolkit又迎來了新的特性——飛翔。
將腳本賦給Controller,並調整相應的速度,(並可以先禁掉之前的鼠標視角控制相關腳本)然後點運行,並可以在天空中自由地飛翔了。
其中用W、A、S、D控制前後左右,R、F控制上升下降。
其代碼如下:
-
//-----------------------------------------------【腳本說明】-------------------------------------------------------
-
// 腳本功能: 控制Contorller在場景中飛翔
-
// 使用語言: C#
-
// 開發所用IDE版本:Unity4.5 06f 、Visual Studio 2010
-
// 2014年12月 Created by 淺墨
-
// 更多內容或交流,請訪問淺墨的博客:http://blog.csdn.net/poem_qianmo
-
//---------------------------------------------------------------------------------------------------------------------
-
//-----------------------------------------------【使用方法】-------------------------------------------------------
-
// 第一步:在Unity中拖拽此腳本到場景的Controller之上,或在Inspector中[Add Component]->[淺墨's Toolkit]->[SetMaxFPS]
-
// 第二步:在面板中設置相關鼠標速度
-
//---------------------------------------------------------------------------------------------------------------------
-
using UnityEngine;
-
using System.Collections;
-
//添加組件菜單
-
[AddComponentMenu("淺墨's Toolkit/FlyController")]
-
public class FlyController : MonoBehaviour
-
{
-
//參數定義
-
public float lookSpeed = 5.0f;
-
public float moveSpeed = 1.0f;
-
public float rotationX = 0.0f;
-
public float rotationY = 0.0f;
-
void Update()
-
{
-
//獲取鼠標偏移量
-
rotationX += Input.GetAxis("Mouse X") * lookSpeed;
-
rotationY += Input.GetAxis("Mouse Y") * lookSpeed;
-
rotationY = Mathf.Clamp(rotationY, -90, 90);
-
//鼠標控制視角
-
transform.localRotation = Quaternion.AngleAxis(rotationX, Vector3.up);
-
transform.localRotation *= Quaternion.AngleAxis(rotationY, Vector3.left);
-
transform.position += transform.forward * moveSpeed * Input.GetAxis("Vertical");
-
transform.position += transform.right * moveSpeed * Input.GetAxis("Horizontal");
-
//I鍵,向上平移
-
if (Input.GetKey(KeyCode.R))
-
transform.position += transform.up * moveSpeed;
-
//K鍵,向下平移
-
if (Input.GetKey(KeyCode.F))
-
transform.position -= transform.up * moveSpeed;
-
}
-
}