Summary and basic knowledge of writing Shader

Why Bothers?

Why is there already a visual Shader editor like ShaderForge ? Why does the Asset Store already have so many cool Shader components for download? Is it still necessary to learn how to write Shader?


2014-0718-1607-11-33.png
  • Because the above Shader tools/components ultimately exist in the form of Shader files.
  • Developers/technical artists need to be able to perform functional analysis, efficiency evaluation, selection, optimization, compatibility, and even debugging of Shader.
  • For special needs, it may be more practical and efficient to write Shader directly.

In short, Shader writing is important; but whether it is urgent or not depends on the needs of the project.

Scope involved

This article only discusses the knowledge and usage of Unity ShaderLab. but,

  • The basic concepts related to rendering are not discussed. For basic concepts, please refer to articles such as Rendering Pipeline Overview .
  • Nor does it discuss specific rendering techniques.
  • There are many differences in the hardware architecture of mobile device GPUs and desktop device GPUs. For details, see the "Mobile Device GPU Architecture Brief Overview" chapter below.

Use Shader


2014-0720-1007-25-36.png


As shown in the picture above, it can be summarized in one sentence:

  1. There is MeshRenderer in GameObject,
  2. There is a Material list in MeshRenderer,
  3. There is only one Shader in each Material;
  4. Material exposes the Shader's adjustable properties in the editor.

So the key is how to write Shader.

Shader basics

editor

It is actually satisfying to use MonoDevelop, an anti-human IDE, to write Shader. There is syntax highlighting, but no syntax hints.
If you are used to Visual Studio, you can implement syntax highlighting of .Shader files as follows.

  • Download the keyword file usertype.dat added by the author donaldwu himself . It includes some keywords of Unity ShaderLab and all keywords of HLSL. Keywords will be added in the future.
  • Place the downloaded usertype.dat in the Microsoft Visual Studio xx.x\CommonX\IDE\ folder;
  • Open VS, Tools>Options>Text Editor>File extension, fill in "shader" in the extension, select VC++ as the editor, and click Add;
  • Restart VS, Done.

Shader

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

2014-0720-1707-17-42.png


The name of the shader will directly determine the path where the shader appears in the material.

SubShader

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

A Shader has multiple SubShaders. A SubShader can be understood as a rendering scheme of a Shader . That is, SubShader is written for different rendering situations. Each Shader has at least one SubShader, and theoretically there can be an infinite number, but two or three are often enough.
Only one SubShader will be selected for rendering at a time. The specific SubShader selection rules include:

  • Select from top to bottom
  • SubShader label, Pass label
    • Whether it conforms to the current "Unity rendering path"
    • Whether it matches the current ReplacementTag
  • Is SubShader compatible with the current GPU?
  • wait

The first SubShader selected according to this rule will be used for rendering, and the unselected SubShader will be ignored for this rendering.

SubShaderTag

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

SubShader can have tags (Tags) defined inside it. Tag specifies the rendering order (timing) of this SubShader, as well as some other settings.

  • "RenderType"Label. Unity can replace all Shaders that match a specific RenderType at runtime. Camera.RenderWithShaderor Camera.SetReplacementShaderused together. Unity's built-in RenderType includes:
    • "Opaque": Most opaque objects use this;
    • "Transparent": Most transparent objects, including particle effects, use this;
    • "Background": All skyboxes use this;
    • "Overlay": Both GUI and lens flare use this;
    • RenderTypeUsers can also define any value for this tag of their own .
    • It should be noted that Camera.RenderWithShaderthe or Camera.SetReplacementShadernot required label can only be RenderTypea RenderTypelabel internally used for Replace in Unity. You can also customize your own brand-new label for Replace.
      For example, you add Tag to your ShaderA.SubShaderA1 (the SubShader that will be selected by Unity, often the first SubShader in the Shader file), and "Distort"="On"then pass it "Distort"as a parameter replacementTagto the function. At this time, replacementShaderif there is an identical ShaderB.SubShaderB1 as the actual parameter "Distort"="On", then this SubShaderB1 will replace SubShaderA1 for this rendering.
    • For details, please refer to Rendering with Replaced Shaders
  • "Queue"Label. Define the rendering order. The prefabricated value is
    • "Background". The value is 1000. For example, used for skyboxes.
    • "Geometry". The value is 2000. Most objects are in this queue. Opaque objects are here too. The rendering order of objects within this queue will be further optimized (it should be from near to far, and the early-z test can eliminate fragments that do not need to be processed by FS). Objects in other queues are rendered according to their spatial position from far to near.
    • "AlphaTest". The value is 2450. Objects that have been AlphaTested are in this queue.
    • "Transparent". The value is 3000. Transparent objects.
    • "Overlay". The value is 4000. Such as lens flare.
    • The user can define any value, such as"Queue"="Geometry+10"
  • "ForceNoShadowCasting", "true"when the value is , it means that shadows are not accepted.
  • "IgnoreProjector", "true"when the value is , it means that the projection of the Projector component is not accepted.

