一、cginc文件
1.1 unity的UnityCG.cginc文件
我们经常使用#include 指令包含UnityCG.cginc。这个文件中包含了unity预定义的大量结构和函数,通过#include指令可以复用这些结构和函数,而不必每次都重新定义它们。
1.2定义自己的cginc文件
我们可以定义自己的cginc文件,然后用#include指令包含该文件,实现着色器代码的复用。虽然包含了整个cginc文件,但unity只会在实际代码中包含被用到的cginc文件中的那部分代码。
二、通过UsePass来复用通道
2.1定义自己要复用的通道
我们可以为定义的Pass声明名字,以便外部引用,名字要大写,因为在unity引擎内部,所有通道名都是大写的。
2.2复用这些通道
复用格式如下:
UsePass "Tut/Organize/UsePass/MyPasses/RED"
三、定义着色器的关键字
3.1使用关键字改变着色器的行为
我们可以自定义着色器关键字,用它们组织着色器的框架,让他们可以在不同的平台上实现预期效果。Unity4.x版本中,整个工程中着色器关键字最多不能超过64个(包括unity自己内置关键字),在unity5.0版本中,关键字数量会增加到128个。一般检测方法可以用 #if defined(XX)、 #ifdef XX、 #ifndef XX,然后#endif。
3.2 自定义着色器关键字
Shader "Tut/Organize/KeyWords/KeyWord_1" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
pass{
CGPROGRAM
#define MY_Condition_1 //定义了一个关键字
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct vertOut{
float4 pos:SV_POSITION;
};
vertOut vert(appdata_base v)
{
vertOut o;
o.pos=UnityObjectToClipPos(v.vertex);
return o;
}
float4 frag(vertOut i):COLOR
{
float4 c=float4(0,0,0,0);
#if defined(MY_Condition_1) //检测此关键字是否被定义,并执行不同的运算
c=float4(1,0,0,0);
#endif
return c;
}
ENDCG
}//end pass
}
}
但是这样做仍然是静态的,只会在着色器编译时起作用,如果想在运行时通过关键字改变着色器的行为呢?
四、ShaderVariant shader变体介绍
4.1 ShaderVariant
举个例子,对于一个支持法线贴图的Shader来说,用户肯定希望无论是否为材质提供法线贴图它的Shader都能正确的进行渲染处理。一般有两种方法来保证这种需求:
1.在底层shader(GLSL,HLSL等)定义一个由外部传进来的变量(如int),有没有提供法线贴图由外部来判断并给这个shader传参,若是有则传0,否则传1,在Shader用if对这个变量进行判断,然后在两个分支中进行对应的处理。
2.对底层shader封装,如Unity的ShaderLab就是这种,然后在上层为用户提供定义宏的功能,并决定宏在被定义和未被定义下如何处理。最终编译时,根据上层的宏定义,根据