[轉]Unity Shader 學習總結

1.先來一段單張紋理貼圖的shader示例代碼:html

 1 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
 2 
 3 Shader "Custom/MyShader"{
 4 Properties{
 5     //外部可調屬性
 6     _MainTex ("Main Tex", 2D) = "white" {}
 7 }
 8 SubShader
 9 {
10     //設置使用本Subshader所須要知足的渲染路徑等參數,若是知足,即便用本shader
11     Tags {"Queue"="Transparent""RenderType"="Transparent"}
12     Pass
13     {
14     //設置該pass 的渲染狀態和標籤
15     Tags { "LightMode"="ForwardBase" }
16     //開始cg代碼片斷
17     CGPROGRAM
18     //該代碼的編譯指令, 
19     #pragma vertex vert//設置頂點着色器的函數名稱
20     #pragma fragment frag//設置片斷着色器的函數名稱
21     #include "Lighting.cginc"//包含庫文件
22 
23     struct a2v {
24         float4 vertex : POSITION;//當前要渲染的頂點座標
25         float4 texcoord : TEXCOORD0;//當前要渲染的頂點的第一套紋理座標
26     };
27             
28     struct v2f {
29         float4 pos : SV_POSITION;//
30         float2 uv : TEXCOORD0;
31     };
32     sampler2D _MainTex;
33     float4 _MainTex_ST;
34 
35     v2f vert(a2v v)
36     {
37         v2f o;
38         o.pos=UnityObjectToClipPos(v.vertex);//將頂點座標變換到裁剪空間中
39         o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);//變換uv座標
40         return o;
41     }
42 
43     fixed4 frag(v2f i):SV_Target
44     {
45         fixed4 c = tex2D (_MainTex, i.uv);//對紋理座標進行採樣
46         return c;
47     }
48     ENDCG
49     }
50     //SubShader
51     //{
52     //    //若是不知足第一個subshader所須要的條件,那麼再來檢測是否知足第二subshader 的條件。    
53     //}
54     }
55 FallBack "Diffuse"
56 }
MyShader.shader

SubShader

Shader "ShaderLab Tutorials/TestShader" {
    SubShader
    {
        //...
    }
}

一個Shader有多個SubShader。一個SubShader可理解爲一個Shader的一個渲染方案。即SubShader是爲了針對不一樣的渲染狀況而編寫的。每一個Shader至少1個SubShader、理論能夠無限多個,但每每兩三個就足夠。
一個時刻只會選取一個SubShader進行渲染,具體SubShader的選取規則包括:android

  • 從上到下選取
  • SubShader的標籤、Pass的標籤
    • 是否符合當前的「Unity渲染路徑」
    • 是否符合當前的ReplacementTag
  • SubShader是否和當前的GPU兼容

按此規則第一個被選取的SubShader將會用於渲染,未被選取的SubShader在此次渲染將被忽略。編程

SubShader的Tag

Shader "ShaderLab Tutorials/TestShader" {
    SubShader
    {
        Tags { "Queue"="Geometry+10" "RenderType"="Opaque" }
        //...
    }
}

shader內部能夠有標籤(Tags)的定義。Tag指定了這個SubShader的渲染順序(時機),以及其餘的一些設置。windows

  • "RenderType"標籤。Unity能夠運行時替換符合特定RenderType的全部Shader。Camera.RenderWithShaderCamera.SetReplacementShader配合使用。Unity內置的RenderType包括:
    • "Opaque":絕大部分不透明的物體都使用這個;
    • "Transparent":絕大部分透明的物體、包括粒子特效都使用這個;
    • "Background":天空盒都使用這個;
    • "Overlay":GUI、鏡頭光暈都使用這個;
    • 用戶也能夠定義任意本身的RenderType這個標籤所取的值。
    • 應注意,Camera.RenderWithShaderCamera.SetReplacementShader不要求標籤只能是RenderTypeRenderType只是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的非官方經驗總結是,一幀的渲染隊列的生成,依次決定於每一個渲染物體的:sass

  • 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" }
            //...
        }
    }
}
shader有本身專屬的Tag相似,Pass也有Pass專屬的Tag。

其中最重要Tag是 "LightMode",指定Pass和Unity的哪種渲染路徑(「Rendering Path」)搭配使用。除最重要的ForwardBaseForwardAdd外,這裏需額外提醒的Tag取值可包括:app

  • 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實現,因其通常可以在當前全部顯卡運行。ide

