一、这种是只要有遮挡就显示。
遮挡显示需要两个Pass,第一个Pass用于占坑,第二个Pass用于正常输出。
Shader "Custom/Test0"
{
Properties
{
_MainColor("主颜色",Color)=(1,1,1,1)
}
SubShader
{
Tags{"Queue"="Overlay"}
//正常漫反射
Pass
{
//ZWrite off
//深度值更大的通过测试,同时写入深度缓存
ZTest Greater
ZWrite On
//没有必要输入颜色值
ColorMask 0
}
Pass
{
//正常渲染
Tags
{
"LightMode"="ForwardBase" "Queue"="Overlay"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc"
fixed4 _MainColor;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f
{
float4 pos:SV_POSITION;
float3 worldNormal :COLOR;
};
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
return o;
}
fixed4 frag(v2f i):SV_Target
{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb * _MainColor.rgb *
(dot(worldLight, worldNormal) * 0.5 + 0.5);
return fixed4(diffuse + ambient, 1);
}
ENDCG
}
}
}
这种算是最简单的写法了。
一般我们需要被遮挡的时候显示一下轮廓什么的。
这时候第一个Pass的作用就不只是占坑,我们还需要关闭深度写入用于做一些特殊处理。
Shader "Custom/Test0"
{
Properties
{
_MainColor("主颜色",Color)=(1,1,1,1)
_FresnelPow("菲涅尔次幂",Float)=1.0
_FresnelStrength("菲涅尔次幂",Float)=1.0
}
SubShader
{
Tags{"Queue"="Overlay"}
//正常漫反射
Pass
{
//ZWrite off
//深度值更大的通过测试,同时写入深度缓存
ZTest Greater
ZWrite off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
fixed4 _MainColor;
fixed _FresnelPow;
fixed _FresnelStrength;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f
{
float4 pos:SV_POSITION;
float4 worldPos:TEXCOORD0;
float3 worldNormal :COLOR;
};
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldPos=mul(unity_ObjectToWorld,v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
return o;
}
fixed4 frag(v2f i):SV_Target
{
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldViewDir=normalize(+_WorldSpaceCameraPos-i.worldPos);
fixed fresnel=pow(1-dot(worldNormal,worldViewDir),_FresnelPow)*_FresnelStrength;
return fixed4(1,1,1, fresnel);
}
ENDCG
}
Pass
{
Tags
{
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc"
fixed4 _MainColor;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f
{
float4 pos:SV_POSITION;
float3 worldNormal :COLOR;
};
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
return o;
}
fixed4 frag(v2f i):SV_Target
{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb * _MainColor.rgb *
(dot(worldLight, worldNormal) * 0.5 + 0.5);
return fixed4(diffuse+ambient, 1);
}
ENDCG
}
}
}
这种遮挡显示一般适用于3D游戏,只要挡住了全给显示出来。
还有一种给处理方式就是遮挡的话把遮挡物给透明处理了,这个用射线检测可能会更好,shader的实现没想到,主要是遮没遮挡只能通过人物判断,你一判断人物,遮挡物的信息就丢失了,但如果反过来判断遮挡物,那么人物遮没遮住就不知道了。
这种渲染一般都很少用,一般有遮挡都会让摄像机移动,因为游戏里面加这种菲涅尔透视效果怪怪的。
二、因为场景导致的穿模遮挡
根据我平常玩的游戏还有一种东西,这种时候遮挡需要处理的和前面不一样,前面的是只要遮挡必渲染,这种需要按总体前后顺序渲染,解决穿模现象。
2D和3D的结合,如明日方舟,2D人物是斜插在场景中的,那个柱子理论上是要挡住人物的头部,但我们需要把它显示出来,但如果是柱子上面正常挡住的角色那就正常挡住即可。
这种就是属于 强制按从后到前的顺序渲染,然后把深度值强行按这个顺序写进去,这意味着人物要和柱子放一个渲染队列。
Shader "Custom/Test0"
{
Properties
{
_MainColor("主颜色",Color)=(1,1,1,1)
}
SubShader
{
Tags{"Queue"="Overlay"}
Pass
{
ZTest Always
ZWrite on
ColorMask 0
}
Pass
{
Tags
{
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc"
fixed4 _MainColor;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL;
};
struct v2f
{
float4 pos:SV_POSITION;
float3 worldNormal :COLOR;
};
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
return o;
}
fixed4 frag(v2f i):SV_Target
{
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb * _MainColor.rgb *
(dot(worldLight, worldNormal) * 0.5 + 0.5);
return fixed4(diffuse+ambient, 1);
}
ENDCG
}
}
}
但我看了明日方舟之前的技术会,他们的实现不是这种,是把人物立起来,用立起来的深度值去做深度测试,然后再斜着渲染,我也不知道怎么实现。
结果应该是没问题的反正试了很多种情况,前面的猴头是插进中间的猴头的,后面的猴头是没插进去的,按前后顺序正常渲染,不确定明日方舟开发者是不是还遇到其他问题了。