Surface Shaders

"表面着色器"

Posted by PandaL33 on May 24, 2017

表面着色器

使用Unity3D的表面着色器,只需要编写最关键的表面函数,其余周边代码将由Unity3D自动生成,包括适配各种光源类型、渲染实时阴影以及集成到前向/延迟渲染管线中等。

编写表面着色器的规则如下:

  • 表面着色器的实现代码需要放置在CGPROGRAM…ENDCG代码块中,而不是Pass结构中,它会自己编译到各个Pass。
  • 使用#pragma surface…命令来指明它是一个表面着色器,例
#pragma surface 表面函数 光照模型 [可选参数]

其中“表面函数”用来说明那个CG函数包含有表面着色器代码,其作用是接收输入的UV或者附加数据,然后进行处理最后将结果填充到输出结构体SurfaceOutput中。表面函数形式为:

void surf(Input IN,inout SurfaceOutput 0)

“光照模型”可以是内置的Lambert和BlinnPhong,或者是自定义的光照模型。输入结构体Input一般包含着色器所需的纹理坐标,纹理坐标的命名规则为uv加纹理名称(当使用第二张纹理时使用uv2加纹理名称),另外还可以在输入结构中设置一些附加数据,具体内容如下:

附加数据   说明
float3 viewDir   视角方向
float4 COLOR   每个顶点的插值颜色
float4 screenPos   屏幕坐标(使用.xy/.w来获取屏幕2D坐标)
float3 worldPos   世界坐标
float3 worldRefl   世界坐标系中的反射向量
float3 worldNormal   世界坐标系中的法线向量
INTERNAL_DATA   当输入结构包含worldRefl或worldNormal且表面函数会写入输出结构的Normal字段时需包含此声明

SurfaceOutput描述了表面的各种参数,标准结构为:

struct SurfaceOutput{
    half3 Albedo;       //反射光
    half3 Normal;       //法线
    half3 Emission;     //自发光
    half Specular;      //高光
    half Gloss;         //光泽度
    half Alpha;         //透明度
}

表面着色器代码:

Shader "Surface Shader Example/WorldRefl"{
    Properties{//属性定义
        _MainTex("Base (RGB)",2D)="white"{}
        _Cube("Cubemap",CUBE)=""{}//立方体贴图属性
    }
    SubShader{
        Tags{"RenderType"="Opaque"}
        CGPROGRAM
        #pragma surface surf Lambert
        struct Input{
            float2 uv_MainTex;
            float3 worldRefl;//输入反射参数
        };
        smapler2D _MainTex;
        samplerCUBE _Cube;
        void surf(Input IN,inout SurfaceOutput o)
        {
            o.Albedo=text2D(_MainTex,IN.uv_MainTex).rgb*0.5;
            O.Emission=texCUBE(_Cube,IN.worldRefl).rgb;//将反射颜色设置给自发光颜色
        }
        ENDCG
    }
    Fallback "Diffuse"
}