文章目录
- 渲染队列
- 透明度测试(Alpha Test)
- 效果
- Shader
- 透明度混合(Alpha Blending)
- 效果
- Shader
- 参考
渲染队列
由”Queue“ 标签决定,索引号越小越早被渲染:
名称 | 队列索引号 |
---|---|
Background | 1000 |
Geometry | 2000 |
AlphaTest | 2450 |
Transparent | 3000 |
Overlay | 4000 |
透明度测试(Alpha Test)
某一片元的透明度小于某个阈值,即被舍弃,反之,按非透明物体处理,进行正常的深度测试和深度写入【不需要关闭深度写入】。
效果
Shader
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
Shader "Example/AlphaTest"
{
Properties
{
_Color ("Main Tint", Color) = (1, 1, 1, 1 )
_MainTex ("Main Tex", 2D) = "white" {}
_Cutoff ("Alpha Cutoff", Range(0, 1)) = 0.5
}
SubShader
{
//TransparentCutout: 指明使用了透明度测试
//不受投影标签的影响
Tags {"Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout"}
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
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;
};
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _Cutoff;
float4 _LightColor0;
v2f vert (a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed4 texColor = tex2D(_MainTex, i.uv);
//透明度测试, 输入值小于0则丢弃该片元
clip(texColor.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);
}
ENDCG
}
}
Fallback "Transparent/Cutout/VertexLit"
}
UnityObjectToClipPos
将顶点从模型空间转到剪裁空间
UnityObjectToWorldNormal
将法线方向从模型空间变换到世界空间
unity_ObjectToWorld
当前模型矩阵
TRANSFORM_TEX
UnityCG.cginc内置宏,变换贴图的平移和缩放的属性到UV:
#define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)
UnityWorldSpaceLightDir
光照模式在ForwardBase下,根据给定在模型空间下的顶点位置,计算朝向光源的世界空间方向。
tex2D
从纹理中获取像素的颜色信息,传入一个纹理和一个二维坐标(通常是纹理坐标),以获取该坐标处的像素颜色。
透明度混合(Alpha Blending)
可以得到真正的半透明效果,使用当前片元的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合,得到新的颜色。需要关闭深度写入,但没有关闭深度测试。
效果
Shader
Shader "Example/AlphaBlend"
{
Properties
{
_Color ("Main Tint", Color) = (1, 1, 1, 1)
_MainTex ("Texture", 2D) = "white" {}
_AlphaScale ("Alpha Scale", Range(0, 1)) = 1
}
SubShader
{
Tags {"Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent"}
// Pass的先后顺序有影响
//开启深度写入,不输出颜色
Pass
{
ZWrite On
ColorMask 0
}
//透明度混合
Pass
{
Tags{"LightMode" = "ForwardBase"}
// 关闭深度写入
ZWrite Off
// 设置Pass的混合模式,SrcAlpha: 片元着色器产生的颜色的混合因子
// OneMinusSrcAlpha 已经存在于颜色缓冲中的颜色的混合因子
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
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;
};
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _AlphaScale;
float4 _LightColor0;
v2f vert (a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return 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);
}
ENDCG
}
}
Fallback "Transparent/VertexLit"
}
使用两个Pass来渲染模型:第一个Pass开启深度写入,但不输出颜色,第二个Pass进行正常的透明度混合。注意写Pass有先后顺序。
使用两个Pass原因是,由于关闭了深度写入,当模型本身有复杂的遮挡关系或是包含了复杂的非凹凸网络,就会因为排序问题产生错误的透明效果。
ColorMask
设置颜色通道的写掩码,ColorMask RGB | A | 0 | 其他任何RGBA的组合,当设置为0时,Pass不写入任何的颜色通道,不会输出颜色。
参考
《Unity Shader入门精要》冯乐乐
内置着色器变量
内置着色器函数