Properties

 1 Shader "ShaderLab Tutorials/TestShader"
 2 {
 3     Properties {
 4     _Range ("My Range", Range (0.02,0.15)) = 0.07 // sliders
 5     _Color ("My Color", Color) = (.34, .85, .92, 1) // color
 6     _2D ("My Texture 2D", 2D) = "" {} // textures
 7     _Rect("My Rectangle", Rect) = "name" { }
 8     _Cube ("My Cubemap", Cube) = "name" { }
 9     _Float ("My Float", Float) = 1
10     _Vector ("My Vector", Vector) = (1,2,3,4)
11 
12     // Display as a toggle.
13     [Toggle] _Invert ("Invert color?", Float) = 0
14     // Blend mode values
15     [Enum(UnityEngine.Rendering.BlendMode)] _Blend ("Blend mode", Float) = 1
16     //setup corresponding shader keywords.
17     [KeywordEnum(Off, On)] _UseSpecular ("Use Specular",  Float) = 0
18     }
19 
20     // Shader
21     SubShader{
22         Pass{
23           //...
24           uniform float4 _Color;
25           //...
26           float4 frag() : COLOR{ return fixed4(_Color); }
27           //...
28              #pragma multi_compile __ _USESPECULAR_ON
29           }
30     }
31 
32     //fixed pipeline
33     SubShader    {
34         Pass{
35             Color[_Color]
36         }
37     }
38 }
  • Shader在Unity編輯器暴露給美術的參數,經過Properties來實現。
  • 全部可能的參數如上所示。主要也就Float、Vector和Texture這3類。
  • 除了經過編輯器編輯Properties,腳本也能夠經過Material的接口(好比SetFloatSetTexture編輯)
  • 以後在Shader程序經過[name](固定管線)或直接name(可編程Shader)訪問這些屬性。
  • 在每個Property前面也能相似C#那樣添加Attribute,以達到額外UI面板功能。詳見MaterialPropertyDrawer.html

Shader中的數據類型

有3種基本數值類型:floathalffixed
這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中各個Space的座標系

通常狀況下,從Vertex Buff輸入頂點到Vertex Shader,

  • 該頂點爲左手座標系Model Space中的頂點vInModel
    其用w=1的Homogenous Cooridniates(故等效於Cartesian Coordinates)表達vInModel = float4(xm, ym, zm, 1)
  • vInWrold = mul(_Object2World , vInModel)後,得出左手座標系World Space中的vInWorld,其爲w=1的Homogenous Cooridniates(故等效於Cartesian Coordinates)vInWorld = float4(xw, yw, zw, 1)
  • vInView = mul(UNITY_MATRIX_V , vInWrold)後,得出右手座標系View Space中的vInView,其爲w=1的Homogenous Cooridniates(故等效於Cartesian Coordinates)vInWorld = float4(xv, yv, zv, 1)
  • vInClip = mul(UNITY_MATRIX_P , vInView)後,得出左手座標系Clip Space中的vInClip,其爲w每每不等於1的Homogenous Cooridniates(故每每不等效於Cartesian Coordinates)vInClip = float4(xc, yc, zc, wc)
    設r、l、t、b、n、f的長度絕對值以下圖:

     

    注意View Space中攝像機前方的z值爲負數、-z爲正數。則GL/DX/Metal的Clip Space座標爲:
    • GL:
      • xc=(2nx+rz+lz)/(r-l);
      • yc=(2ny+tz+bz)/(t-b);
      • zc=(-fz-nz-2nf)/(f-n);
      • wc=-z;
    • DX/Metal:
      • xc=(2nx+rz+lz)/(r-l);
      • yc=(2ny+tz+bz)/(t-b);
      • zc=(-fz-nf)/(f-n);
      • wc=-z;
  • vInNDC = vInClip / vInClip.w後,得出左手座標系Normalized Device Coordinates中的vInNDC,其爲w=1的Homogenous Cooridniates(故等效於Cartesian Coordinates)vInNDC = float4(xn, yn, zn, 1)
    xnyn的取值範圍爲[-1,1]。
    • GL: zn=zc/wc=(fz+nz+2nf)/((f-n)z);
    • DX/Metal: zn=zc/wc=(fz+nf)/((f-n)z);
    • 在Unity中,zn的取值範圍能夠這樣決定:
      • 若是UNITY_REVERSED_Z已定義,zn的取值範圍是[UNITY_NEAR_CLIP_VALUE, 0],即[1,0]
      • 若是UNITY_REVERSED_Z未定義,zn的取值範圍是[UNITY_NEAR_CLIP_VALUE, 1]
        • 若是SHADER_API_D3D9/SHADER_API_D3D11_9X定義了,即[0,1]
        • 不然,即OpenGL狀況,即[-1,1]
 1 v2f vert (appdata v)
 2 {
 3     v2f o;
 4     o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
 5     // 1 、二、3是等價的,和4是不等價的
 6     // 由於是M在左、V在右,因此是Column Vector
 7     // 由於是HLSL/CG語言,因此是訪問方式是Row-Major
 8     o.rootInView = mul(UNITY_MATRIX_MV, float4(0, 0, 0, 1)); // 1
 9     o.rootInView = float4(UNITY_MATRIX_MV[0].w, UNITY_MATRIX_MV[1].w, UNITY_MATRIX_MV[2].w, 1); // 2                
10     o.rootInView = UNITY_MATRIX_MV._m03_m13_m23_m33;  // 3
11     //o.rootInView = UNITY_MATRIX_MV[3]; // 4
12 
13     return o;
14 }
15 
16 fixed4 frag (v2f i) : SV_Target
17 {
18     // 由於是ViewSpace是右手座標系,因此當root在view前面的時候,z是負數,因此須要-z才能正確顯示顏色
19     fixed4 col = fixed4(i.rootInView.x, i.rootInView.y, -i.rootInView.z, 1);
20     return col;
21 }
22 
23 struct appdata
24 {
25     float4 vertex : POSITION;
26 };
27 struct v2f
28 {
29     float4 rootInView : TEXCOORD0;
30     float4 vertex : SV_POSITION;
31 };

 

