Koo叔说Shader-Unity中的Shader

本文介绍了Unity的ShaderLab系统,讲解了ShaderLab的基本结构、属性、SubShader以及三种Shader写法。ShaderLab用于调用CG/HLSL/GLSL接口,通过Properties暴露参数到材质球。SubShader由多个Pass组成,按顺序执行。Unity推荐使用Surface Shader,但更自由的Vertex and Fragment Shader在需要更多定制时更为适用。

前言

Unity有自己的一套Shader系统,叫ShaderLab,今天主要说一下ShaderLab的语法和Unity中的几种不同种类的Shader的区别及使用场景,并分别做一些例子说明。

什么是ShaderLab

ShaderLab 是Unity3d自己封装的一个调用CG/HLSL/GLSL的接口,如果熟悉CG/HLSL/GLSL中的一种,理解起来会比较容易一些。

ShaderLab语法

首先,看一下ShaderLab的基本结构如下:

Shader "MyShader"{
   Properties{
        _MyTexture("My Texture",2D) = "white"{}
        //other properties like colors or vectors go here as well
   }
   SubShader{
       //here goes the 'meat' of your
       //- sureface shader or
       //- vertex and program shader or
       //- fixed function shader
   }
   SubShader{
       //here goes a simpler version of the SubShader
       //above than can run on older graphics cards
   }
}

上面代码可以看到,ShaderLab主要由Shader名字,属性和SubShader组成。

抽象语法可以表示成:

Shader "name" {[Properties] Subshaders [Fallback] [CustomEditor]}
Shader “name”{}:

Shader关键字加Shader名称,类似声明类class name{},Shader的名字一般是”xx/xx”,类似命名空间,这样可以避免重名。

Properties

ShaderLab的属性并不是必须的,属性主要用于暴露一些参数显示到材质(Material)球上,可以方便的调整效果,而不必每次都改代码。

属性的格式及支持的类型如下:
- 数字和范围滑条

name(“display name”,Range(min,max))=number

name(“display name”,Float) = number

name(“display name”,Int) = number
- 颜色和向量

name(“display name”,Color) = (number,number,number,number)

name(“display name”,Vector) = (number,number,number,number)
- 贴图

name(“display name”,2D) = “defaulttexture”{}

name(“display name”,Cube)= “defaulttexture”{}

name(“display name”,3D) = “defaulttexture”{}

其中name是属性的名字,在SubShader中会用到,display name是显示在material的inspector中,后面的类型定义,即是类型的修饰,又会在inspector中显示不同的控件(如Range显示滑条,Color显示颜色选择框等),赋值语句之后是默认值。

SubShader

在Unity中每个Shader都由一个或多个subshader组成。语法格式如下:

Subshader{[Tags][CommonState]Passdef[Passdef ..]}
- Tags:主要作用是告诉渲染引擎什么时候渲染和怎么样渲染

具体语法为:Tags{"TagName1" = "Value1" "TabName2"="Value2"}
1. Queue tag: Queue标签决定对象的渲染顺序。有Background(1000),Geometry(2000),AlphaTest(2450),Transparent(3000),Overlay(4000)等预定义的渲染顺序,也可以自己定义(其实就是数值,数值越大,渲染越靠后)
2. RenderType tag:RenderType tag将shader分类到几个预先定义的组,如不透明shader,alpha test shader等,一般用于Shader替换或产生相机深度纹理.稍后再详细解释。
3. DisableBatching Tag:这个标签主要用于禁用Batching,因为当Draw Call Batching后,所有对象都变换到了世界空间,而失去了模型空间信息,有”True”(禁用),”False”(不禁用,默认是这个),”LODFading”(当LOD fading激活,禁用,主要用于树)
4. ForceNoShadowCasting tag:如果为”True”,则使用此subshader渲染将不接收阴影,当在透明对象上使用shader replacement时可以避免从其它的subshader继承阴影。
5. IgnoreProjector Tag:如果为”True”,则物体不受投影影响,主要用于半透明的物体。
6. CanUseSpriteAtlasTag:如果为”False”,则sprite atlas不能使用。
7. PreviewType tag:主要影响material在inspector的显示,默认为球形,可以设置成”Plane”或”Skybox”
- CommonState:主要是设置硬件开关的各种状态。根据渲染管线,设置硬件状态,对渲染的各阶段进行控制。
1. Color,Material,Lighting:

Color color

Material {Material Block}

Lighting On|Off

SeparateSpecular On|Off

ColorMaterial AmbientAndDiffuse|Emission
2. Culling&Depth Testing:

Cull Back|Front|Off

ZWrite On|Off

ZTest Less|Greater|LEqual|GEqual|Equal|NotEqual|Always
3. Texture Combiners:

SetTexture[TextureName]{Texture Block}

SetTexture[_MainTex]{Combine
previous*texture,previous+texture}
4. Fog:

Fog {Fog Commands}

Mode Off|Global|Linear|Exp|Exp2

Color ColorValue

Density FloatValue

Range FloatValue,FloatValue
5. Alpha testing:

AlphaTest Off

AlphaTest comparison AlphaValue
6. Blending:

