美文网首页822思享实验室
Shader基础笔记(1)-基本结构

Shader基础笔记(1)-基本结构

作者: 邱宏健 | 来源:发表于2018-03-03 21:24 被阅读7次

    新建Shader的分类

    1. Standard Surface Shader - 产生一个包含标准光照模型的表面着色器模板。
    2. Unlit Shader(推荐) - 产生一个不包含光照(但包含雾效)的基本顶点/片元着色器。
    3. Image Effect Shader - 为实现各种屏幕处理后效果提供的基本模板。
    4. Compute Shader - 特殊Shader,利用GPU的并行特性计算一些计算。
    • ShaderLab 是 Unity 提供的编写 Unity Shader 的一种说明性语言。在 Unity 中,所有的 Unity Shader 都是使用 ShaderLab 来编写的。

    Shader 的基本结构

    Shader "MyShader/Temp01"
    {
        Properties
        {
            _MainTex ("Texture", 2D) = "white" {}
        }
        
        SubShader
        {
            Tags { "RenderType"="Opaque" }
            LOD 100
            Pass
            {    
            CGPROGRAM
            
            ENDCG
            }
        }
    }
    

    Shader 基本结构说明

    1. 给Shader起个名字

    Shader "MyShader/Temp01"
    这一行代码设置了 Shader 在材质中出现的位置及名称:

    2. 属性

    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    

    声明这些属性是为了在材质面板中能够方便地调整各种材质属性。在 Unity 中,这些属性的名字通常由一个下划线开始。括号中的第一个参数,是属性显示在材质面板上的名字。第二个参数,是数据类型。

    下面的代码给出了一个展示所有属性类型的例子:

    Shader "MyShader/Temp01"
    {
       Properties
       {
           // Unmbers and Sliders
          _Int("Int", Int) = 2
          _Float("Float", Float) = 1.5
          _Range("Range", Range(0.0, 5.0)) = 3.0
          
          // Colors and Vectors
          _Color("Color", Color) = (1,1,1,1) 
          _Vector("Vector", Vector) = (2,3,6,1)
          
          // Textures
          _2D("2D", 2D) = ""{}
          _Cube("Cube", Cube) = "white"{}
          _3D("3D", 3D) = "black"{}
       }
       
       FallBack "Diffuse"
    }
    

    TIPS:编译器对 Shader 的支持普遍不好,其中比较好用的还是 JetBrans 公司的 Rider。

    3. SubShader

    每一个 Unity Shader 文件可以包含多个 SubShader 语义块,但至少一个。当 Unity 需要加载这个 Unity Shader 时, Unity 会扫描所有的SubShader 语义块,然后选择第一个能够在目标平台上运行的 SubShader。如果都不支持,Unity 会使用 Fallback 语义指定的 Unity Shader。

    每个Pass定义了一次完整的渲染流程,但如果Pass的数目过多,往往会造成渲染性能的下降。因此,应当尽量使用最小数目的Pass。

    SubShader 语义块中包含的定义通常如下:
    ···
    Subshader{
    // 标签,可选的
    [Tags]

    // 状态,可选的
    [RenderSetup]
    
    Pass{
    }
    // Other Passes
    

    }
    ···
    SubShader 内的具体内容放到以后再写。

    最简单的 Unity Shader

    尽管 Unity Shader 可以做的事情非常多(例如设置渲染状态等),但其最重要的任务还是指定各种着色器所需的代码。这些着色器代码可以写在 SubShader 语义块中(表面着色器的做法),也可以写在 Pass 语义块中(顶点/片元着色器和固定函数着色器的做法)。

    在 Unity 中,我们可以使用2种最常用的形式来编写 Unity Shader。

    1. 表面着色器(Surface Shader)

    表面着色器是 Unity 自己创造的一种着色器代码类型,它需要的代码量很少,Unity 在背后做了很多工作,但渲染的代价比较大。其本质与接下来的顶点/片元着色器一样,我们可以理解成 Unity 对顶点/片元着色器的更高一层的抽象。它存在的价值在于,Unity为我们处理了很多光照细节,使得我们不需要再操心这些“烦人的事情”。

    一个非常简单的例子:

    Shader "MyShader/Temp01"
    {  
       Subshader{
           Tags { "RenderType" = "Opaque" }
           CGPROGRAM
           #pragma surface surf Lambert
           struct Input{
               float4 clolr : COLOR;
           };
           void surf (Input IN, inout SurfaceOutput o){
               o.Albedo = 1;
           }
           ENDCG
       }
       
       FallBack "Diffuse"
    }
    

    可见,表面着色器被定义在 SubShader 语义块(而非Pass语义块)中的 CGPROGRAM 和 ENDCG 之间。原因是:表面着色器不需要开发者关心使用多少个 Pass、每个 Pass 如何渲染等问题,Unity 会在背后为我们做好这些事情。我们要做的只是告诉它:“嘿,使用这些纹理去填颜色,使用这个法线纹理去填充法线,使用Lambert光照模型,其他的不要来烦我!”

    2. 顶点/片元着色器(Vertex/Fragment Shader)

    顶点/片元着色器更加复杂,但也更加灵活。

    一个非常简单的例子:

    Shader "MyShader/Temp01"
    {  
       Subshader{     
           Pass{
               CGPROGRAM
               #pragma vertex vertex
               #pragma fragment fra
               
               float4 vert(float4 v : POSITION) : SV_POSITION {
                   return UnityObjectToClipPos (v);
               }
               
               fixed4 frag() : SV_Target {
                   return fixed4(1.0, 0.0, 0.0, 1.0);
               }
               ENDCG
           }
       }
    }
    

    我们将主要使用顶点/片元着色器。

    扩展阅读

    Unity官网的 Unity Shader 文档:官方文档

    相关文章

      网友评论

        本文标题:Shader基础笔记(1)-基本结构

        本文链接:https://www.haomeiwen.com/subject/znexfftx.html