In addition, the unofficial experience summary about rendering queues and batches is that the generation of a frame's rendering queue is determined by each rendering object in turn:

  • Shader and RenderType tag,
  • Renderer.SortingLayerID,
  • Renderer.SortingOrder,
  • Material.renderQueue (default value is "Queue" in Shader),
  • Transform.z(ViewSpace) (the default is from front to back according to the z value, but when the Queue is "Transparent", it is from back to front according to the z value).

After the rendering queue is determined (maybe there is a dirty flag mechanism?) the renderer traverses the rendering queue in turn, and the rendering objects of the "same" material are combined into one Batch.

Pass

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

A SubShader (rendering scheme) is executed by Pass blocks. Each Pass consumes a corresponding DrawCall. Reduce the number of passes as much as possible while satisfying the rendering effect.

Pass Tag

Shader "ShaderLab Tutorials/TestShader" {
    SubShader {
        Pass
        {
            Tags{ "LightMode"="ForwardBase" }
            //...
        }
    }
}

Similar to SubShader which has its own exclusive tag, Pass also has its own exclusive Tag.
The most important tag is "LightMode"to specify which rendering path ("Rendering Path") of Pass and Unity to use together. In addition to the most important ones ForwardBase, ForwardAddthe Tag values ​​that require additional reminders here may include:

  • Always, always renders but does not handle lighting
  • ShadowCaster, used to render objects that produce shadows
  • ShadowCollector, used to collect object shadows into the screen coordinate Buff.

For details about tags related to other rendering paths, see the following chapter "Unity Rendering Path Types".
For specific values ​​of all Tags, please refer to ShaderLab syntax: Pass Tags .

FallBack

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

    FallBack "Diffuse" // "Diffuse"即Unity预制的固有Shader
    // FallBack Off //将关闭FallBack
}

When all SubShaders of this Shader do not support the current graphics card, another Shader specified by the FallBack statement will be used. It is best to specify Unity's own pre-made Shader implementation for FallBack, as it can generally run on all current graphics cards.

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]
        }
    }
}
  • The parameters that Shader exposes to art in the Unity editor are implemented through Properties.
  • All possible parameters are shown above. There are mainly three categories: Float, Vector and Texture.
  • In addition to editing Properties through the editor, scripts can also be edited through Materialthe interface (for example SetFloat, SetTextureediting)
  • These properties are then accessed in the Shader program through [name](fixed pipeline) or directly name(programmable Shader).
  • Attribute can also be added in front of each Property similar to C# to achieve additional UI panel functions. See MaterialPropertyDrawer.html for details .

Data types in Shader

There are 3 basic numeric types: float, halfand fixed.
These three basic numerical types can be further composed into vector and matrix, for example, they are composed of half33 and 16 .halffloat4x4float

  • float: 32-bit high-precision floating point number.
  • half: 16-bit medium-precision floating point number. The range is [-60,000, +60,000], which can be accurate to 3.3 decimal places after the decimal point.
  • fixed: 11-bit low-precision floating point number. The range is [-2, 2] and the precision is 1/256.
Data type affects performance
  • As long as the accuracy is sufficient.
    • Color and unit vectors, usefixed
    • In other cases, try to use it half(that is, the range is within [-60,000, +60,000], accurate to 3.3 decimal places); otherwise, use it float.

Matrix in ShaderLab

When referring to "Row-Major" and "Column-Major", they may mean different things depending on the situation:

  • Mathematically, it mainly refers to whether the vector V is a Row Vector or a Column Vector. Quoted from [Game Engine Architecture 2nd Edition, 183]. Pay attention to the multiplication of V and M. When it is a Row Vector, it is written as VM in mathematics, and the Matrix is ​​on the right. The bottom row of the Matrix represents Translate; when it is a Column Vector, it is written as MtVt in mathematics, and the Matrix is ​​on the left and needs to be translated. Set, the rightmost column of the Matrix represents Translate.
  • On the access interface: Row-Major is MyMatrix[Row][Column], Column-Major is MyMatrix[Column][Row]. The access interface of HLSL / CG is Row-Major, for example, MyMatrix[3] returns the 3rd row; the access interface of GLSL is Column-Major, for example, MyMatrix[3] returns the 3rd column.
  • Register storage: whether each element is stored in the register in rows or columns. An example of a general situation where you need to pay attention to it is whether the MyMatrix of float2x3 occupies 2 registers (Row-Major) or 3 registers (Column-Major). In HLSL, row_major or column_major can be set through #pragmapack_matrix.