Blend SrcAlpha OneMinusSrcAlpha //Alpha blending

Blend One One //Additive

Blend OneMinusDstColor One//Soft Additive

Blend DstColor Zero//Multiplicative

Blend DstColor SrcColor//2x Multiplicative

image
- Passdef:定义渲染通道,一个subShader可以有多个pass,由于pass会产生drawcall, 一般都会用一个pass,但有一些效果可能需要多个pass配合实现。分为regular Pass,Use Pass,和Grab Pass
1. Regular Pass:语法
Pass{[Name and Tags][RenderSetup]}
Name就是指定Pass的名字 Tags和SubShader的Tags

RenderSetup是设置显卡状态
2. UsePass:引用其它Shader中的Pass名字
UsePass "Shader/Name"
3. GrabPass:抓取当前屏幕内容绘制到texture中,用于其它的pass,GrabPass{}GrabPass{"TextureName"}

Fallback

如果没有subShader可以在当前显卡运行,则尝试调用其它shader

Fallback "name"Fallback Off

CustomEditor

CustomEditor "name"
定义CustomEditor后,Unity会去找类名是CustomeEditor指定的,并继承ShaderGUI的类。如Unity自带的 Standard.shader 就是用了CustomEditor

Shader的三种写法

Unity中Shader分为surface shaders,vertex and fragment shaders或fxied function shaders
- Surface Shader:表面着色器,Unity中推荐使用的一种写法,Unity默认创建的就是Surface Shader,Surface Shader自身会编译为多个通道,不能添加Pass通道。如果需要受到光线和阴影影响,Surface Shader是最好的选择。如果不需对光线处理,不要用这个,因为会生成更多的代码。有点大材小用的感觉。
例子:

Shader "Example/Diffuse Texture"{
    Properties{
        _MainTex("Texture",2D) = "white"{}
    }
    SubShader{
        Tags{"RenderType" = "Opaque"}
        CGPROGRAM
        #pragma surface surf Lambert
        struct Input{
            float2 uv_MainTex;
        };
        sampler2D _MainTex;
        void surf(Input IN,inout SurfaceOutput o){
            o.Albedo = tex2D(_MainTex,IN.uv_MainTex).rgb;
        }
        ENDCG
    }
}
  • vertex and fragment shader:顶点和片段着色器,功能最强大,最自由的形态,自己编写的代码会多,在Pass里放CGPROGRAM和ENDCG块。
    例子:
Shader "Custom/Simple"{
    Properties{
        _Color("BaseColor",Color) = (1,1,1,1)
        _MainTex("Base(RGB)",2D) = "white"{}
    }
    SubShader{
        tags{"Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "True"}
        Blend SrcAlpha OneMinusSrcAlpha
        Pass{
            Name "Simple"
            Cull off
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            float4 _Color;
            sampler2D _MainTex;
            struct v2f{
                float4 post:POSITION;
                float4 uv:TEXCOORD0;
            };
            v2f vert(appdata_base v){
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                o.uv = v.texcoord;
                return o;
            }
            half4 frag(v2f i):COLOR{
                float2 uv = i.uv.xy;
                half4 = tex2D(_MainTex.uv)*_Color;
                return c;
            }
            ENDCG
        }
    }
}
  • fixed function shader:固定功能着色器,写法简单,功能少,Unity官方不建议用这个写法。除非是用于比较古老的硬件,其它Shader功能不支持时才考虑用fixed function.例子:
Shader "ShaderLab/TestShader"{
    Properties{
        _Color("My Color",Color)= (.34,.85,.92,1)
    }
    SubShader{
        Pass{
            Material{
                Diffuse[_Color]
                Ambient[_Color]
            }
            Lighting On
        }
    }
}

Shader相关文件(扩展名):

  • shader: 着色器的主要文件
  • cg/cginc: 着色器的公用文件,可以在cg/shader/cginc文件中被”include”(包含),一般用来写全局方法和全局变量,方便多个shader文件调用。

ShaderLab的一些疑问补充

  • 多个Subshader的情况下,会按顺序优先选择当前第一个可用的Shader.如果都不能用就执行FallBack(如果指定的话)
  • Subshader中的pass是按顺序依次执行的。多个pass会导致多次drawcall.
  • CG块中包含的是CG语言,是编写逻辑和效果的地方,CG块可以在SubShader内,也可以在Pass内。当多个Pass的CG块相同则可以提到Subshader中,或surface Shader中CG块也是在SubShader中。
  • Category:Category解决了当多个SubShader中Tags或Common State相同时,可以提取这些到Category中,例子:

    Shader "Custom/Test"{
      Properties{
          _Color("Main Color",Color) = (1,1,1,1)
      }
      Category{
          Tags{"Queue" = "Transparent"}
          ZWrite Off
          Blend SrcAlpha OneMinusSrcAlpha
          SubShader{
              ...
          }
          SubShader{
              ...
          }
      }
    }

    总结

    本文主要大概总结了一下Unity中的ShaderLab语法,ShaderLab其实主要是提供了一个统一的框架,具体实现主要是用CG语言来写,关于CG语言,以后会写一篇专门针对CG语言的文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值