Shader introductory tutorial (1)

I have been learning Unity for a while, and it is said that Unity needs to learn Shader programming to advance, so it took a while to learn Shader programming. After learning it, I found that Shader is not as complicated as I thought. After mastering its principle and syntax, we can also use shader to write the special effects we want. Well, let me introduce the introductory knowledge of shader in detail.

The contents I mainly introduce in this article are 
①Shader basic knowledge  
②Shader knowledge introduction in  
Unity ③Surface Shader syntax

Shader Basics

What is a Shader?

Before talking about what Shader is, let's take a look at the following two pieces of code 

write picture description here

The functions implemented by these two pieces of code are to extract the color value of each pixel on the 2D image. The first piece of code is written in C++ and runs on cup. It needs to loop through each pixel. The second piece of code is The CG code, running on the GPU, does the same thing with just one line of code. The GPU is specially used for graphics processing, and the Shader is a program executed by the GPU to operate on 3D objects.

The explanation of shader on Wikipedia is like this ( https://zh.wikipedia.org/wiki/%E7%9D%80%E8%89%B2%E5%99%A8 )

Shader is used in the field of computer graphics and refers to a set of instructions used by computer graphics resources when performing rendering tasks to calculate the color or shade of an image. But recently, it can also be used for some special effects, or video post-processing. In layman's terms, shaders tell the computer how to draw objects in a specific way.

Programmers apply shaders to the programmable pipeline of graphics processing units (GPUs) to implement 3D applications. Such graphics processors are different from traditional fixed-pipeline processors and bring greater flexibility and adaptability to GPU programming. The previously inherent pipeline can only do some geometric transformations and pixel grayscale calculations. Programmable pipelines now also process all pixel, vertex, texture position, hue, saturation, lightness, contrast and draw images in real-time. Shaders can also produce effects such as blur, specular, volumetric lights, out of focus, toon rendering, tone separation, distortion, bump mapping, edge detection, motion detection, and more.

OpenGL rendering process

Knowing what a shader is, let's take a look at the types of shaders. First, let me introduce the rendering process of OpenGL.

write picture description here

The above picture is the rendering process of OpenGL. I will not introduce what each step does in this article. If you are interested, you can take a look at this blog ( http://blog.csdn.net/lxdfigo/article/details /8457850 ), after simplifying this process is such 
vertex transformation → primitive assembly and rasterization → fragment texture mapping and shading → write frame buffer

In the two steps of vertex transformation and fragment coloring, we can program it and perform various operations, and we cannot program other parts. Our shader acts on the two parts of vertex transformation and fragment shading.

Types of shaders

Knowing where shaders work, we can now understand the types of shaders.

Shaders are generally divided into fixed rendering pipelines and programmable rendering pipelines according to pipeline classification . A fixed rendering pipeline is a pipeline with fixed functions, such as the refraction of light on the surface of an object, and the reflection algorithm is fixed and cannot be modified. We can only configure these functions, such as turning on or off the reflection effect, fogging effect, etc. Because the function of this pipeline is fixed, it is impossible to give more and more free control over the performance of object details in the program, and it is impossible to achieve more picture effects we want. Therefore, the current graphics cards are all programmable rendering pipelines, that is, those departments that we could not modify can now be modified by programming. After the degree of freedom is high, we can achieve more special effects that we want.

Shader development language

Knowing the types of shaders, I am talking about the development language of shaders

HLSL: Mainly used for Direct3D. Platform: windows.

GLSL: Mainly used for OpenGL. Platform: Mobile platform (iOS, Android), mac (only use when you target Mac OS X or OpenGL ES 2.0)

CG: Fully compatible with DirectX 9.0 and above and OpenGL. Runtime or precompiled into GPU assembly code. CG supports more platforms than HLSL and GLSL. Unity Shader uses CG/HLSL as the development language.

Introduction to Shader knowledge in Unity

Rendering process of shader on GPU

write picture description here

The first thing to enter the GPU operation is the Vertex Processor vertex processor. This part requires us to use the Vertex Shader vertex shader. The result of the vertex shader operation will be handed over to the Pixel Processor pixel processor, which is the fragment processor. In this part I You need to write a Pixel Shader pixel shader program for pixel processing. After this part is calculated, it outputs the color information that we can finally use on the screen. We call it the Frame Buffer frame buffer. The frame buffer stores the data that the computer sequentially displays.

Types of shaders in Unity

①Fixed function shader: It belongs to the fixed rendering pipeline Shader, which is basically used for the rollback of the advanced Shader when the old graphics card cannot be displayed. The ShaderLab language is used, and the syntax is similar to Microsoft's FX files or NVIDIA's CgFX.

②Vertex and Fragment Shader: The most powerful Shader type, which belongs to the programmable rendering pipeline. It uses CG/HLSL syntax.

③Surface Shader: The Shader type that Unity3d respects, uses Unity's prefabricated lighting model to perform lighting operations. Also CG/HLSL syntax is used.

Let's first understand the similarities and differences of these three shaders.

The same points: 
①All must start from a single root Shader 
②Properties parameter part, the function and syntax are exactly  the same
③The specific functions are all in SubShader (Subshader will run from top to bottom the first hardware can support)  ④SubShader
can be labeled⑤ 
Both can be rolled back 
⑥ can handle basic functions, such as light diffuse reflection (Diffuse) and specular reflection (Specular). However, Vertex and Fragment and Surface can implement advanced functions that cannot be achieved by the Fixed function, such as effects based on uv calculations and so on.

Differences 
①Fixed function shader and Vertex and Fragment Shader also have pass{} structure under subshader, but Surface Shader has already packaged the specific content in the lighting model, and cannot add pass{} 
②Fixed function shader There is no semicolon after each code of the fixed function shader" ;", but the V&F shader and Surface shader must add a semicolon ";" after each code. 
③The structure 
of the SunShader of the Fixed function shader with different core structures is:

Material{} 
……
SetTexture[_MainTex]{
    ……
}
  • 1
  • 2
  • 3
  • 4
  • 5

The core structure of Vertex and Fragment Shader is

CGPROGRAM
#pragma vertex vert
#pragma fragment frag   
……       
#include "UnityCG.cginc"
ENDCG
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

The core structure of Surface Shader is

CGPROGRAM
#pragma surface surf Lambert
……
ENDCG
  • 1
  • 2
  • 3
  • 4

It can be seen that the encoding implementation in the Subshader of these three shaders is different. The structure of these three shaders is as follows, and their differences are all in the SubShader. 

write picture description here

因为Unity推荐Surface Shader,所以文章直接分析Surface Shader的用法,其他两种shader就不做过多介绍了。

Surface Shader语法

在Unity的项目面板中直接创建一个Stander surface shader,默认生成的代码如下

Shader "Custom/DiffuseShader" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)       //设置一个默认的颜色值
        _MainTex ("Albedo (RGB)", 2D) = "white" {}  //默认的白色纹理
        _Glossiness ("Smoothness", Range(0,1)) = 0.5  //默认的光泽度
        _Metallic ("Metallic", Range(0,1)) = 0.0    //金属光泽度
    }
    SubShader {
        Tags { "RenderType"="Opaque"}
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0


        fixed4 _Color;
        sampler2D _MainTex;
        half _Glossiness;
        half _Metallic;


        struct Input {
            float2 uv_MainTex;
        };



        void surf (Input IN, inout SurfaceOutputStandard o) {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            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
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

接下来我来介绍一下这段代码

Properties {}

Properties{}是定义着色器属性的,在这里定义的属性将被作为输入提供给所有的子着色器。属性定义的格式如下

_Name(“Display Name”, type) = defaultValue[{options}]

_Name代表的是属性名,如Color,MainTex,Glossiness ,Metallic 等

”Display Name”则是在Inspector中显示的名字

type代表属性:

    Color - 一种颜色,由RGBA(红绿蓝和透明度)四个量来定义;
    2D - 一张2的阶数大小(256,512之类)的贴图。这张贴图将在采样后被转为对应基于模型UV的每个像素的颜色,最终被显示出来;
    Rect - 一个非2阶数大小的贴图;
    Cube - 即Cube map texture(立方体纹理),简单说就是6张有联系的2D贴图的组合,主要用来做反射效果(比如天空盒和动态反射),也会被转换为对应点的采样;
    Range(min, max) - 一个介于最小值和最大值之间的浮点数,一般用来当作调整Shader某些特性的参数(比如透明度渲染的截止值可以是从0至1的值等);
    Float - 任意一个浮点数;
    Vector - 一个四维数;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这段默认Properties在Inspector中的显示效果如下 

write picture description here

SubShader{}

Tags :tags标签是三种类型的shader都具有的标签,它决定了硬件什么调用该子着色器

Tags标签里面默认的“RenderType”=”Opaque”,是告诉系统应该在渲染非透明物体时调用这个SubShader
“RenderType”=”Transparent”表示在渲染含有透明效果的物体时调用该Sunshader,

Tags里面还有许多其他的我们可选的标签
①.”Queue”:定义渲染顺序。预制的值有这些 
    ”Background”。值为1000。比如用于天空盒。
    ”Geometry”。值为2000。大部分物体在这个队列。不透明的物体也在这里。
    ”AlphaTest”。值为2450。已进行AlphaTest的物体在这个队列。 
    ”Transparent”。值为3000。透明物体。 
    ”Overlay”。值为4000。比如镜头光晕。 
    用户可以定义任意值,比如”Queue”=”Geometry+10”
②“RenderType”:定义渲染类型。预制的值有这些
    ”Opaque”:绝大部分不透明的物体都使用这个; 
    ”Transparent”:绝大部分透明的物体、包括粒子特效都使用这个; 
    ”Background”:天空盒都使用这个; 
    ”Overlay”:GUI、镜头光晕都使用这个; 
③”ForceNoShadowCasting”:定义物体是否有阴影效果
    “true”。表示有阴影
    “false”。表示没有阴影
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

LOD:Level of Detail的缩写,它表示着色器的细节层次效果。在某些硬件比较差的系统上,我们可以设置一个低一点的值,减少细节的显示。Unity内置shader的LOD值如下

  • VertexLit kind of shaders = 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

CGPROGRAM 到ENDCG这一部分就这这个shader的核心内容了

#pragma surface surf Standard fullforwardshadows
  • 1

这段编译指令声明了我们要写一个Surface Shader,并指定了光照模型。它的写法是这样的

#pragma surface surfaceFunction lightModel [optionalparams]
  • 1
  • surface - 声明的是一个表面着色器
  • surfaceFunction - 着色器代码的方法的名字
  • lightModel - 使用的光照模型。

这段代码默认的surfaceFunction为surf,我们可以在源码的底部看到在这儿声明了的surf函数。默认的lightModel为Standard。

下面我先介绍一下lightModel光照模型

  • Lambert:该光照模型能很好的表示粗糙表面的光照,但不能表现出镜面反射高光

  • Toon:最近在游戏中常用的风格之一即是Toon shading(又称 cel shading).这是一种非逼真渲染风格,通过改变了光在一个模型上反射实际情况来给人以手绘的感觉

  • BlinnPhong:仿真镜面反射材料

  • Standard:Unity5中默认的光照模式是Standard, 其引入了 物理渲染 (PBR), 但是与其它光照模型没有什么不同。相比于朗伯反射, PBR提供了一个更加逼真的光线物体作用模型,PBR考虑了材料的物理属性, 比如能量守恒以及光的散射

接下来的这段代码

   fixed4 _Color;
   sampler2D _MainTex;
   half _Glossiness;
   half _Metallic;
  • 1
  • 2
  • 3
  • 4

我们可以发现 _Color,_MainTex,_Glossiness,_Metallic都shader属性的声明,在上面的Properties 中已经声明过了这些属性,但是在这段CG程序,要想访问在Properties中所定义的变量的话,必须使用和之前变量相同的名字再次进行声明,其实就是链接在上面properties中声明的属性。

我再来介绍一下shader中常用的数据类型

3 basic numeric types: float, half and fixed. 
These three basic numeric types can be reconstituted into vectors and matrices. For example, half3 is composed of 3 halfs, and float4x4 is composed of 16 floats.

float: 32-bit high precision floating point number. 
half: 16-bit medium precision floating point number. The range is [-60,000, +60,000], accurate to 3.3 decimal places. 
fixed: 11-bit low-precision floating point number. The range is [-2, 2] and the precision is 1/256. 
Sampler2D: 2D texture properties

Next is the Input structure

struct Input {
    float2 uv_MainTex;
};
  • 1
  • 2
  • 3

This structure is relative to another parameter inout structure in the surf function, one representing input and one representing output. We can understand these two structures in this way, you define the input data structure (Inputs Struct), write your own Surface function to process the input, and finally output the modified SurfaceOutput. Input is actually a structure that we need to define, so we can put all the data we need to participate in the calculation into this Input structure, and pass in the surf function to use

There is a uv_MainTex parameter in the default Input structure, which represents the UV value of the texture, and we can use this parameter directly in the surf function.

Knowing the structure of Input, let's take a look at the structure of Output

struct SurfaceOutput
{
    fixed3 Albedo;  // diffuse color  漫反射的颜色值。
    fixed3 Normal;  // tangent space normal, if written 法线坐标
    fixed3 Emission;  //自发光颜色
    half Specular;  // specular power in 0..1 range 镜面反射系数
    fixed Gloss;    // specular intensity   光泽系数
    fixed Alpha;    // alpha for transparencies  透明度系数
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Now let's take a look at the contents of the surf function, and we can already understand it.

Let's take a look at the code in the surf function now, and we can know what it means.

        void surf (Input IN, inout SurfaceOutputStandard o) {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;               //将物体显示的漫反射颜色设置成在纹理的颜色值
            o.Metallic = _Metallic;         //将物体显示的金属光泽设置成在properties中定义的光泽
            o.Smoothness = _Glossiness;     //设置物体显示的光滑度
            o.Alpha = c.a;                  //设置物体显示的透明度
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
Copyright statement: This article is an original article by the blogger and may not be reproduced without the blogger's permission. https://blog.csdn.net/tyuiof/article/details/52754300

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325824413&siteId=291194637