Shader形態

Shader形態之1:固定管線

固定管線是爲了兼容老式顯卡。都是頂點光照。以後固定管線多是被Unity拋棄的功能,因此最好不學它、當它不存在。特徵是裏面出現了形以下面Material塊、沒有CGPROGRAMENDCG塊。

 1 Shader "ShaderLab Tutorials/TestShader"
 2 {
 3     Properties {
 4     _Color ("My Color", Color) = (.34, .85, .92, 1) // color
 5     }
 6 
 7     // Fixed Pipeline
 8     SubShader
 9     {
10         Pass
11         {
12             Material{
13             Diffuse [_Color]
14             Ambient [_Color]
15             }
16 
17             Lighting On
18         }
19     }
20 }

Shader形態之2:可編程Shader

 1 Shader "ShaderLab Tutorials/TestShader"
 2 {
 3     Properties {}
 4 
 5     SubShader
 6     {
 7         Pass
 8         {
 9           // ... the usual pass state setup ...
10 
11           CGPROGRAM
12           // compilation directives for this snippet, e.g.:
13           #pragma vertex vert
14           #pragma fragment frag
15 
16           // the Cg/HLSL code itself
17           float4 vert(float4 v:POSITION) : SV_POSITION{
18               return mul(UNITY_MATRIX_MVP, v);
19           }
20           float4 frag() : COLOR{
21               return fixed4(1.0, 0.0, 0.0, 1.0);
22           }
23           ENDCG
24           // ... the rest of pass setup ...
25           }
26     }
27 }
  • 功能最強大、最自由的形態。
  • 特徵是在Pass裏出現CGPROGRAMENDCG
  • 編譯指令#pragma。詳見官網Cg snippets。其中重要的包括:
