1、透明测试是用于处理哪种透明需求
在游戏开发中对象的某些部位完全透明而其他部位完全不透明,这种透明需求往往不需要半透明效果,相对比较极端,只有看得见和看不见之分比如树叶、草、栅栏等等。(即一张图除了主要物体有颜色,其他区域都为透明)
2、透明测试的基本原理
基本原理:通过一个阈值来决定哪些像素应该被保留,哪些应该被丢弃
具体实现:片元携带的颜色信息中的透明度(A值),不满足条件时(通常是小于某个阈值),该片元就会被舍弃,被舍弃的片元不会在进行任何处理,不会对颜色缓冲区产生任何影响;满足条件时(通常是大于等于某个阈值),该片元会按照不透明物体的处理方式来处理
阈值判断使用的方法:利用CG中的内置函数:clip(参数)
该函数有重载,参数类型可以是 float4 float3 float2 float 等等,如果传入的参数任何一个分量是负数就会舍弃当前片元它的内部实现会用到一个 discard 指令,代表剔除该片元 不再参与渲染
void clip(float4 x) {
if (any(x < 0))
discard;
}
3、透明测试实现
- 复制颜色纹理结合光照模型的Shader
- 在属性中加一个阈值_Cutoff,取值范围为0~1,用来设定用来判断的阈值。并在CG中添加属性的映射成员
- 将渲染队列设置为AlphaTest,并配合IgnoreProjector和RenderType一起设置
- 在片元着色器中获取了颜色贴图颜色后,就进行阈值判断
注意:透明度测试不需要关闭深度写入
选用下面这张各个区域透明度不同的纹理图片
Shader "ShaderProj/3/TransparentTest"
{
Properties
{
_MainTex("MainTex", 2D) = ""{}
_MainColor("MainColor", Color) = (1,1,1,1)
_SpecularColor("SpecularColor", Color) = (1,1,1,1)
_SpecularNum("SpecularNum", Range(0,20)) = 15
_CutOff("CutOff", Range(0,1)) = 0 // 透明度测试阈值
}
SubShader
{
Tags{
"Queue"="AlphaTest"
"IgnoreProjector"="True"
"RenderType"="TransparentCutout"
}
Pass
{
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _MainColor;
fixed4 _SpecularColor;
float _SpecularNum;
fixed _CutOff;
struct v2f
{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
float3 wNormal:NORMAL;
float3 wPos:TEXCOORD01;
};
fixed3 getLambertColor(float3 normal, float3 lightDir, fixed3 albedo)
{
fixed3 color = _LightColor0 * albedo * max(0, dot(lightDir, normal));
return color;
}
fixed3 getSpecularColor(float3 worldPos, float3 normal, float3 lightDir)
{
//float3 viewDir = normalize(_WorldSpaceCameraPos - worldPos);
float3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
float3 halfAngle = normalize(viewDir + lightDir);
fixed3 color = _LightColor0 * _SpecularColor * pow(max(0, dot(normal, halfAngle)), _SpecularNum);
return color;
}
v2f vert (appdata_base v)
{
v2f data;
data.pos = UnityObjectToClipPos(v.vertex);
data.wNormal = UnityObjectToWorldNormal(v.normal);
data.wPos = mul(unity_ObjectToWorld, v.vertex);
data.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
//data.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
return data;
}
fixed4 frag (v2f i) : SV_Target
{
// 透明度测试
fixed4 texColor = tex2D(_MainTex, i.uv);
clip(texColor.a - _CutOff);
// 纹理颜色需要和漫反射材质颜色叠加(乘法)共同决定最终的颜色
fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _MainColor.rgb;
float3 lightDir = normalize(_WorldSpaceLightPos0);
fixed3 lambertColor = getLambertColor(i.wNormal, lightDir, albedo);
fixed3 specularColor = getSpecularColor(i.wPos, i.wNormal, lightDir);
// 环境光也要与纹理颜色叠加,防止变灰
fixed3 color = lambertColor + specularColor + UNITY_LIGHTMODEL_AMBIENT.rgb * albedo;
return fixed4(color, 1);
}
ENDCG
}
}
}