街机游戏《幽灵特警》第一关有个这样的效果:
嗯,透视挂hhhh,关键很炫。
来做个吧。
第一步,做“墙”
仔细观察GIF可见,这个效果像是一堵向前跑的墙,撞到无生命物体时(如椅子)只是扫一下光;但撞到敌人就会专门高亮一会。
这效果我是参考了上一次写能量护盾时参考的文章实现的:
UnityShader——屏幕空间的能量罩(模拟守望先锋温斯顿的能量罩),作者:Porco_
主要用到了文章的深度相交算法。
效果如下:
代码如下:
(shader的)
Shader "Unlit/DetectEnemyWall"
{
Properties
{
_Color("主颜色",Color) = (1,1,1,1)
_RimPower("边缘光颜色强度",Range(0,2)) = 1
_IntersectionPower("相交处颜色强度",Range(0,2)) = 1
}
SubShader
{
Tags {
"RenderType"="Transparent" "Queue"="Transparent"}
Pass
{
ZWrite off
Blend one one
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float3 worldPos : TEXCOORD0;
float3 worldNormal : TEXCOORD1;
float4 scrPos : TEXCOORD2;
float2 uv : TEXCOORD3;
};
sampler2D _CameraDepthTexture; // 犯了个错误,忘了写这句接收Camera传来的DepthTexture;
fixed4 _Color;
fixed _RimPower;
fixed _IntersectionPower;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.uv = v.uv;
o.scrPos = ComputeScreenPos(o.vertex);
COMPUTE_EYEDEPTH(o.scrPos.z);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed3 normalDir = normalize(i.worldNormal);
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 rim = (1.0 - saturate(dot(normalDir,viewDir))) * _RimPower;
float ScreenZ = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture,UNITY_PROJ_COORD(i.scrPos)));
fixed intersect = saturate( 1 - (ScreenZ - i.scrPos.z) ) * _IntersectionPower;
fixed v = max(rim,intersect);
return _Color * v;
}
ENDCG
}
}
}
(C#的,这个脚本要挂在摄像机上)
void Start()
{
camera = GetComponent<Camera>();
camera.depthTextureMode = DepthTextureMode.Depth;
}
这个效果涉及到很多深度、裁剪空间有关的知识和内置函数啊、宏啊变量啊啥的。但要命的是我已经忘的差不多了。。。
挨个挨个说吧,也当作给自己补补基础:
1、
sampler2D _CameraDepthTexture; // 犯了个错误,忘了写这句接收Camera传来的DepthTexture;
要通过这句变量声明来接收从Camera传过来的深度纹理。
2、
o.scrPos = ComputeScreenPos(o.vertex)