編譯指令 示例/含義
#pragma vertex name
#pragma fragment name
替換name,來指定Vertex Shader函數、Fragment Shader函數。
#pragma target name 替換name(爲2.03.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階段之間)的輸入輸出參數,經過語義字符串,來指定參數的含義。經常使用的語義包括:COLORSV_PositionTEXCOORD[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

 1 Shader "ShaderLab Tutorials/TestShader"
 2 {
 3     Properties {   }
 4 
 5     // Surface Shader
 6     SubShader {
 7       Tags { "RenderType" = "Opaque" }
 8       CGPROGRAM
 9       #pragma surface surf Lambert
10       struct Input {
11           float4 color : COLOR;
12       };
13       void surf (Input IN, inout SurfaceOutput o) {
14           o.Albedo = 1;
15       }
16       ENDCG
17     }
18     FallBack "Diffuse"
19 }
  • SurfaceShader能夠認爲是一個光照Shader的語法糖、一個光照VS/FS的生成器。減小了開發者寫重複代碼的須要。
  • 在手遊,因爲對性能要求比較高,因此不建議使用SurfaceShader。由於SurfaceShader是一個比較「通用」的功能,而通用每每致使性能不高。
  • 特徵是在SubShader裏出現CGPROGRAMENDCG塊。(而不是出如今Pass裏。由於SurfaceShader本身會編譯成多個Pass。)
  • 編譯指令是:
    #pragma surface surfaceFunction lightModel [optionalparams]
    • surfaceFunction:surfaceShader函數,形如void surf (Input IN, inout SurfaceOutput o)
    • lightModel:使用的光照模式。包括Lambert(漫反射)和BlinnPhong(鏡面反射)。
      • 也能夠本身定義光照函數。好比編譯指令爲#pragma surface surf MyCalc
  • 你定義輸入數據結構(好比上面的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結構很類似。

 1 // Compiled shader for iPhone, iPod Touch and iPad, uncompressed size: 36.5KB
 2 // Skipping shader variants that would not be included into build of current scene.
 3 Shader "ShaderLab Tutorials/TestShader"
 4 {
 5     Properties {...}
 6     SubShader {
 7         // Stats for Vertex shader:
 8         //        gles : 14 avg math (11..19), 1 avg texture (1..2)
 9         //       metal : 14 avg math (11..17)
10         // Stats for Fragment shader:
11         //       metal : 14 avg math (11..19), 1 avg texture (1..2)
12         Pass {
13             Program "vp" // vertex program
14             {
15                 SubProgram "gles" {
16                     // Stats: 11 math, 1 textures
17                     Keywords{...} // keywords for shader variants ("uber shader")
18 
19                     //shader codes in string
20                     "
21                     #ifdef VERTEX
22                     vertex shader codes
23                     #endif
24 
25                     // Note, on gles, fragment shader stays here inside Program "vp"
26                     #ifdef FRAGMENT
27                     fragment shader codes
28                     #endif
29                     " 
30                 }
31 
32                 SubProgram "metal"  {
33                     some setup
34                     Keywords{...}
35 
36                     //vertex shader codes in string
37                     "..."
38                 }
39             }
40 
41             Program "fp" // fragment program
42             {
43                 SubProgram "gles" {
44                     Keywords{...}
45                     "// shader disassembly not supported on gles" //(because gles fragment shader codes are in Program "vp") 
46                 }
47 
48                 SubProgram "metal" {
49                     common setup
50                     Keywords{...}
51 
52                     //fragment shader codes in string
53                     "..."
54                 }
55             }
56         }
57     }
58 
59     ...
60 }

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。

移動設備GPU架構簡述

《The Mali GPU: An Abstract Machine》系列以Arm Mali GPU爲例子給出了全面的討論,現簡述以下:

  • Part 1 - Frame Pipelining
    • Application/Geometry/Fragment三階段組成,三者中最大才是瓶頸
    • OpenGL的同步API是個「illusion」,事實上是CommandQueue(直到遇到Fence會被強制同步),以減小CPU/GPU之間的互相等待
    • Pipeline Throttle,爲了更低的延遲,當GPU累積了多幀(每每是3幀,以eglSwapBuffers()Present()來區分幀)的Command時,OS會經過eglSwapBuffers()Present()來阻塞CPU讓其進入idle,從而防止更多後續Command的提交
  • Part 2 - Tile-based Rendering
    • tile-based deferred rendering (WikiPowerVR/Mali/Adreno)是重要的概念。其將Fragment一幀處理多個好比16x16的單元,併爲Shader集成一個小但快的cache,從而大幅避免Shader和主內存之間帶寬消耗(電量消耗)
  • Part 3 - The Midgard Shader Core
    • GPU包含數個(當前常見爲4-8個)Unified Shading Core,可動態分配用於Vertex Shader、Fragment Shader或Compute Kernel
    • 每一個Unified Shader Core包含數個(當前常見爲2個)用於SIMD計算的運算器Arithmetic Pipeline(A-pipe),1個用於紋理採樣的Texutre Pipeline(T-pipe),1個用於非紋理類的內存讀寫的Load/Store Pipeline(LS-pipe)好比頂點屬性寫讀、變量訪問等
    • 會進行Early-ZS測試嘗試減小Overdraw(依賴於渲染物體提交順序由前至後)
    • Arm的Forward Pixel Kill和PowerVR的Hidden Surface Removal作到像素級別的Overdraw減小(不用依賴於渲染物體提交順序由前至後)
    • 當Shader使用discardclip、在Fragment Shader裏修改深度值、半透明,將不能進行Early-ZS,只好使用傳統的Late-ZS
  • Part 4 - The Bifrost Shader Core
    • 2016年的新型號,對架構做出了優化

參考資源

  • Youtube:https://www.youtube.com/watch?v=hDJQXzajiPg (包括part1-6)。視頻是最佳的入門方式沒有之一,因此牆裂建議就算不看下文的全部內容,都要去看一下part1。
  • 書籍:《Unity 3D ShaderLab開發實戰詳解》
  • Unity各類官方文檔
做者:DonaldW 連接:http://www.jianshu.com/p/7b9498e58659 來源:簡書 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。