Shader以及Unity中的Shader

Shader即着色器,是一中运行在GPU上的程序,用来对三维物体进行着色处理,光与影的计算,纹理颜色的呈现等,从而将游戏引擎中一个个作为抽象的几何数据存在的模型,场景和特效,以和真实世界类似的光与影的形式呈现于玩家的眼中。通过Shader可以改变物体的形状,大小,位置,旋转等,甚至可以做PS的功能效果。伴随着GPU硬件性能的提升,shader编程方式经历了从最初的固定管线,到可编程流水线的发展。Shader有顶点Shader和片段Shader两个基本类型,顶点Shader有着可以处理,变换最终会渲染到屏幕上的网格物体的顶点位置的功能,但是不可以生成新的顶点。Shader作为一款在GPU上运行上的程序,目前有三种高级图形语言可供选择:HLSL,GLSL,CG。Unity对shader编程语言支持的重点是CG。
Unity中的Shader:
以关键字shader开始,在Unity中新建一个Shader默认如下

Shader "Custom/NewShader" {
    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
    } 
    FallBack "Diffuse"
}

真正用于呈现渲染物体的内容是在SubShader中实现的,不同的显卡使用不同的SubShader,SubShader数量不限,不过最好只有两三个。SubShader中添加标签,可以告诉Unity渲染引擎或者其他用户如何认证这个SubShader。

Tags{"Queue"="Geometry""RenderType"="Opaque""IgnoreProjector"="True" }

Queue表示渲染队列,希望渲染引擎在什么时候渲染自己。Queue有5个可选值,它们是Background,Geometry,AlphaTest,Transparent,Overlay,分别对应数字1000,2000,2450,3000,4000。所以也可以表示

Tags{"Queue"="Geometry+1314"}

Unity内置Shader按照上面顺序渲染,下一个RenderType标签,内置值有Opaque,Transparent,TransparentCutout,Background和Overlay。IgnoreProjector值为TRUE,表示当前物体忽略Projector的影响。在做代替渲染时候也可以添加自定义标签。
SubShader包装了一个渲染方案,这个方案是由一个个Pass块来执行的。
往上面代码添加一个SubShader

SubShader{
        Pass    {
                Name "MYM"
                Material{
                    Diffuse(1,0.7,0.4,1)
                    Ambient(1,0.7,0.4,1)
                }
                Lighting On
                SetTexture[_]{combine primary}
        }
    }

使用这个新加的Pass

Shader "Custom/NewShader1" {
SubShader {
                   UsePass "Custom/NewShader/MYM"
            }
 }

如果所有的SubShader都失败了,一般会使用Unity预制的Shader实现,使用FallBack。
在Unity的ShaderLab所提供的结构中,既可以用GLSL来写Shader的逻辑代码,也可以用Cg/HLSL,如果使用Cg,那么代码必须位于CGPROGRAM和ENDCG之间。
Unity中Shader的三种形态
1.固定管线在老一代GPU能力有限,对Shader的约束性比较高的一种形态,未来会逐步淘汰,下面是固定管线的代码例子:
固定管线的相关代码都必须处于一个Pass

Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _Color ("Main Color",Color) =(1,1,1,0.5)
        _SpecColor("Spec Color",Color) = (1,1,1,1);
        _Emission("Emmisie Color",Color)=(0,0,0,0);
        _Shininess("Shininess",Range(0.01,1))=0.7;
    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 * ConstantColor
                }
            }
        }

2.可编程Shader 顶点+片段着色器

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
        #pragma fragment frag
        #include "UnityCG.cginc"
        sampler2D _MyColor;

        struct v2f{
            float4 pos::SV_POSITION;
        };

        v2f vert(appdata_full v)
        {
            v2f o;
            o.pos = mul(UNITY_MATRIX_MVP,v.Vertex);
            return o;
        }
        float4 frag(v2f i)
        {
            return float4(i);
        }
        ENDCG
            }
        }
        FallBack "Diffuse"

3.表面着色器
Unity通过SurfaceShader可以处理不同的照明,点光源,平行光,光照贴图等,又能处理不同的阴影选项,还能同时在Unity两个渲染路径下正常工作。例子代码就是Unity创建的默认Shader

Shader "Custom/NewShader" {
    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
    } 
    FallBack "Diffuse"
}

surf函数中 SurfaceOutput是一个包含大多数描述一个物体表面渲染特征的结构
struct SurfaceOutput{
half3 Albedo;//颜色纹理
half3 Normal;
half3 Emission;//自发光,不受照明影响
half Specular;//高光指数
half Gloss;//光泽度
half Alpha;//Alpha通道
};
表面着色器最终会被编译成一个复杂的顶点+片段着色器。

你可能感兴趣的:(unity3d)