1. 开启深度写入的半透效果
前面提到过,在进行半透物体的渲染时需要关闭深度写入,但是如果物体本身存在复杂的遮挡关系时,关闭深度写入的渲染就会出现问题。
如上图红框中的部分,这种情况下,可以使用开启深度写入的半透渲染方式。
开启深度写入的半透渲染包含两个Pass:
- 第一个Pass开启深度写入,但不输出颜色,目的仅仅是将模型的深度信息写入深度缓存,从而得到正确的遮挡关系
- 第二个Pass进行正常的透明度混合
这里我们通过 ZWrite On 开启深度写入
同时会用到一个新的指令——ColorMask,该指令用于设置颜色通道的写掩码,讲人话就是通知Unity哪些颜色通道不要写入,比如可以设置为 ColorMask RG 即表示不写入RG通道的颜色,只写入BA通道的颜色,设置为ColorMask A 即表示不写入Alpha值,特别的,当设置为 ColorMask 0 时,表示不写入任何颜色值,但此时如果开启了深度写入的话,会正常写入深度信息
Shader如下:
Shader "MyShader/Chapter_8/Chapter_8_KNot_Shader"
{
Properties
{
_Color("Color", Color) = (1,1,1,1)
_Alpha("Alpha", Range(0, 1)) = 0.5
}
SubShader
{
Tags { "Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "True"}
Pass
{
ZWrite On
ColorMask 0
}
Pass
{
Tags {"LightMode" = "ForwardBase"}
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 vertex : SV_POSITION;
float3 worldNormal : TEXCOORD0;
};
fixed4 _Color;
fixed _Alpha;
v2f vert(a2v i)
{
v2f o;
o.vertex = UnityObjectToClipPos(i.vertex);
o.worldNormal = mul(i.normal, (float3x3)unity_WorldToObject);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed3 _ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
float3 _worldNormal = normalize(i.worldNormal);
float3 _worldLight = normalize(_WorldSpaceLightPos0.xyz);
fixed3 _diffuse = _LightColor0.rgb * _Color.xyz * (0.5 * dot(_worldLight, _worldNormal) + 0.5);
return fixed4(_ambient + _diffuse, _Alpha);
}
ENDCG
}
}
}
效果如下
2. 双面渲染的半透效果
在之前的透明度测试和透明度混合的例子中,渲染得到的效果还存在一个明显的问题,就时物体看起来像是只有一个片,这是因为对于透明(或者半透)的物体,应该能透过透明的部分看到物体内部的样子,而之前的Shader中并没有对这种情况做处理
如上图中,被透明度测试剔除的部分,直接看到了后面的地面,但实际上应该看到的是立方体的内部。为了解决这种问题,我们可以使用双面渲染的半透渲染方式。
在双面渲染的半透渲染方式中,同样需要两个Pass:
- 第一个Pass进行正面剔除,只渲染背面,通过设置 Cull Front 来实现
- 第一个Pass进行背面剔除,只渲染正面,通过设置 Cull Back 来实现
这两个Pass中的其他代码都与前文完全一样。另外需要注意的是,由于SubShader是自上而下顺序执行Pass,因此在开启了深度写入的情况下(比如透明度测试),为保证正确的深度关系,需要Cull Front的Pass一定在Cull Back的Pass之上。
双面渲染的透明度测试Shader:
Shader "MyShader/Chapter_8/Chapter_8_AlphaTest_BothSide_Shader"
{
Properties
{
_MainTex("MainTex", 2D) = "white"{}
_AlphaTest("AlphaTest", range(0, 1)) = 0
}
SubShader
{
Tags {"Queue" = "AlphaTest" "IgnoreProjector" = "True" "RenderType" = "TransparentCutout"}
Pass
{
Tags {"LightMode" = "ForwardBase"}
Cull Front
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float3 worldNormal : TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _AlphaTest;
v2f vert(a2v i)
{
v2f o;
o.vertex = UnityObjectToClipPos(i.vertex);
o.worldNormal = mul(i.normal, (float3x3)unity_WorldToObject);
o.uv = TRANSFORM_TEX(i.uv, _MainTex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed3 _ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
float3 _worldNormal = normalize(i.worldNormal);
float3 _worldLight = normalize(_WorldSpaceLightPos0.xyz);
fixed4 _sampledColor = tex2D(_MainTex, i.uv);
clip(_sampledColor.w - _AlphaTest);
fixed3 _diffuse = _LightColor0.rgb * _sampledColor.xyz * (0.5 * dot(_worldLight, _worldNormal) + 0.5);
return fixed4(_ambient + _diffuse, _sampledColor.w);
}
ENDCG
}
Pass
{
Tags {"LightMode" = "ForwardBase"}
Cull Back
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float3 worldNormal : TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _AlphaTest;
v2f vert(a2v i)
{
v2f o;
o.vertex = UnityObjectToClipPos(i.vertex);
o.worldNormal = mul(i.normal, (float3x3)unity_WorldToObject);
o.uv = TRANSFORM_TEX(i.uv, _MainTex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed3 _ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
float3 _worldNormal = normalize(i.worldNormal);
float3 _worldLight = normalize(_WorldSpaceLightPos0.xyz);
fixed4 _sampledColor = tex2D(_MainTex, i.uv);
clip(_sampledColor.w - _AlphaTest);
fixed3 _diffuse = _LightColor0.rgb * _sampledColor.xyz * (0.5 * dot(_worldLight, _worldNormal) + 0.5);
return fixed4(_ambient + _diffuse, _sampledColor.w);
}
ENDCG
}
}
}
效果如下:
双面渲染的透明度混合Shader:
Shader "MyShader/Chapter_8/Chapter_8_AlphaBlend_BothSide_Shader"
{
Properties
{
_MainTex("MainTex", 2D) = "white"{}
}
SubShader
{
Tags { "Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "True"}
Pass
{
Tags {"LightMode" = "ForwardBase"}
Cull Front
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float3 worldNormal : TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert(a2v i)
{
v2f o;
o.vertex = UnityObjectToClipPos(i.vertex);
o.worldNormal = mul(i.normal, (float3x3)unity_WorldToObject);
o.uv = TRANSFORM_TEX(i.uv, _MainTex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed3 _ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
float3 _worldNormal = normalize(i.worldNormal);
float3 _worldLight = normalize(_WorldSpaceLightPos0.xyz);
float4 _mainColor = tex2D(_MainTex, i.uv);
fixed3 _diffuse = _LightColor0.rgb * _mainColor.xyz * (0.5 * dot(_worldLight, _worldNormal) + 0.5);
return fixed4(_ambient + _diffuse, _mainColor.w);
}
ENDCG
}
Pass
{
Tags {"LightMode" = "ForwardBase"}
Cull Back
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float3 worldNormal : TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert(a2v i)
{
v2f o;
o.vertex = UnityObjectToClipPos(i.vertex);
o.worldNormal = mul(i.normal, (float3x3)unity_WorldToObject);
o.uv = TRANSFORM_TEX(i.uv, _MainTex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed3 _ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
float3 _worldNormal = normalize(i.worldNormal);
float3 _worldLight = normalize(_WorldSpaceLightPos0.xyz);
float4 _mainColor = tex2D(_MainTex, i.uv);
fixed3 _diffuse = _LightColor0.rgb * _mainColor.xyz * (0.5 * dot(_worldLight, _worldNormal) + 0.5);
return fixed4(_ambient + _diffuse, _mainColor.w);
}
ENDCG
}
}
}
效果如下: