XRay X光射线效果
实现原理:
通过ZTest(深度测试)判断该物体是否被遮挡,如果被遮挡则为物体被遮挡的片元画上一层 边缘光
,加上 Blend透明混合模式
,实现Xray效果。需通过两个Pass通道来一个画被遮挡住的效果,一个画正常的模型效果,
1.开启深度测试 判断是否被遮挡:
Ztest Greater 含义:深度大于当前缓存的值则开通过,否则舍弃该片源。
在深度测试中,深度值一般用Z表示,范围在0—1之间,深度值越小越靠近相机,深度值越大越靠后,由此我们可以通过深度测试来得知物体是否被遮挡,如果某一个片元满足了ZTest Greater 则说明在该片元的前面已经有物体被渲染且写入了深度。
ZTest的状态有下面几中:
Less | 深度小于当前缓存则通过 |
---|---|
Greater | 深度大于当前缓存则通过 |
LEqual | 深度小于等于当前缓存则通过 |
GEqual | 深度大于等于当前缓存则通过 |
Equal | 深度等于当前缓存则通过 |
NotEqual | 深度不等于当前缓存则通过 |
ZTest Always | 不论如何都通过 |
由此的知,当前片元处于大于当前颜色缓冲区的深度时,说明该物体前面有其他的物体被渲染且已经进行深度写入。所以在这种状态下,我们就可以绘边缘光实现我们的Xray效果了。
2.关闭深度写入:
ZWrite Off
注意:我们只需要开启深度测试,检测是否被遮挡。不需要写入深度。如果写入深度,那么就与深度测试相冲突,ZTest Greater永远不满足,那么我们的XRay效果也不会被绘制出来。
3.开启透明混合,否则渲染出来的片元无法透明化,如下图:
Blend SrcAlpha One
4.忽略阴影投射:
Tags{ "ForceNoShadowCasting" = "true" }
原因:Xray效果不需要阴影。
核心算法:
float rim=1-saturate(dot(NormalDir,ViewDir));
float4 rimColor=_XRayColor*pow(rim,1/_XRayPower);
return rimColor;
其实就是边缘光的算法,博文开始已经有讲到,若对边缘光有所不解 点击 UnityShader边缘光实现。
效果图:
下面附上完整UnityShader:
Shader "Unity/XRay"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Diffuse("Color",Color) =(1,1,1,1)
_XRayColor("XRayColor",Color)=(1,1,1,1)
_XRayPower("XRayPower",float) =0
}
SubShader
{
Tags {"Queue"= "Geometry+1000" "RenderType"="Opaque" }
LOD 100
//Xray效果
Pass
{
Name "Xray"
//忽略阴影,半透明物体不需要阴影,可开启此功能
Tags{ "ForceNoShadowCasting" = "true" }
//开启混合
Blend SrcAlpha One
//不进行任何颜色信息写入
ZWrite Off
//大于深度缓冲池中的颜色深度的片元才进行处理 其他的全部舍弃
ZTest Greater
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
float4 _XRayColor;
float _XRayPower;
struct v2f
{
float4 vertex:SV_POSITION;
float3 normal:TEXCOORD0;
float3 viewDir:TEXCOORD1;
};
v2f vert(appdata_base v)
{
v2f o;
o.vertex=UnityObjectToClipPos(v.vertex);
o.normal= v.normal;
o.viewDir=ObjSpaceViewDir(v.vertex);
return o;
};
fixed4 frag(v2f i):SV_TARGET
{
float3 NormalDir=normalize(i.normal);
float3 ViewDir=normalize(i.viewDir);
float rim=1-saturate(dot(NormalDir,ViewDir));
float4 rimColor=_XRayColor*pow(rim,1/_XRayPower);
return rimColor;
};
ENDCG
}
//正常的漫反射渲染
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
float3 _Diffuse;
struct v2f
{
float4 vertex:SV_POSITION;
float2 uv:TEXCOORD0;
float3 worldPos:TEXCOORD1;
float3 worldNormal:TEXCOORD2;
};
v2f vert(appdata_base v)
{
v2f o;
o.vertex=UnityObjectToClipPos(v.vertex);
o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
o.worldPos=mul(unity_ObjectToWorld,v.vertex);
o.worldNormal=UnityObjectToWorldNormal(v.normal);
return o;
};
fixed4 frag(v2f i):SV_TARGET
{
float3 worldNormalDir=normalize(i.worldNormal);
float3 WorldLightDir=normalize(UnityWorldSpaceLightDir(i.worldNormal));
float3 texColor=tex2D(_MainTex,i.uv);
float3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb*texColor.rgb;
float3 diffuse=_LightColor0.rgb*_Diffuse.rgb*texColor.rgb*(dot(worldNormalDir,WorldLightDir)*0.5+0.5);
float3 color=diffuse+ambient;
return fixed4(color,1);
};
ENDCG
}
}
Fallback "Diffuse"
}
努力积才能,壹叶便成名!