Unity3D Shader 入門

什麼是Shader

Shader(着色器)是一段可以針對3D對象進行操做、並被GPU所執行的程序。Shader並非一個統一的標準,不一樣的圖形接口的Shader並不相同。OpenGL的着色語言是GLSL, NVidia開發了Cg,而微軟的Direct3D使用高級着色器語言(HLSL)。而Unity的Shader 是將傳統的圖形接口的Shader(由 Cg / HLSL編寫)嵌入到獨有的描述性結構中而造成的一種代碼生成框架,最終會自動生成各硬件平臺本身的Shader,從而實現跨平臺。html

Unity Shader 其實並不難,初學者每每很迷惑是由於它有太多固定的命令和結構,而這些命令又須要咱們對3D渲染有必定的瞭解才能知道它們是作什麼的。數組


Shader種類

OpenGL和Direct3D都提供了三類着色器:ruby

  • 頂點着色器:處理每一個頂點,將頂點的空間位置投影在屏幕上,即計算頂點的二維座標。同時,它也負責頂點的深度緩衝(Z-Buffer)的計算。頂點着色器能夠掌控頂點的位置、顏色和紋理座標等屬性,但沒法生成新的頂點。頂點着色器的輸出傳遞到流水線的下一步。若是有以後定義了幾何着色器,則幾何着色器會處理頂點着色器的輸出數據,不然,光柵化器繼續流水線任務。
  • 像素着色器(Direct3D),經常又稱爲片段着色器(OpenGL):處理來自光柵化器的數據。光柵化器已經將多邊形填滿並經過流水線傳送至像素着色器,後者逐像素計算顏色。像素着色器經常使用來處理場景光照和與之相關的效果,如凸凹紋理映射和調色。名稱片段着色器彷佛更爲準確,由於對於着色器的調用和屏幕上像素的顯示並不是一一對應。舉個例子,對於一個像素,片段着色器可能會被調用若干次來決定它最終的顏色,那些被遮擋的物體也會被計算,直到最後的深度緩衝纔將各物體先後排序。
  • 幾何着色器:能夠從多邊形網格中增刪頂點。它可以執行對CPU來講過於繁重的生成幾何結構和增長模型細節的工做。Direct3D版本10增長了支持幾何着色器的API, 成爲Shader Model 4.0的組成部分。OpenGL只可經過它的一個插件來使用幾何着色器。

Unity Shader 分爲 表面着色器(Surface Shader)和 頂點片斷着色器(Vertex And Fragment Shader)。app

  • 表面着色器(Surface Shader)是Unity提出的一個概念。編寫着色器與光照的交互是複雜的,光源有不少類型,不一樣的陰影選項,不一樣的渲染路徑(正向和延時渲染),表面着色器將這一部分簡化。Unity建議使用表面着色器來編寫和光照有關的Shader。
  • 頂點片斷着色器(Vertex And Fragment Shader)和OpenGL,Direct3D中的頂點着色器和片斷着色器沒有什麼區別。頂點片斷着色器比表面着色器使用更自由也更強大,固然光照須要自行處理。Unity也容許在裏面編寫幾何着色器,通常用得很少。

Shader程序結構

這裏寫圖片描述

Shader語法:框架

//Shader語法:
Shader "name" { [Properties] Subshaders [Fallback] [CustomEditor] } //Properties 語法 Properties { Property [Property ...] } // Subshader 語法 Subshader { [Tags] [CommonState] Passdef [Passdef ...] } // Pass 語法 Pass { [Name and Tags] [RenderSetup] } // Fallback 語法 Fallback "name"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 屬性定義(Property Definition):定義Shader的輸入,這些輸入能夠在材質編輯的時候指定
  • 子着色器(SubShader):一個Shader能夠有多個子着色器。這些子着色器互不相干且只有一個會在最終的平臺運行。編寫多個的目的是解決兼容性問題。Unity會本身選擇兼容終端平臺的Shader運行。
  • 回滾(Fallback):若是子着色器在終端平臺上都沒法運行,那麼使用Fallback指定的備用Shader,俗稱備胎。
  • Pass:一個Pass就是一次繪製。對於表面着色器,只能有一個Pass,因此不存在Pass節。頂點片斷着色器能夠有多個Pass。屢次Pass能夠實現不少特殊效果,例如當人物被環境遮擋時還能夠看到人物輪廓就能夠用多Pass來實現。
  • Cg代碼:每一個Pass中均可以包含自定義的Cg代碼,從CGPROGRAM開始到ENDCG結束。