The above situations are irrelevant to each other.
Then, in ShaderLab, it is Column Vector in terms of mathematics, Row-Major in terms of access interface, and (not yet identified) in terms of storage.

The coordinate system of each Space in ShaderLab

Generally, input vertices from Vertex Buff to Vertex Shader,

  • This vertex is a vertex in the left-handed coordinate system Model Space vInModel,
    which is expressed by Homogenous Cooridniates with w=1 (so equivalent to Cartesian Coordinates) vInModel = float4(xm, ym, zm, 1);
  • vInWrold = mul(_Object2World , vInModel)Finally, it is obtained that in the left-hand coordinate system World Space vInWorld, it is Homogenous Cooridniates with w=1 (so it is equivalent to Cartesian Coordinates) vInWorld = float4(xw, yw, zw, 1);
  • vInView = mul(UNITY_MATRIX_V , vInWrold)Finally, it is obtained that in the right-hand coordinate systemvInView View Space , it is Homogenous Cooridniates with w=1 (so it is equivalent to Cartesian Coordinates) vInWorld = float4(xv, yv, zv, 1);
  • vInClip = mul(UNITY_MATRIX_P , vInView)Finally, it is obtained that in the left-hand coordinate system Clip Space vInClip, it is Homogenous Cooridniates whose w is often not equal to 1 (so it is often not equivalent to Cartesian Coordinates) vInClip = float4(xc, yc, zc, wc);
    let the absolute values ​​of the lengths of r, l, t, b, n, f be as follows picture:


    Note that the z value in front of the camera in View Space is a negative number and -z is a positive number. Then the Clip Space coordinates of GL/DX/Metal are:
    • 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.wFinally, it is obtained that in the left-hand coordinate system Normalized Device Coordinates vInNDC, it is the Homogenous Cooridniates with w=1 (so it is equivalent to Cartesian Coordinates) vInNDC = float4(xn, yn, zn, 1).
    xnThe value range of sum ynis [-1,1].
    • GL: zn=zc/wc=(fz+nz+2nf)/((f-n)z);
    • DX/Metal: zn=zc/wc=(fz+nf)/((f-n)z);
    • In Unity, znthe value range can be determined like this:
      • If UNITY_REVERSED_Zdefined, znthe value range is [ UNITY_NEAR_CLIP_VALUE, 0], that is, [1,0]
      • If UNITY_REVERSED_Zundefined, znthe value range is [ UNITY_NEAR_CLIP_VALUE, 1]
        • If SHADER_API_D3D9/ SHADER_API_D3D11_9Xis defined, that is [0,1]
        • Otherwise, that is the OpenGL case, which is [-1,1]
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 form

Shader form 1: Fixed pipeline

The fixed pipeline is for compatibility with older graphics cards. They are all vertex lighting. In the future, the fixed pipeline may be a feature abandoned by Unity, so it is best not to learn it and treat it as if it does not exist. The characteristic is that there are blocks in the form of lower Materialblocks, no blocks CGPROGRAM, and ENDCGblocks.

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 form 2: Programmable 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 ...
          }
    }
}
  • The most powerful and free form.
  • CGPROGRAMThe characteristic is that the sum ENDCGblock appears in the Pass
  • Compilation directives #pragma. See the official website Cg snippets for details . Important ones include:
Compilation directives Example/Meaning
#pragma vertex name
#pragma fragment name
Replace name to specify the Vertex Shader function and Fragment Shader function.
#pragma target name Replace name (for 2.0, 3.0etc.). Set the version of the compilation target shader model.
#pragma only_renderers name name ...
#pragma exclude_renderers name name...
#pragma only_renderers gles gles3,
#pragma exclude_renderers d3d9 d3d11 opengl,
only compiled for the specified rendering platform (render platform)
  • Reference library. #include "UnityCG.cginc"Import the specified library through the form . UnityCG.cgincThat’s the commonly used one . For details about other libraries, see the official website Built-in shader include files .
  • ShaderLab built-in value. Unity provides convenient and commonly used values ​​for the Shader program. For example, the following example UNITY_MATRIX_MVPrepresents the MVP matrix at this moment. For details, see the official website ShaderLab built-in values .
  • Shader input and output parameter semantics (Semantics). The input and output parameters between each stage in the pipeline process (such as between the Vertex Shader stage and the FragmentShader stage) specify the meaning of the parameters through semantic strings. Commonly used semantics include: COLOR, SV_Position, TEXCOORD[n]. The complete parameter semantics can be found in HLSL Semantic (because it is an HLSL connection, it may not be completely available in Unity).
  • In particular, because the input of Vertex Shader is often the beginning of the pipeline, Unity has built-in commonly used data structures for this purpose:
