前部分知识复习01
一、关于变体
1.#pragma multi_compile A
2.#pragma shader_feature A
Unity提供了两个关键字来定义宏 multi_compile 和 shader_feature,Unity 会根据宏定义来生成不同种类的shader,这些不同种类的shader就是所谓的变体。
multi_compile的特点如下:
1、会组合爆炸
#pragma multi_compile A B
#pragma multi_compile C D这样就会生成4种变体 (A,C) (A,D) (B,C) (B,D)
如果multi_compile定义的越多,生成的变体组合数就会非常非常多,特别恐怖。2、不论是否动态启用(代码中调用EnableKeyword),变体都会打进包中
所以这样带来的问题就是,multi_compile 控制不好会导致打包慢,还生成很多没用的shader。
两种变体的适用范围:
两种定义方式可以使用在任何shader中,只是各自有一些建议使用情况。
multi_compile定义的宏,如#pragma multi_compile_fog,#pragma multi_compile_fwdbase等,基本上适用于大部分shader,与shader自身所带的属性无关。
shader_feature定义的宏多用于针对shader自身的属性。比如shader中有_NormalMap这个属性(Property),便可通过#pragma shader_feature _NormalMap
来定义宏,用来实现这个shader在material有无_NormalMap时可进行不同的处理。
以上内容引用自:
Shader变体收集与打包 - 金城寺的文章 - 知乎
https://zhuanlan.zhihu.com/p/68888831Unity 之唠叨下 Shader 变体 - 阿文的文章 - 知乎
https://zhuanlan.zhihu.com/p/645102924
变体的两种使用方法
1. #pragam shader_feature MASKENABLE
Properties{
//定义与变体有关的开关 //括号内为变体名 可以没有ON 也可以没有下划线
[MaterialToggle( MASKENABLE )] _MaskEnable("MaskEnable",int)=0
}
#if MASKENABLE
......
#endif
2. #pragma shader_feature _DISTORTENABLE_ON
Properties
{
[Toggle]_DistortEnable("DistortEnable",int)=0
}
#if _DISTORTENABLE_ON
.......
#endif
二、lerp(a,b,x)函数
lerp(a,b,x)
x的范围为(0,1);当x=0时,函数值取a;当x=1时,函数值取b;当x为0-1之间的值时,函数取a,b之间的插值
三、特效通用的材质Shader
Shader"unity/Effects2"
{
Properties
{
[Header(RenderingMode)]
[Space(5)]
//Blend混合枚举属性
[Enum(UnityEngine.Rendering.BlendMode)]_SrcBlend("SrcBlend",int)=0
[Enum(UnityEngine.Rendering.BlendMode)]_DstBlend("DstBlend",int)=0
//剔除属性
[Enum(UnityEngine.Rendering.CullMode)]_Cull("Cull",int)=0
[Header(Base)]
[Space(5)]
//主贴图
_MainTex("MainTex",2D)="white"{}
//主贴图UV流动
_MainUVSpeedX("MainUVSpeed X",float)=0
_MainUVSpeedY("MainUVSpeed Y",float)=0
//颜色属性
_Color("Color",Color)=(1,1,1,1)
//颜色增加滑杆
_Intensity("Intensity",Range(-3,3))=1
[Header(Mask)]
[Space(5)]
//遮罩开关
// [Toggle]_MaskEnabled("MaskEnable",int)=0
[MaterialToggle(MASKENABLED)]_MaskEnable("MaskEnable",int)=0 //括号内为变体名 可以没有ON 也可以没有下划线
//遮罩贴图
_MaskTex("MaskTex",2D)="white"{}
//遮罩贴图UV流动
_MaskUVSpeedX("MaskUVSpeed X",float)=0
_MaskUVSpeedY("MaskUVSpeed Y",float)=0
[Header(Distort)]
[Space(5)]
//扭曲开关
[Toggle]_DistortEnabled("DistortEnabled",int)=0
//UV扭曲贴图
_DistortTex("DistortTex",2D)="white"{}
//扭曲贴图UV流动属性
_DistortUVSpeedX("DistortUVSpeed X",float)=0
_DistortUVSpeedY("DistortUVSpeed Y",float)=0
//扭曲滑杆调节
_Distort("Distort",Range(0,1))=0
}
SubShader
{
Tags{"Queue"="Transparent"} //半透明队列
Blend [_SrcBlend][_DstBlend] //混合
Cull [_Cull] //剔除
Pass
{
CGPROGRAM
#pragma vertex vert;
#pragma fragment frag;
#pragma shader_feature MASKENABLED //变体的声明 _MASKENABLED_ON 为变体名
#pragma shader_feature _DISTORTENABLED_ON
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
float _MainUVSpeedX;
float _MainUVSpeedY;
sampler2D _MaskTex;
float4 _MaskTex_ST;
float _MaskUVSpeedX;
float _MaskUVSpeedY;
half _Intensity; //注意使用half定义
//扭曲属性的声明
sampler2D _DistortTex; //扭曲贴图
float4 _DistortTex_ST;
float _DistortUVSpeedX; //UV流动
float _DistortUVSpeedY;
float _Distort; //滑杆
struct appdate
{
float4 vertex :POSITION;
float4 uv:TEXCOORD;
float2 uv1:TEXCOORD1; //重新定义一张UV 用来存放扭曲贴图
};
struct v2f
{
float4 pos:SV_POSITION;
float4 uv:TEXCOORD;
float2 uv1:TEXCOORD1; //重新定义一张UV 用来存放扭曲贴图
};
v2f vert(appdate v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.uv.xy=TRANSFORM_TEX(v.uv,_MainTex)+float2(_MainUVSpeedX,_MainUVSpeedY)*_Time.y;
#if MASKENABLED
o.uv.zw=TRANSFORM_TEX(v.uv,_MaskTex)+float2(_MaskUVSpeedX,_MaskUVSpeedY)*_Time.y;
#endif
#if _DISTORTENABLED_ON
o.uv1.xy=TRANSFORM_TEX(v.uv,_DistortTex)+float2(_DistortUVSpeedX,_DistortUVSpeedY)*_Time.y; //扭曲贴图中使Tilling和Offset有效 并实现UV自流动
#endif
return o;
}
float4 frag(v2f i):SV_TARGET
{
float4 c;
float2 distort=i.uv.xy; //默认值为主贴图的UV坐标
#if _DISTORTENABLED_ON
float4 distortTex=tex2D(_DistortTex,i.uv1.xy); //扭曲贴图UV采样 须写在主贴图采样前 因为主贴图中采样的UV值需用到扭曲贴图UV采样后的结果
distort=lerp(i.uv.xy,distortTex,_Distort); //这里distort所得的结果用作主贴图的纹理采样UV
#endif
float4 tex=tex2D(_MainTex,distort); //使用lerp()函数和_Distort滑杆值来更改扭曲值
c=tex;
c*=_Color*_Intensity;
#if MASKENABLED
float4 maskTex=tex2D(_MaskTex,i.uv.zw);
c*=maskTex;
#endif
return c;
}
ENDCG
}
}
}
四、模版测试
stencil
{
Ref [_Stencil]
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
Comp [_StencilComp] ((UnityEngine.Rendering.CompareFunction))
Pass [_StencilOp] (UnityEngine.Rendering.StencilOp)
Fail [_Fail]
ZFail [_ZFail]}
模版测试公式:
(Ref & ReadMask) Comp (StencilBufferValue & ReadMask)
读取掩码ReadMask默认值为255 二进制位(11111111)
StencilBufferValue为模版缓冲区内的存储值 Ref为当前模版测试值
所以(StencilBufferValue & ReadMask) &(与) 后的结果仍为StencilBufferValue(模版缓冲区内的存储值)
之后再用当前的模版测试值Ref与模版缓冲中的存储值StencilBufferValue进行Comp操作
Stencil
{
Ref [_Stencil]
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
Comp [_StencilComp] ((UnityEngine.Rendering.CompareFunction))
Pass [_StencilOp] (UnityEngine.Rendering.StencilOp)
Fail [_Fail]
ZFail [_ZFail]
}
Ref: 设定的参考值,这个值将用来与模板缓冲中的值进行比较.取值范围位为0-255的整数.
ReadMask: ReadMask的值将和Ref的值以及模板缓冲中的值进行按位与(&)操作,取值范围也是0-255的整数,默认值为255(二进制位11111111),即读取的时候不对Ref的值和模板缓冲中的值产生修改,读取的还是原始值.
WriteMask: WriteMask的值是当写入模板缓冲时进行的按位与操作,取值范围是0-255的整数,默认值也是255,即不做任何修改.
Comp: 定义Ref与模板缓冲中的值比较的操作函数,默认值为always.
Pass: 当模板测试(和深度测试)通过时,则根据(stencilOperation值)对模板缓冲值进行处理,默认值为keep.
Fail: 当模板测试(和深度测试)失败时,则根据(stencilOperation值)对模板缓冲值进行处理,默认值为keep.
ZFail: 当模板测试通过而深度测试失败时,则根据(stencilOperation值)对模板缓冲值进行处理,默认值为keep
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/2401_83878847/article/details/143590005
Comp 比较操作符
Less: 相当于“<”操作,即仅当左边<右边,模板测试通过,渲染像素.
Greater: 相当于“>”操作,即仅当左边>右边,模板测试通过,渲染像素.
Equal: 相当于“=”操作,即仅当左边=右边,模板测试通过,渲染像素.
NotEqual: 相当于“!=”操作,即仅当左边!=右边,模板测试通过,渲染像素.
Always: 不管公式两边为何值,模板测试总是通过,渲染像素.
Never: 不管公式两边为何值,模板测试总是失败 ,像素被抛弃.
Pass 更新模版缓冲区内的值
Keep: 保留当前缓冲中的内容,即stencilBufferValue不变.
Zero: 将0写入缓冲,即stencilBufferValue值变为0.
Replace: 将参考值写入缓冲,即将referenceValue赋值给stencilBufferValue.
IncrSat: 将当前模板缓冲值加1,如果stencilBufferValue超过255了,那么保留为255,即不大于255.
DecrSat: 将当前模板缓冲值减1,如果stencilBufferValue超过为0,那么保留为0,即不小于0.
Invert: 将当前模板缓冲值(stencilBufferValue)按位取反.
IncrWrap: 当前缓冲的值加1,如果缓冲值超过255了,那么变成0,(然后继续自增).
DecrWrap: 当前缓冲的值减1,如果缓冲值已经为0,那么变成255,(然后继续自减)
五、半透明混合模式
SrcAlpha 和 OneMinusSrcAlpha 半透明混合模式
六、使image中的颜色变灰
方法一: c.rgb=c.rrr;
方法二:c.rgb=c.r*0.22+c.g*0.787+c.b*0.071;
方法三:c.rgb=Luminance(c.rgb);
Shader"unity/UIMask04"
{
Properties
{
_MainTex("MainTex",2D)="white"{}
[Enum(UnityEngine.Rendering.BlendMode)]_SrcBlend("SrcBlend",int)=0
[Enum(UnityEngine.Rendering.BlendMode)]_DstBlend("DstBlend",int)=0
_Ref("Ref",float)=0
[Enum(UnityEngine.Rendering.CompareFunction)]_Comp("Comp",int)=0
[Enum(UnityEngine.Rendering.StencilOp)]_Pass("Pass",int)=0
[Toggle]_GrayEnable("GrayEnable",int)=0
}
SubShader
{
Tags{"Queue"="Transparent"}
//SrcAlpha 和 OneMinusSrcAlpha 半透明混合模式
Blend [_SrcBlend] [_DstBlend]
//模版测试 (在透明度测试之后,深度测试之前)
Stencil
{
Ref [_Ref]
Comp [_Comp]
Pass [_Pass]
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma shader_feature _GRAYENABLE_ON
#include "UnityCG.cginc"
sampler2D _MainTex;
int _GrayEnable;
struct appdate
{
float4 vertex : POSITION;
float4 uv : TEXCOORD;
float4 Color:COLOR; //引用image中的颜色
};
struct v2f
{
float4 pos : SV_POSITION;
float4 uv : TEXCOORD;
float4 Color:COLOR;
};
v2f vert(appdate v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.uv=v.uv;
o.Color=v.Color;
return o;
}
float4 frag(v2f i):SV_Target
{
float4 c;
float4 mainTex=tex2D(_MainTex,i.uv);
c=mainTex;
c*=i.Color;
#if _GRAYENABLE_ON
//使颜色变灰
c.rgb=Luminance(c.rgb);
#endif
return c;
}
ENDCG
}
}
}