基本的表面着色器示例:函數

Shader "Custom/NewShader" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} } SubShader { Tags { "RenderType" = "Opaque" } LOD 200 CGPROGRAM #pragma surface surf Lambert sampler2D _MainTex; struct Input { float2 uv_MainTex; }; void surf (Input IN, inout SurfaceOutput o) { half4 c = tex2D (_MainTex, IN.uv_MainTex); o.Albedo = c.rgb; o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

基本的頂點片斷着色器示例:性能

Shader "VertexInputSimple" { SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct v2f { float4 pos : SV_POSITION; fixed4 color : COLOR; }; v2f vert (appdata_base v) { v2f o; o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.color.xyz = v.normal * 0.5 + 0.5; o.color.w = 1.0; return o; } fixed4 frag (v2f i) : SV_Target { return i.color; } ENDCG } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

Shader 輸入

Shader的輸入有兩個來源,一是經過屬性定義,一是經過Shader.SetGlobalXXX方法全局設置。測試

  • 屬性定義變量:屬性定義中的變量是Shader參數的主要設置方式。 它是隨材質變化的,每一個使用該Shader的材質均可以在Inspector或者腳本中設置這些參數。這些參數除了在Shader的Properties段中定義外,還須要在Cg中聲明方可以使用。例如上面表面着色器的例子中咱們定義了_MainTex這個類型爲2D的屬性,還須要在Cg中聲明 sampler2D _MainTex。this

  • 全局變量:Shader有一組SetGlobalXXX方法,能夠對Shader的在Cg中定義而沒有在屬性中定義的uniform變量進行設置。這個設置是全局的,全部定義了該uniform的Shader都會受到影響。例如咱們但願場景隨着時間變化而改變顏色,就能夠給場景所使用到的Shader設置統一的全局顏色變量,而後在腳本中經過設置該顏色來改變場景的顏色。在角色釋放技能時場景變黑也可使用這個方法。編碼

Unity shader 中容許定義的屬性類型有:

關鍵字 類型 對應Cg類型
Float 浮點數 float _MyFloat (「My float」, Float) = 0.5
Range 浮點數 (在指定範圍內) float _MyRange (「My Range」, Range(0.01, 0.5)) = 0.1
Color 浮點四元組 float4 _MyColor (「Some Color」, Color) = (1,1,1,1)
Vector 浮點四元組 float4 _MyVector(「Some Vector」,Vector) = (1,1,1,1)
2D 2的階數大小的貼圖 sampler2D _MyTexture (「Texture」, 2D) = 「white」 {}
Rect 非2的階數大小的貼圖 sampler2D _MyRect(「My Rect」, Rect) = 「white」 {}
CUBE CubeMap samplerCUBE _MyCubemap (「Cubemap」, CUBE) = 「」 {}

注:CubeMap 是6張有聯繫的2D貼圖的組合主要用來作反射效果(好比天空盒和動態反射)


SubShader

SubShader中除了Pass,有兩個標籤值得關注:LOD和Tags

LOD

LOD是 Level of Detail的簡寫,確切地說是Shader Level of Detail的簡寫,由於Unity中還有一個模型的LOD概念,這是兩個不一樣的東西。咱們這裏只介紹Shader中LOD,模型的LOD請參考這裏

Shader LOD 就是讓咱們設置一個數值,這個數值決定了咱們能用什麼樣的Shader。能夠經過Shader.maximumLOD或者Shader.globalMaximumLOD 設定容許的最大LOD,當設定的LOD小於SubShader所指定的LOD時,這個SubShader將不可用。經過LOD,咱們就能夠爲某個材質寫一組SubShader,指定不一樣的LOD,LOD越大則渲染效果越好,固然對硬件的要求也可能越高,而後根據不一樣的終端硬件配置來設置 globalMaximumLOD來達到兼顧性能的最佳顯示效果。

Unity內建Shader定義了一組LOD的數值,咱們在實現本身的Shader的時候能夠將其做爲參考來設定本身的LOD數值

  • VertexLit及其系列 = 100
  • Decal, Reflective VertexLit = 150
  • Diffuse = 200
  • Diffuse Detail, Reflective Bumped Unlit, Reflective Bumped VertexLit = 250
  • Bumped, Specular = 300
  • Bumped Specular = 400
  • Parallax = 500
  • Parallax Specular = 600

Tag

SubShader能夠被若干的標籤(tags)所修飾,而硬件將經過斷定這些標籤來決定何時調用該着色器。 
比較常見的標籤有:

  • Queue 
    這個標籤很重要,它定義了一個整數,決定了Shader的渲染的次序,數字越小就越早被渲染,早渲染就意味着可能被後面渲染的東西覆蓋掉看不見。 
    預約義的Queue有:
名字 描述
Background 1000 最先被調用的渲染,用來渲染天空盒或者背景
Geometry 2000 這是默認值,用來渲染非透明物體(普通狀況下,場景中的絕大多數物體應該是非透明的)
AlphaTest 2450 用來渲染通過Alpha Test的像素,單獨爲AlphaTest設定一個Queue是出於對效率的考慮
Transparent 3000 以從後往前的順序渲染透明物體
Overlay 4000 用來渲染疊加的效果,是渲染的最後階段(好比鏡頭光暈等特效)
  • RenderType 
    「Opaque」或」Transparent」是兩個經常使用的RenderType。若是輸出中都是非透明物體,那寫在Opaque裏;若是想渲染透明或者半透明的像素,那應該寫在Transparent中。這個Tag主要用ShaderReplacement,通常狀況下這Tag好像也沒什麼做用。

CommonState

SubShader中能夠定義一組Render State,基本上就是一些渲染的開關選項,他們對該SubShader的全部的Pass都有效,因此稱Common。這些Render State也能夠在每一個Pass中分別定義,將在Pass中詳細介紹。


Pass

Render State

Render State主要就是控制渲染過程的一些開關選項,例如是否開啓alpha blending ,是否開啓depth testing。 
經常使用的Render State有:

  • Cull 
    用法:Cull Back | Front | Off 
    多邊形表面剔除開關。Back表示背面剔除,Front表示正面剔除,Off表示關閉表面剔除即雙面渲染。有時候如裙襬,飄帶之類很薄的東西在建模時會作成一個面片,這就須要設置Cull Off來雙面渲染,不然背面會是黑色。

  • ZWrite 
    用法:ZWrite On | Off 
    控制當前對象的像素是否寫入深度緩衝區(depth buffer),默認是開啓的。通常來講繪製不透明物體的話ZWrite開啓,繪製透明或半透明物體則ZWrite關閉。 
    深度緩衝區:當圖形處理卡渲染物體的時候,每個所生成的像素的深度(即 z 座標)就保存在一個緩衝區中。這個緩衝區叫做 z 緩衝區或者深度緩衝區,這個緩衝區一般組織成一個保存每一個屏幕像素深度的 x-y 二維數組。若是場景中的另一個物體也在同一個像素生成渲染結果,那麼圖形處理卡就會比較兩者的深度,而且保留距離觀察者較近的物體。而後這個所保留的物體點深度保存到深度緩衝區中。最後,圖形卡就能夠根據深度緩衝區正確地生成一般的深度感知效果:較近的物體遮擋較遠的物體。 
    理解了深度緩衝區也就理解了爲何繪製透明或半透明物體須要關閉ZWrite, 若是不關閉,透明物體的depth也會被寫入深度緩衝區,從而會剔除掉它後面的物體,後面的物體就不會被渲染,看不見後面的物體還能叫透明嗎?所以咱們使用Alpha blending的時候須要設置ZWrite Off。

  • ZTest 
    用法:ZTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always) 
    控制如何進行深度測試,也就是上面說的圖形處理卡比較兩者的深度的比較方法。默認是LEqual。 
    值得一提的是使用Aplha blending的時候ZWrite須要關閉可是ZTest是要開啓的,由於若是透明物體前面還有不透明物體,透明物體仍是應該被遮擋剔除的。

  • Blend 
    混合。控制了每一個Shader的輸出如何和屏幕上已有的顏色混合。 
    用法: 
    Blend Off: 關閉混合 
    Blend SrcFactor DstFactor:最終顏色 = Shader產生的顏色 × SrcFactor + 屏幕上原來的顏色 × DstFactor 
    Blend SrcFactor DstFactor, SrcFactorA DstFactor:和上面同樣,只是Alpha通道使用後面兩個參數計算 
    經常使用的Blend模式有: 
    Blend SrcAlpha OneMinusSrcAlpha // Alpha blending 
    Blend One One // Additive 
    Blend OneMinusDstColor One // Soft Additive 
    Blend DstColor Zero // Multiplicative 
    Blend DstColor SrcColor // 2x Multiplicative 
    具體參考這裏

