一、透明度测试
只要一个片元不满足条件(通常是小于某个阙值),那么它对应的片元就会被舍弃。
函数:
clip(),参数可以是1-4维的矢量,也可以是普通标量。
作用:裁剪使用时的标量或者矢量条件。如果给定参数的任何一个分量是负数,就会舍弃当前像素的输出颜色。
代码:
Shader “Unity Shaders Book/Chapter 8/Alpha Test”
{
Properties
{
_Color("Main Tint",Color)=(1,1,1,1)
_MainTex("Main Tex",2D)="white"{}
_Cutooff("Alpha Cutoff",Range(0,1))=0.5 //设置透明度测试使用的判断条件
}
Subshader
{
Tags{"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
//这里透明度测试使用的渲染队列为AlphaTest,
//设置忽视投影器的影响
//RenderType是可以将Shader提前归入定义的组TransparentCutout,
//指明这是一个使用了透明度测试的Shader,RenderType通常被用来用于着色器替换功能。
Pass
{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _Cutoff; //用于判断比较的条件
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct v2f
{
float4 pos : SV:POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv :TEXCOORD2;
}
vef vert(a2v v)
{
v2f o;
o.pos = mul(UNTIY_MATRIX_MVP,v.vertex);
o.worldNormal = UnityObjectToWorldNoraml(v.normal);
o.worldPos = mul(_Object2World,v.vertex).xyz;
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); //计算平铺偏移后的纹理坐标
renturn o;
}
fixed4 frag(v2f i):SV_Target
{
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texColor = tex2D(_Maintex,i.uv);
clip(texColor.a-_Cutoff); //这里直接使用上面的采样后的纹理a分量进行对比_Cutoff。
fixed3 albedo = texColor.rgb*_Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;
fixed3 diffuse = _LightColor0.rgb*albedo*max(0,dot(worldNormal,worldLightDir));
return fixed4(ambient+diffuse,1.0);
}
}
}
Fallback "Transparent/Cutout/VertexLit"
//这个回调Shader不仅可以充当显卡不能使用时的替换Shader,
//也可以保证使用透明度测试的物体可以正确的向其他物体投射阴影。
}
二、ShaderLab混合命令
混合命令:Blend–混合模式的设置,Unity中Blend命令命令除了设置混合方式,也同时会开启混合,但需要注意在其他图形API中是需要我们手动开启的。
进行混合时,我们需要使用两个混合等式,一个用于混合RGB通道,一个用于A通道。
设置混合状态时,我们设置的就是混合等式中的操作和因子。
两个通道所以可能会用到4个因子。
等式:
RGB: Orgb=SrcFactor×Srgb+DstFactor×Drgb
A: Oa=SrcFactorA×Sa+DstFactorA×Da
语义:
Blend Off
//关闭混合
Blend SrcFactor DstFactor
//开启混合,源颜色(该片元产生的颜色)乘以SrcFactor,目标颜色(已经存在与颜色缓冲中的颜色)乘以DstFactor,然后两者相加再存入颜色缓冲中。此时,两个通道使用的是相同的混合因子。
Blend SrcFactor DstFactor,SrcFactorA DstFactorA
//和上面一样,只是在透明通道使用了不同的混合因子
BlendOp BlenderOperation
//使用了其他操作(不是简单的加法了)
当min与max时,混合因子实际上是不起作用的。他仅仅判断原始的源颜色和目的颜色之间的比较结果
举例:
Blend SrcAlpha OneMinusSrcAlpha,One Zero
//使用源颜色值和(1-原颜色值)作为rgb分量因子,输出颜色透明度值就是源颜色值的透明度
使用其他计算操作(除相加)可见上面变量变暗等效果。
三、透明度混合
实现真正的半透明效果。
使用当前片元透明度作为混合因子,与已经存储在颜色缓冲中颜色值进行混合,得到新的颜色,但此时我们需要关闭深度写入,所以我们需要小心物体的渲染顺序。
Shader “Unity Shaders Book/Chapter 8/Alpha Blend”
{
Properties
{
_Color("Main Tint",Color)=(1,1,1,1)
_MainTex("Main Tex",2D)="white"{}
_AlphaScale("Alpha Scale",Range(0,1))=1 //控制整体透明度
}
Subshader
{
Tags{"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
//这里透明度混合使用的渲染队列为Transparent,
//设置忽视投影器的影响
//RenderType是可以将Shader提前归入定义的组Transparent,
//指明这是一个使用了透明度混合的Shader,RenderType通常被用来用于着色器替换功能。
Pass
{
Tags{"LightMode"="ForwardBase"}
ZWrite Off //将深度写入关掉
Blend SrcAlpha OneMinusSrcAlpha //开启混合模式,并设置方式
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _AlphaScale; //控制整体透明度
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct v2f
{
float4 pos : SV:POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv :TEXCOORD2;
}
vef vert(a2v v)
{
v2f o;
o.pos = mul(UNTIY_MATRIX_MVP,v.vertex);
o.worldNormal = UnityObjectToWorldNoraml(v.normal);
o.worldPos = mul(_Object2World,v.vertex).xyz;
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); //计算平铺偏移后的纹理坐标
renturn o;
}
fixed4 frag(v2f i):SV_Target
{
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texColor = tex2D(_Maintex,i.uv);
fixed3 albedo = texColor.rgb*_Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;
fixed3 diffuse = _LightColor0.rgb*albedo*max(0,dot(worldNormal,worldLightDir));
return fixed4(ambient+diffuse,texColor.a*_AlphaScale);//只有打开透明通道后,这里才有意义,否则将不会有影响
}
}
}
Fallback "Transparent/VertexLit"
//这个回调Shader不仅可以充当显卡不能使用时的替换Shader,
//也可以保证使用透明度测试的物体可以正确的向其他物体投射阴影。
}
四、开启深度写入的透明效果
重新利用深度写入,让模型像半透明物体一样进行淡入淡出。
效果:物体是透明的,但是只看物体时,物体前后之间会有深度效果遮挡。
方法:使用两个Pass来渲染模型,第一个开启深度写入,目的是将模型的深度值写入深度缓冲中,第二个进行透明度混合,因为上一个Pass我们已经得到了逐像素的正确深度信息,该个PASS就可以按照像素级别的深度排序结果进行透明渲染。
缺点:两个PASS会对性能造成一定影响。
代码:
Shader “Unity Shaders Book/Chapter 8/Alpha Blend ZWrite”
{
Properties
{
_Color("Main Tint",Color)=(1,1,1,1)
_MainTex("Main Tex",2D)="white"{}
_AlphaScale("Alpha Scale",Range(0,1))=1 //控制整体透明度
}
Subshader
{
Tags{"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
//这里透明度混合使用的渲染队列为Transparent,
//设置忽视投影器的影响
//RenderType是可以将Shader提前归入定义的组Transparent,
//指明这是一个使用了透明度混合的Shader,RenderType通常被用来用于着色器替换功能。
Pass
{
ZWrite On
ColorMask 0
//用于设置颜色通道,设置为0,意味着Pass不写入任何颜色通道,不会输出颜色信息,只是写入深度缓存。
}
Pass
{
Tags{"LightMode"="ForwardBase"}
ZWrite Off //将深度写入关掉
Blend SrcAlpha OneMinusSrcAlpha //开启混合模式,并设置方式
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _AlphaScale; //控制整体透明度
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct v2f
{
float4 pos : SV:POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv :TEXCOORD2;
}
vef vert(a2v v)
{
v2f o;
o.pos = mul(UNTIY_MATRIX_MVP,v.vertex);
o.worldNormal = UnityObjectToWorldNoraml(v.normal);
o.worldPos = mul(_Object2World,v.vertex).xyz;
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); //计算平铺偏移后的纹理坐标
renturn o;
}
fixed4 frag(v2f i):SV_Target
{
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texColor = tex2D(_Maintex,i.uv);
fixed3 albedo = texColor.rgb*_Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;
fixed3 diffuse = _LightColor0.rgb*albedo*max(0,dot(worldNormal,worldLightDir));
return fixed4(ambient+diffuse,texColor.a*_AlphaScale);//只有打开透明通道后,这里才有意义,否则将不会有影响
}
}
}
Fallback "Diffuse"
//这个回调Shader不仅可以充当显卡不能使用时的替换Shader,
//也可以保证使用透明度测试的物体可以正确的向其他物体投射阴影。
}
五、双面渲染的透明效果
效果:可以通过透明部分看到透明物体内部结构和后面结构。
指令:使用剔除Cull指令。
Cull back/Front/Off
设置为Back时,背对摄像机的背面渲染图元不会被渲染,这是默认情况下的剔除状态。
设置为Front时,朝向摄像机的图元不会被渲染。
如果设置为Off,那么所有图元都会被渲染。但这时渲染数目会成倍增加,如不是实现特殊效果不会开启。
1.透明度测试的双面渲染方法:
使用Cull关闭剔除。
Shader “Unity Shaders Book/Chapter 8/Alpha Test Both Sided”
{
Properties
{
_Color("Main Tint",Color)=(1,1,1,1)
_MainTex("Main Tex",2D)="white"{}
_Cutooff("Alpha Cutoff",Range(0,1))=0.5 //设置透明度测试使用的判断条件
}
Subshader
{
Tags{"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
//这里透明度测试使用的渲染队列为AlphaTest,
//设置忽视投影器的影响
//RenderType是可以将Shader提前归入定义的组TransparentCutout,
//指明这是一个使用了透明度测试的Shader,RenderType通常被用来用于着色器替换功能。
Pass
{
Tags{"LightMode"="ForwardBase"}
Cull off //关闭剔除功能
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _Cutoff; //用于判断比较的条件
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct v2f
{
float4 pos : SV:POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv :TEXCOORD2;
}
vef vert(a2v v)
{
v2f o;
o.pos = mul(UNTIY_MATRIX_MVP,v.vertex);
o.worldNormal = UnityObjectToWorldNoraml(v.normal);
o.worldPos = mul(_Object2World,v.vertex).xyz;
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); //计算平铺偏移后的纹理坐标
renturn o;
}
fixed4 frag(v2f i):SV_Target
{
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texColor = tex2D(_Maintex,i.uv);
clip(texColor.a-_Cutoff); //这里直接使用上面的采样后的纹理a分量进行对比_Cutoff。
fixed3 albedo = texColor.rgb*_Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;
fixed3 diffuse = _LightColor0.rgb*albedo*max(0,dot(worldNormal,worldLightDir));
return fixed4(ambient+diffuse,1.0);
}
}
}
Fallback "Transparent/Cutout/VertexLit"
//这个回调Shader不仅可以充当显卡不能使用时的替换Shader,
//也可以保证使用透明度测试的物体可以正确的向其他物体投射阴影。
}
2.透明度混合的双面渲染
方法:因为透明度混合需要关闭深度写入,所以使用两个Pass控制渲染顺序,
第一个只渲染背面,第二个只渲染前面。保证背面总是在前面渲染之前进行渲染。
Shader “Unity Shaders Book/Chapter 8/Alpha Blend Both Sided”
{
Properties
{
_Color("Main Tint",Color)=(1,1,1,1)
_MainTex("Main Tex",2D)="white"{}
_AlphaScale("Alpha Scale",Range(0,1))=1 //控制整体透明度
}
Subshader
{
Tags{"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
//这里透明度混合使用的渲染队列为Transparent,
//设置忽视投影器的影响
//RenderType是可以将Shader提前归入定义的组Transparent,
//指明这是一个使用了透明度混合的Shader,RenderType通常被用来用于着色器替换功能。
Pass
{
Tags{"LightMode"="ForwardBase"}
Cull Front
ZWrite Off //将深度写入关掉
Blend SrcAlpha OneMinusSrcAlpha //开启混合模式,并设置方式
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _AlphaScale; //控制整体透明度
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct v2f
{
float4 pos : SV:POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv :TEXCOORD2;
}
vef vert(a2v v)
{
v2f o;
o.pos = mul(UNTIY_MATRIX_MVP,v.vertex);
o.worldNormal = UnityObjectToWorldNoraml(v.normal);
o.worldPos = mul(_Object2World,v.vertex).xyz;
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); //计算平铺偏移后的纹理坐标
renturn o;
}
fixed4 frag(v2f i):SV_Target
{
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texColor = tex2D(_Maintex,i.uv);
fixed3 albedo = texColor.rgb*_Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;
fixed3 diffuse = _LightColor0.rgb*albedo*max(0,dot(worldNormal,worldLightDir));
return fixed4(ambient+diffuse,texColor.a*_AlphaScale);//只有打开透明通道后,这里才有意义,否则将不会有影响
}
}
Pass
{
Tags{"LightMode"="ForwardBase"}
Cull Back
ZWrite Off //将深度写入关掉
Blend SrcAlpha OneMinusSrcAlpha //开启混合模式,并设置方式
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _AlphaScale; //控制整体透明度
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct v2f
{
float4 pos : SV:POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float2 uv :TEXCOORD2;
}
vef vert(a2v v)
{
v2f o;
o.pos = mul(UNTIY_MATRIX_MVP,v.vertex);
o.worldNormal = UnityObjectToWorldNoraml(v.normal);
o.worldPos = mul(_Object2World,v.vertex).xyz;
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); //计算平铺偏移后的纹理坐标
renturn o;
}
fixed4 frag(v2f i):SV_Target
{
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texColor = tex2D(_Maintex,i.uv);
fixed3 albedo = texColor.rgb*_Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;
fixed3 diffuse = _LightColor0.rgb*albedo*max(0,dot(worldNormal,worldLightDir));
return fixed4(ambient+diffuse,texColor.a*_AlphaScale);//只有打开透明通道后,这里才有意义,否则将不会有影响
}
}
}
Fallback "Transparent/VertexLit"
//这个回调Shader不仅可以充当显卡不能使用时的替换Shader,
//也可以保证使用透明度测试的物体可以正确的向其他物体投射阴影。
}