来源:《UNITY SHADER入门精要》
正如之前所说,为了实现透明度混合,我们必须在绘制半透明物体的时候关闭 深度值写入。Unity已经给我们提供了混合的命令:
我们书中使用的是表中第二种语义,我们会把 SrcFactor
设为 SrcAlpha
,而目标颜色的混合因子 DstFactor
设为 OneMinusSrcAlpha
。那么,混合之后的颜色是:
D s t C o l o r n e w = S r c A l p h a × S r c C o l o r + ( 1 − S r c A l p h a ) × D s t C o l o r o l d DstColor_{new}=SrcAlpha \times SrcColor + (1 - SrcAlpha) \times DstColor_{old} DstColornew=SrcAlpha×SrcColor+(1−SrcAlpha)×DstColorold
Shader "Unity Shaders Book/Chapter 8/Alpha Blend" {
Properties {
_Color ("Color Tint", Color) = (1, 1, 1, 1)
_MainTex ("Main Tex", 2D) = "white" {}
_AlphaScale ("Alpha Scale", Range(0, 1)) = 1
}
我们新增了一个 _AlphaScale
来控制透明度的变化。
SubShader {
Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
Pass {
Tags { "LightMode"="ForwardBase" }
SubShader 的 Tags 中,设置了 "Queue"="Transparent"
使用了Transparent 的渲染队列,RenderType
标签可以让 Unity 把这个 Shader 归入到提前定义的组里面(这里就是 Transparent 组)中,用来指明该 Shader 是一个使用了透明度混合的 Shader。别忘了我们还 设置了 "IgnoreProjector"="True"
,来禁止被投影。
当然 Pass 中光照还是设置为 ForwardBase。
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Pass中采用 Blend 命令
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;
};
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;
}
emmmm维持不变,没啥好说的。
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);
}
唯一变动的部分就是第 13 行,返回的时候,最后一项,用 texColor.a * AlphaScale
构造了最后一项透明度。其他的,因为我们开启了 Blend,Unity会帮我们自动完成。
ENDCG
}
}
FallBack "Transparent/VertexLit"
}
如果一个模型本身就有复杂的结构和网格,就会因为各种排序的问题而且深度值关闭,导致成像有问题:
所以,我们打算采用开启深度值的方法写入半透明效果。我们使用两个 Pass 来渲染模型:第一个 Pass 开启深度写入,但不输出颜色,仅仅是将在最表面的物体写入深度缓冲中。第二个 Pass 就直接依据上一个 Pass 深度值排序的结果来进行渲染。
Shader "Unity Shaders Book/Chapter 8/Alpha Blending With ZWrite" {
Properties {
_Color ("Color 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"}
// Extra pass that renders to depth buffer only
Pass {
ZWrite On
ColorMask 0
}
后面的代码都和前面是一样的,就这里因为多定义了一个Pass,所以不一样了一些,这里 ZWrite On
开启了深度值测试,而后用 ColorMask 0
又关闭了颜色输出。
这里的 ColorMask
的语义是:
ColorMask RGB \ A \ 0 \ 其它任何 R、G、B、A 的任意组合
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;
};
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"
}