一、深度测试与深度写入
深度:像素距离摄像机的远近,离摄像机越近,深度越小;离摄像机越远,深度越大;
默认深度值为 1
深度测试(ZTest):将当前像素的深度值与深度缓冲中的深度值进行比较,满足条件则通过测试;比较的语法有Less、Greater、Equal等
深度写入(ZWrite):前提是已经通过了深度测试
例如:ZWrite On / ZWrite Off
在制作半透明的效果时一般将深度写入关闭 (ZWrite Off)
Pass
{
ZWrite On; //代表写入最前面的深度
ColorMask 0 //代表不写入任何颜色
}在半透明模型的Shader中增加上面Pass,可以解决复杂模型在实现半透明效果时出现背面的情况
- 待解决的问题:
突然灵感一来,想到了为什么会出现这样的效果
如图三,因为当前一个Pass打开深度写入后,深度缓冲中的默认值为该模型最前面像素的深度值(也就是离摄像机最近的模型像素的深度值),在当渲染下一个Pass时,当条件为Greater(大于)通过测试时,这时只会渲染比离摄像机最近模型的深度值还大的地方,所以就等会出现如图三所式的情况
所以如图二,关闭前一个Pass的深度写入后就不会出现这样的效果
图四,前一个Pass打开深度写入后,在下一个Pass中当深度测试为小于时,当前Pass模型的所有像素的深度值,不是等于就是大于深度缓冲中的值,所以全部不通过(离摄像机越近,深度值越小)
图五,深度测试为小于等于时,离摄像机最近的模型像素的深度值等于当前深度缓冲中的深度值,通过测试,但是后面的模型像素的深度值大于当前深度缓冲中的深度值,测试不通过,这样就解决了半透明模型渲染出背面的问题
但是,此时还没有想到能够解决图一中所示情况的有效办法!!!!!
二、菲尼尔效果实现
菲尼尔:1-dot(N,V)
float3 N=normalize(i.worldNormal);
float3 V=normalize(_WorldSpaceCameraPos-i.worldPos);
流光效果的实现:
float v=frac(i.worldPos.y*2+_Time.y);
c*=v;
代码:
Shader"unity/practices01"
{
Properties
{
_Kd("Kd",float)=1
_Kd2("Kd2",float)=1
[Enum(UnityEngine.Rendering.BlendMode)]_DstBlend("DstBlend",int)=0
[Enum(UnityEngine.Rendering.BlendMode)]_SrcBlend("SrcBlend",int)=0
[Enum(UnityEngine.Rendering.CompareFunction)]_ZTest("ZTest",int)=0
_Color("Color",Color)=(1,1,1,1)
}
SubShader
{
// Pass
// {
// ZWrite On
// ColorMask 0
// }
Tags{"Queue"="Transparent"}
Blend [_DstBlend] [_SrcBlend]
Pass
{
ZTest [_ZTest]
ZWrite Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float _Kd;
float _Kd2;
float4 _Color;
struct appdate
{
float4 vertex : POSITION;
float4 uv : TEXCOORD;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float4 uv : TEXCOORD;
float3 worldNormal : TEXCOORD1;
float4 worldPos : TEXCOORD2;
};
v2f vert(appdate v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.uv=v.uv;
o.worldNormal=UnityObjectToWorldNormal(v.normal);
o.worldPos=mul(unity_ObjectToWorld,v.vertex);
return o;
}
float4 frag(v2f i):SV_Target
{
float4 c=float4(1,1,1,1);
float3 N=normalize(i.worldNormal);
float3 V=normalize(_WorldSpaceCameraPos-i.worldPos);
float fresnel=_Kd2*pow(1-dot(N,V),_Kd);
c=fresnel*_Color;
float v=frac(i.worldPos.y*2+_Time.y);
c*=v;
return c;
}
ENDCG
}
}
}
三、Pass的复用
在需要使用的Pass中添加
Name "X"
在需要引用上面Pass的SubShader中添加
UsePass "unity/XXXX/X" // 路径 (Pass的复用)