untiy 3d ShaderLab_第 2 章Unity中Shader(着色器)的形态_2_Unity中Shader的3种形态

2.2 Unity的ShaderLab所支持的Shader

    在Unity的ShaderLab所提供的结构中,我们既能使用GLSL来写Shader的逻辑代码,也能使用Cg/HLSL来写。如果使用GLSL,则这些代码必须位于GLSLPROGRAM和ENDGLSL关键字之间;如果使用Cg/HLSL,则这些代码必须位于CGPROGRAM和ENDCG之间。我全部使用Cg编程语言编写。Cg语言并非像Mac平台开发的Object-C语言一样,让习惯了C、C++或者Java、 C#的程序员看起来怪怪的。这门语言和C:语言很类似,作为一种Shader编程语言,主要提供了一个全新的函数库。关于Cg的学习,读者可以查看附录,里面有NVIDIA官方的权威教程链接地址。

2.3 Unity中Shader的3种形态

2.3.1固定管线
    固定管线是在老代GPU能力比较有限时,对Shader的约束性比较高的一种形态。为了市场占有率,新一代的显卡仍对其有所选择地进行支持,但是会在未来逐步被淘汰。在ShaderLab中,固定管线的形态和语法和NVIDIA的CgFX以及微软的FX文件比较类似。下面是固定管线的一个例子:

Shader  "Tut/Shader/FixedFuncs/BaseForm_1’‘{
          Properties{
          _Color("Main Color",Color)=(1,1,1,0.5)
          _SpecColor("Spec Color",Color)=(1,1,1,1)
          _Emission("Emmisive Color",Color)=(0, 0, 0,0)
          _Shininess ("Shininess", Range(0.01,1)) = 0.7
          _MainTex("Base (RGB)”,2D)="white"{ }
      }
      SubShader{
          Pass{
              Material{
                    Diffuse  [ _Color]
                    Ambient [ _Color]
                    Shininess[ _Shininess]
                    Specular [ _ SpecColor]
                    Emission [ _Emission]
                }
              Lighting On
              SeparateSpecular On
                SetTexture [ _ MainTex]  {
                    constantColor [ _ Color]
                    Combine texture*primary DOUBLE, texture*constant
                    }
               }
         }
}

    固定管线的相关代码必须都处于一个Pass块之中。关于Unity中固定管线的详细讲解,可以参考Shader篇的关于固定管线的第16章,这里只说其大概形态。

2.3.2可编程Shader
    如果你想自己处理照明,可以写vertex+fragment Shader,这是Unity中对可编程Shade:的一种支持。下面是可编程Shader的一个例子。

Shader "Tut/NewBie/FOUrthShader"
Properties{
      _MyTexture ("Texture (RGB)”,2D)="white"{ }
      _MyColor("Color of Object",Color)=(1, 1,1, 1)
}
SubShader{
Tags{"Queue"="Geometry""RenderType"="Opaque""IgnoreProjector"="True"}
Pass{
CGPROGRAM
#pragma vertex vert//声明vertex Shader的函数
#pragma fragment frag//声明fragment Shader的函数
#include "UnityCG.cg土nc"//包括外部文件
sampler2D  _MyTexture;
float4 _MyColor;
struct v2f { //定义一个结构
        float4 pos:SV_POSITION;
};
v2f vert (appdata_full v)//vertex Shader
{
     v2f o;
     o.pos= mul(UNITY_ MATRIX_MVP, v.vertex);
     return o;
}
float4  frag ( v2f  i) : COLOR// fragment Shader
{
       return float4(1);
}
  ENDCG
        }
 }
 Fa1lBack "Diffuse"
}

除了上面例子中有的,我们还可以使用下面一些指令告诉Unity如何具体地编译Shader。

//编译目标2.0,相当于Direct3D的Shader Model 2.0
//对应于。penGL下的256条ARB vertex shader的指令,32条ARB_fragment_shader的texture指令
//和64条普通指令,16个寄存器和4个贴图
#pragma target 2 .0
//如果编译目标3.0,则相当于Direct3D的Shader Model 3
//对于penGL的ARB  vertex shader来说没有指令数目限制,对应ARB_fragment_shader的
//512条texture操作指令、512条普通指令、32个寄存器和4个贴图。

    对于面向OpenGL接口的情况,还可以使用#pragma profileoption MaxTexIndirection = 256这样的指令。当编译平台为独立的可执行桌面OpenGL程序时,可以使用#pragma glsl把Cg代码转换为GLSL代码,从而绕过在Shader Model 3.0中的一些指令限制。如果大家熟悉OpenGL接口,也可以使用#pragma fragmentoption option来限制编译出的fragment函数。对于移动平台的GLSL,比如Android和IOS,可以使用#pragma glsl_no_auto_normalizationa来关闭在vertex函数中对法线和切向量的自动单位化处理。
    为了增加平台适应性,Unity会把Shader针对不同的平台进行编译,对移动平台Unity做些优化。除此之外,开发者也可以使用下面这两条指令来限制Unity对不同平台的编译。

#pragma only_ renderersd3d9 gles
#pragma exclude renderers xbox360

    适应于这两条指令的值有d3d9、d3d11、opengl、gles(移动平台的OpenGL)、xbox360、p3(任天堂的PlayStation)、flash。

2.3.3  ShaderLab的骄傲:Surface Shader
    如果你想写一个能处理不同的照明、点光源、平行光、光照贴图等,又能够处理不同的阴影选项,还同时能在Unity的两个渲染路径(Forward和Deferred )下正常工作,是一件很复杂、很烦人的事情。Unity通过Surface Shader把上面这一切复杂性包装了起来。下面是这样一个Surface Shader例子,其实也就是在编辑器中创建Shader的默认结果:

Shader "Tut/NewBie/SurfShader"{
        Properties  {
                _MainTex("Base  (RGB)”,2D) = ”white"{ }
          }
        SubShader{
              Tags {"RenderType"="Opaque" }
               LOD 200
               CGPROGRAM
               #pragma surface surf Lambert
               sampler2D  _MainTex;
              struct Input {
                      float2 uv _MainTex;
         };
          void surf (Input IN, inout Surfaceoutput o){
          half4 c= tex2D ( _MainTex,IN.uv_MainTex);
         o.Albedo=c.rgb;
         o.Alpha = c.a;
           }
           ENDCG
      }
   Fa1lBack "Diffuse"
}
    在Surface函数surf中,Surface0utput是一个包含大多数描述个物体表面渲染特征的结构,
例如:
struct Surfaceoutput{
      half3 Albedo;//颜色纹理
      half3 Normal;//法线
      half3 Emission;//自发光,不受照明的影响
      half Specular;//高光指数
      half Gloss;//光泽度
      half Alpha;//Alpha通道
};

    Surface Shader最终会被编译为一个复杂的 vertex+fragment Shader,不过通过Surface Shader,开发者需要做的就是简单地调色,当然这个说法比较笼统,可以自己实际体会一下。关于Surface Shader的更详细说明在以后的Surface Shader一章中。

你可能感兴趣的:(untiy 3d ShaderLab_第 2 章Unity中Shader(着色器)的形态_2_Unity中Shader的3种形态)