data structure meaning
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 form 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 can be thought of as syntax sugar for a lighting Shader and a generator of lighting VS/FS . Reduces the need for developers to write duplicate code.
  • In mobile games, due to the relatively high performance requirements, it is not recommended to use SurfaceShader . Because SurfaceShader is a relatively "universal" function, and universality often leads to low performance.
  • CGPROGRAMThe characteristic is that the sum block appears in the SubShader ENDCG. (Instead of appearing in Pass. Because SurfaceShader itself will compile into multiple Passes.)
  • The compilation instructions are:
    #pragma surface surfaceFunction lightModel [optionalparams]
    • surfaceFunction: surfaceShader function, in the formvoid surf (Input IN, inout SurfaceOutput o)
    • lightModel: The lighting mode used. Including Lambert(diffuse reflection) and BlinnPhong(specular reflection).
      • You can also define your own lighting function. For example, the compilation instruction is#pragma surface surf MyCalc
  • You define the input data structure (such as the one above Input), write your own Surface function to process the input, and finally output the modified SurfaceOutput. SurfaceOutput is defined as
    struct SurfaceOutput {
      half3 Albedo; // 纹理颜色值(r, g, b)
      half3 Normal; // 法向量(x, y, z)
      half3 Emission; // 自发光颜色值(r, g, b)
      half Specular; // 镜面反射度
      half Gloss; // 光泽度
      half Alpha; // 不透明度
    };

Shader form 4: Compiled Shader

Click a.shader"Compile and show code" of the file, you can see the "compiled" ShaderLab shader file of the file, the file name is in the form Compiled-a.shader.
It is still a ShaderLab file, which contains the shader code string that is finally submitted to the GPU.
First, let’s briefly describe its structure as follows. You will find that it is very similar to the above-mentioned pre-compilation ShaderLab structure.

// 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 (Rendering Path) type

Overview

Developers can choose 1 of 3 rendering paths in the PlayerSettings of the Unity project:

  • Deferred Lighting , delayed lighting path. Restore lighting and shadows with the highest quality among the three. Lighting performance is only related to the final number of pixels, and more light sources will not affect performance.
  • Forward Rendering , sequential rendering path. A rendering path that can take advantage of all the features of Shader, and of course supports pixel-level lighting. It is the most commonly used and has the most free functions. Its performance is related to the number of light sources * the number of illuminated objects. The specific performance depends on the complexity of the Shader used.
  • Vertex Lit , vertex lighting path. Vertex level lighting. It has the highest performance, the most compatibility, the fewest supported features, and the worst quality.

The inner stage of the render path and the Pass's LightMode tag

Each rendering path is internally divided into several stages.
Then, each Pass in the Shader can be assigned to a different LightMode. LightMode actually says: "I want this Pass to be executed in the YYY sub-stage of this XXX rendering path."

Deferred Lifting
Render path internal substages Corresponding LightMode describe
Base Pass "PrepassBase" Render object information. That is, the normal vector and highlight are transferred to an ARGB32 object information texture , and the depth information is saved in the Z-Buff.
Lighting Pass No corresponding programmable pass Based on the object information obtained from the Base Pass, in the screen coordinate system, use the BlinnPhong lighting mode to render the lighting information onto the ARGB32 lighting information texture (RGB represents diffuse color value, A represents highlight)
Final Pass "PrepassFinal" According to the lighting information texture , the object is rendered again, and the lighting information, texture information and self-illumination information are finally mixed. LightMap is also performed in this Pass.
Forward Rendering
Render path internal substages Corresponding LightMode describe
Base Pass "ForwardBase" Rendering: the brightest directional light source (pixel level) and corresponding shadows, all vertex-level light sources, LightMap, all LightProbe SH light sources (Sphere Harmonic, spherical harmonic function, ultra-high-efficiency low-frequency light), ambient light, auto glow.
Additional Passes "ForwardAdd" Other light sources that require pixel-level rendering