Unity5開始下列固定功能的Shader命令被標記爲過期了,這些命令的功能如今建議在Shader(Cg)中經過代碼來實現,這裏列出是爲了方便閱讀之前寫的Shader:

  • Lighting On | Off
  • Material { Material Block }
  • SeparateSpecular On | Off
  • Color Color-value
  • ColorMaterial AmbientAndDiffuse | Emission
  • Fog { Fog Block }
  • AlphaTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always) CutoffValue
  • SetTexture textureProperty { combine options }

Surface Shader

Surface Shader 隱藏了不少光照處理的細節,它的設計初衷是爲了讓用戶僅僅使用一些指令(#pragma)就能夠完成不少事情,而且封裝了不少經常使用的光照模型和函數。相比底層的Vertex And Fragment Shader,Suface Shader的限制比較多,它只能有一次Pass。若是作一些常規的功能又須要光照,能夠用Surface Shader寫,比較快速便捷。若是要寫比較高級的Shader仍是建議使用Vertex Shader 和 Fragment Shader。 
Surface Shader主要有兩部分組成,一個是#pragma後面的指令,一個是surf函數。 
pragma的語法是 #pragma surface surfaceFunction lightModel [optionalparams] 
- surfaceFunction 一般就是名爲surf的函數, 函數名能夠本身取 
surf函數原型是:void surf (Input IN, inout SurfaceOutput o) 
- lightModel是Unity內置的光照模型,能夠是Lambert,Blinn-Phong等。 
- optionalparams: 包含不少指令 詳細參數參考這裏

surf函數主要有一個Input結構的輸入和SurfaceOutput結構的輸出。

Input

Input 結構須要在Shader中定義。它能夠包含以下字段, 若是你定義了這些字段就能夠在surf函數中使用它們(好神奇的黑科技)

  • 多個貼圖的uv座標,名字必須符合格式uv+貼圖名。例如 float2 uv_MainTex
  • float3 viewDir - 視圖方向( view direction)值。爲了計算視差效果(Parallax effects),邊緣光照(rim lighting)等,須要包含視圖方向( view direction)值。
  • float4 with COLOR semantic - 每一個頂點(per-vertex)顏色的插值。
  • float4 screenPos - 屏幕空間中的位置。 爲了反射效果,須要包含屏幕空間中的位置信息。好比在Dark Unity中所使用的 WetStreet着色器。
  • float3 worldPos - 世界空間中的位置。
  • float3 worldRefl - 世界空間中的反射向量。若是表面着色器(surface shader)不寫入法線(o.Normal)參數,將包含這個參數。 請參考這個例子:Reflect-Diffuse 着色器。
  • float3 worldNormal - 世界空間中的法線向量(normal vector)。若是表面着色器(surface shader)不寫入法線(o.Normal)參數,將包含這個參數。
  • float3 worldRefl; INTERNAL_DATA - 世界空間中的反射向量。若是表面着色器(surface shader)不寫入法線(o.Normal)參數,將包含這個參數。
  • float3 worldNormal; INTERNAL_DATA -世界空間中的法線向量(normal vector)。若是表面着色器(surface shader)不寫入法線(o.Normal)參數,將包含這個參數。

SurfaceOutput

SurfaceOutput 描述了表面的特性(光照的顏色反射率、法線、散射、鏡面等),這個結構是固定的,不須要在Shader中再定義。

struct SurfaceOutput { half3 Albedo; //反射率,通常就是在光照以前的原始顏色 half3 Normal; //法線 half3 Emission; //自發光,用於加強物體自身的亮度,使之看起來好像能夠本身發光 half Specular; //鏡面 half Gloss; //光澤 half Alpha; //透明 };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Unity5 因爲引入了基於物理的光照模型,因此新增長了兩個Output

struct SurfaceOutputStandard { fixed3 Albedo; // base (diffuse or specular) color fixed3 Normal; // tangent space normal, if written half3 Emission; half Metallic; // 0=non-metal, 1=metal half Smoothness; // 0=rough, 1=smooth half Occlusion; // occlusion (default 1) fixed Alpha; // alpha for transparencies }; struct SurfaceOutputStandardSpecular { fixed3 Albedo; // diffuse color fixed3 Specular; // specular color fixed3 Normal; // tangent space normal, if written half3 Emission; half Smoothness; // 0=rough, 1=smooth half Occlusion; // occlusion (default 1) fixed Alpha; // alpha for transparencies };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

Unity提供了一些基本的SurfaceShader的例子,有助於咱們理解輸入輸出是如何被使用的。 
Unity提供的SurfaceShader的例子


Vertex Shader

若是不想使用Surface Shader而直接編寫opengl和Direct3D中常見的頂點着色器和片斷着色器,能夠經過Cg代碼段嵌入到Pass中:

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 ENDCG // ... the rest of pass setup ... }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

其中vert就是頂點着色器函數,frag就是片斷着色器函數。通常來講,能夠在頂點着色器中進行的計算就不該該放到片斷着色器中去算,由於頂點着色器是逐頂點計算的而片斷着色器是逐像素計算的,一個模型頂點總比代表像素少不少吧。

編寫頂點和片斷着色器通常須要包含Unity預約義的一個幫助文件UnityCG.cginc,裏面預約義了一些經常使用的結構和方法。Windows版Unity這個文件位於({unity install path}/Data/CGIncludes/UnityCG.cginc。 Mac版位於/Applications/Unity/Unity.app/Contents/CGIncludes/UnityCG.cginc

在代碼中咱們只須要添加 #include "UnityCG.cginc"就可使用裏面的結構和方法。

Input

頂點着色器的原型是 v2f vert (appdata v) 
appdata 是輸入,能夠本身定義也可使用Unity預約義的。Unity在UnityCG.cginc預約義了三種經常使用的輸入結構:appdata_base,appdata_tan,appdata_full。

struct appdata_base { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; }; struct appdata_tan { float4 vertex : POSITION; float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; }; struct appdata_full { float4 vertex : POSITION; float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; float4 texcoord1 : TEXCOORD1; float4 texcoord2 : TEXCOORD2; float4 texcoord3 : TEXCOORD3; #if defined(SHADER_API_XBOX360) half4 texcoord4 : TEXCOORD4; half4 texcoord5 : TEXCOORD5; #endif fixed4 color : COLOR; };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

咱們注意到這些結構的字段和表面着色器中的字段不一樣,後面多了一個冒號和一個標籤。這是該字段的語義,用於告訴GPU這個字段的數據應該去哪裏讀寫。GPU畢竟是爲了圖形計算而特別設計的東西,不少東西都是固定的,咱們只要記得有這麼幾個名字能夠用行了。

類型 名字 標籤 備註
float4 vertex POSITION 頂點在模型座標系下的位置
float3 normal NORMAL 頂點的法向量
float4 tangent TANGENT 頂點的切向量
float4 color COLOR 頂點色
float4 texcoord TEXCOORD0 頂點的第一個uv座標
float4 texcoord1 TEXCOORD1 頂點的第二個uv座標,最多能夠到5

Output

頂點着色器的輸出是也是一個能夠本身定義的結構,可是結構內容也是比較固定的,通常包含了頂點投影后的位置,uv,頂點色等,也能夠加一些後面片斷着色器須要用到可是須要在頂點着色器中計算的值。這個輸出就是後面片斷着色器的輸入。

struct v2f { float4 pos : SV_POSITION; half2 uv : TEXCOORD0; };
  • 1
  • 2
  • 3
  • 4
  • 5

可使用的字段有:

類型 標籤 描述
float4 SV_POSITION 頂點在投影空間下的位置,注意和輸入的模型座標系下的位置不一樣,這個字段必必須設置,這個座標轉換是頂點着色器的重要工做
float3 NORMAL 頂點在視圖座標系下的法向量
float4 TEXCOORD0 第一張貼圖的uv座標
float4 TEXCOORD1 第二張貼圖的uv座標
float4 TANGENT 切向量,主要用來修正法線貼圖Normal Maps
fixed4 COLOR 第一個定點色
fixed4 COLOR1 第二個定點色
Any Any 其餘自定義的字段

座標變換

頂點着色器有一項重要的工做就是進行座標變換。頂點着色器的輸入中的座標是模型座標系(ObjectSpace)下的座標,而最終繪製到屏幕上的是投影座標。 
在咱們Shader裏面只須要一句話就能夠完成座標的轉換,這也是最簡單的頂點着色器:

v2f vert(appdata v) {
          v2f o;
          o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
          return o; }
  • 1
  • 2
  • 3
  • 4
  • 5

用UNITY_MATRIX_MVP矩陣乘以頂點在模型座標系下的座標就獲得投影座標。 
UNITY_MATRIX_MVP是Unity內建的模型->視->投影矩陣, Unity內建矩陣以下:

  • UNITY_MATRIX_MVP:當前模型->視圖->投影矩陣。(注:模型矩陣爲 本地->世界)
  • UNITY_MATRIX_MV:當前模型->視圖矩陣
  • UNITY_MATRIX_V:當前視圖矩陣
  • UNITY_MATRIX_P:當前投影矩陣
  • UNITY_MATRIX_VP:當前視圖->投影矩陣
  • UNITY_MATRIX_T_MV:轉置模型->視圖矩陣
  • UNITY_MATRIX_IT_MV:逆轉置模型->視矩陣, 用於將法線從ObjectSpace旋轉到WorldSpace。爲何法線變化不能和位置變換同樣用UNITY_MATRIX_MV呢?一是由於法線是3維的向量而- UNITY_MATRIX_MV是一個4x4矩陣,二是由於法線是向量,咱們只但願對它旋轉,可是在進行空間變換的時候,若是發生非等比縮放,方向會發生偏移。
  • UNITY_MATRIX_TEXTURE0 to UNITY_MATRIX_TEXTURE3:紋理變換矩陣

下面簡單介紹一下里面提到的幾個座標系: 
模型座標系:也叫物體座標系,3D建模的時候每一個模型都是在本身的座標系下創建的,若是一我的物模型腳底是(0,0,0) 點的話它的身上其它點的座標都是相對腳底這個原點的。 
世界座標系:咱們場景是一個世界,有本身的原點,模型放置到場景中後模型上的每一個頂點就有了一個新的世界座標。這個座標能夠經過模型矩陣×模型上頂點的模型座標獲得。 
視圖座標系:又叫觀察座標系,是以觀察者(相機)爲原點的座標系。場景中的物體只有被相機觀察到纔會繪製到屏幕上,相機能夠設置視口大小和裁剪平面來控制可視範圍,這些都是相對相機來講的,因此須要把世界座標轉換到視圖座標系來方便處理。 
投影座標系:場景是3D的,可是最終繪製到屏幕上是2D,投影座標系完成這個降維的工做,投影變換後3D的座標就變成2D的座標了。投影有平行投影和透視投影兩種,能夠在Unity的相機上設置。 
屏幕座標系 : 最終繪製到屏幕上的座標。屏幕的左下角爲原點。

除了內建矩陣,Unity還內建了一些輔助函數也能夠在頂點着色器裏面使用:

  • float3 WorldSpaceViewDir (float4 v):根據給定的局部空間頂點位置到相機返回世界空間的方向(非規範化的)
  • float3 ObjSpaceViewDir (float4 v):根據給定的局部空間頂點位置到相機返回局部空間的方向(非規範化的)
  • float2 ParallaxOffset (half h, half height, half3 viewDir):爲視差法線貼圖計算UV偏移
  • fixed Luminance (fixed3 c):將顏色轉換爲亮度(灰度)
  • fixed3 DecodeLightmap (fixed4 color):從Unity光照貼圖解碼顏色(基於平臺爲RGBM 或dLDR)
  • float4 EncodeFloatRGBA (float v):爲儲存低精度的渲染目標,編碼[0..1)範圍的浮點數到RGBA顏色。
  • float DecodeFloatRGBA (float4 enc):解碼RGBA顏色到float。
  • float2 EncodeViewNormalStereo (float3 n):編碼視圖空間法線到在0到1範圍的兩個數。
  • float3 DecodeViewNormalStereo (float4 enc4):從enc4.xy解碼視圖空間法線

Fragment Shader

相關文章
相關標籤/搜索