Note that in Forward Rendering, the light source may be a pixel-level light source, a vertex-level light source, or a SH light source. The judgment criteria are:

  • The light sources configured as "Not Important" are both vertex-level light sources and SH light sources.
  • The brightest directional light is always a pixel-level light source
  • Those configured as "Important" are all pixel-level light sources.
  • If the combined number of pixel-level light sources in the above two situations is less than the "Pixel Light Count" in "Quality Settings" , the light source in the first situation will be supplemented as an additional pixel-level light source.

In addition, light sources configured as "Auto" have more complex judgment annotations. The screenshot is as follows:


2014-0720-1607-31-40.png


For details, please refer to Forward Rendering Path Details .

Vertex Lit
Render path internal substages Corresponding LightMode describe
Vertex "Vertex" Rendering objects without LightMap
VertexLMRGBM "VertexLMRGBM" Rendering a LightMap object with RGBM encoding
VertexLM "VertexLM" Rendering LightMap objects with dual LDR encoding

Passes of different LightMode are selected

The rendering path of a project is unique, but the Shader in a project allows Passes with different LightMode.
In Unity, the strategy is "starting from the rendering path mode configured in the project, and searching for a Pass that best matches the LightMode in the order of Deferred, Forward, and VertxLit."
For example, when configuring a Deferred path, the Pass with Deferred-related LightMode will be selected first; if it cannot be found, the Forward-related Pass will be selected; if it cannot be found, the VertexLit-related Pass will be selected.
For another example, when configuring the Forward path, the Forward-related Pass will be selected first; if it cannot be found, the VertexLit-related Pass will be selected.

Brief description of mobile device GPU architecture

The "The Mali GPU: An Abstract Machine" series provides a comprehensive discussion using Arm Mali GPU as an example, which is briefly described as follows:

  • Part 1 - Frame Pipelining
    • It consists of three stages: Application/Geometry/Fragment. The biggest of the three is the bottleneck.
    • OpenGL's synchronization API is an "illusion". It is actually a CommandQueue (it will be forced to synchronize until it encounters a Fence) to reduce the mutual waiting between the CPU/GPU.
    • Pipeline Throttle, for lower latency, when the GPU accumulates multiple frames (often 3 frames, or eglSwapBuffers()to Present()distinguish frames) of Commands, the OS will block the CPU through eglSwapBuffers()or Present()to let it enter idle, thereby preventing more subsequent Commands. submit
  • Part 2 - Tile-based Rendering
    • Tile-based deferred rendering ( Wiki , PowerVR / Mali / Adreno ) is an important concept. It processes multiple Fragment units, such as 16x16, in one frame, and integrates a small but fast cache for the Shader, thus greatly avoiding bandwidth consumption (power consumption) between the Shader and the main memory.
  • Part 3 - The Midgard Shader Core
    • The GPU contains several (currently 4-8 are common) Unified Shading Cores, which can be dynamically allocated for Vertex Shader, Fragment Shader or Compute Kernel
    • Each Unified Shader Core contains several (currently 2 are common) Arithmetic Pipelines (A-pipe) for SIMD calculations, 1 Texutre Pipeline (T-pipe) for texture sampling, and 1 for non- Load/Store Pipeline (LS-pipe) for memory reading and writing of texture classes, such as vertex attribute writing and reading, variable access, etc.
    • Early-ZS testing will be conducted to try to reduce Overdraw (depending on the rendering object submission order from front to back)
    • Arm's Forward Pixel Kill and PowerVR's Hidden Surface Removal achieve pixel-level Overdraw reduction (without relying on the rendering object submission order from front to back)
    • When the Shader uses discardor clipmodifies the depth value or translucency in the Fragment Shader, Early-ZS will not be possible and traditional Late-ZS will have to be used.
  • Part 4 - The Bifrost Shader Core
    • The new model in 2016 has optimized the structure

Reference resources

  • Youtube: https://www.youtube.com/watch?v=hDJQXzajiPg (including part1-6). Video is one of the best ways to get started, so I suggest you watch part 1 even if you don’t read all the content below.
  • Book: "Detailed Practical Explanation of Unity 3D ShaderLab Development"
  • Unity various official documents


Author: DonaldW
Link: http://www.jianshu.com/p/7b9498e58659
Source: The copyright of Jianshu
belongs to the author. For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.

Guess you like

Origin blog.csdn.net/qq_25189313/article/details/78031678