效果:
shader:
Shader "LSQ/EffectAchievement/GlobalScanEffect"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
}
SubShader
{
Cull Off ZWrite Off ZTest Always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float4 ray : TEXCOORD1;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float4 ray : TEXCOORD2;
};
sampler2D _MainTex;
sampler2D _CameraDepthTexture;
float3 _ScanCenterPos;
float _ScanRadius;
float _ScanWidth;
float4 _HeadColor;
float4 _TrailColor;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.ray = v.ray;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
float depth = Linear01Depth(DecodeFloatRG(tex2D(_CameraDepthTexture, i.uv)));
float4 toCameraVector = depth * i.ray;
float3 worldPos = _WorldSpaceCameraPos + toCameraVector;
float outerRing = _ScanRadius + _ScanWidth * 0.5;
float innerRing = _ScanRadius - _ScanWidth * 0.5;
float distanceToCenter = distance(_ScanCenterPos, worldPos);
float value = smoothstep(innerRing, outerRing, distanceToCenter);
fixed4 ringColor;
if(value >= 1 || value <= 0)
{
value = 0;
ringColor = float4(1,1,1,1);
}
else
{
ringColor = lerp(_TrailColor, _HeadColor, value);
}
return col * ringColor;
}
ENDCG
}
}
}
C#:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GlobalScanEffect : PostEffectsBase
{
public float startScanRange = 0;
public float maxScanRange = 20;
public float scanWidth = 3;
public float scanSpeed = 1;
public Color headColor;
public Color trailColor;
private bool isInScan = false;
private Vector3 centerPos;
private float scanRadius;
private IEnumerator scanHandler = null;
void OnEnable()
{
scanRadius = startScanRange;
Camera.depthTextureMode = DepthTextureMode.Depth;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
centerPos = hit.point;
if (scanRadius <= startScanRange)
{
Scan();
}
else
{
ScanBack();
}
}
}
}
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (Material != null && isInScan)
{
Material.SetVector("_ScanCenterPos", centerPos);
Material.SetFloat("_ScanRadius", scanRadius);
Material.SetFloat("_ScanWidth", scanWidth);
Material.SetColor("_HeadColor", headColor);
Material.SetColor("_TrailColor", trailColor);
RaycastCornerBlit(source, destination, Material);
}
else
{
Graphics.Blit(source, destination);
}
}
void RaycastCornerBlit(RenderTexture source, RenderTexture dest, Material mat)
{
float CameraFar = Camera.farClipPlane;
float CameraFov = Camera.fieldOfView;
float CameraAspect = Camera.aspect;
float fovWHalf = CameraFov * 0.5f;
Vector3 toRight = Camera.transform.right * Mathf.Tan(fovWHalf * Mathf.Deg2Rad) * CameraAspect;
Vector3 toTop = Camera.transform.up * Mathf.Tan(fovWHalf * Mathf.Deg2Rad);
Vector3 topLeft = (Camera.transform.forward - toRight + toTop);
float CameraScale = topLeft.magnitude * CameraFar;
topLeft.Normalize();
topLeft *= CameraScale;
Vector3 topRight = (Camera.transform.forward + toRight + toTop);
topRight.Normalize();
topRight *= CameraScale;
Vector3 bottomRight = (Camera.transform.forward + toRight - toTop);
bottomRight.Normalize();
bottomRight *= CameraScale;
Vector3 bottomLeft = (Camera.transform.forward - toRight - toTop);
bottomLeft.Normalize();
bottomLeft *= CameraScale;
RenderTexture.active = dest;
mat.SetTexture("_MainTex", source);
GL.PushMatrix();
GL.LoadOrtho();
mat.SetPass(0);
GL.Begin(GL.QUADS);
GL.MultiTexCoord2(0, 0.0f, 0.0f);
GL.MultiTexCoord(1, bottomLeft);
GL.Vertex3(0.0f, 0.0f, 0.0f);
GL.MultiTexCoord2(0, 1.0f, 0.0f);
GL.MultiTexCoord(1, bottomRight);
GL.Vertex3(1.0f, 0.0f, 0.0f);
GL.MultiTexCoord2(0, 1.0f, 1.0f);
GL.MultiTexCoord(1, topRight);
GL.Vertex3(1.0f, 1.0f, 0.0f);
GL.MultiTexCoord2(0, 0.0f, 1.0f);
GL.MultiTexCoord(1, topLeft);
GL.Vertex3(0.0f, 1.0f, 0.0f);
GL.End();
GL.PopMatrix();
}
void CheckAndBlock()
{
if (scanHandler != null)
{
StopCoroutine(scanHandler);
}
}
void Scan()
{
CheckAndBlock();
scanHandler = ScanCoroutine();
StartCoroutine(scanHandler);
}
void ScanBack()
{
CheckAndBlock();
scanHandler = ScanBackCoroutine();
StartCoroutine(scanHandler);
}
private IEnumerator ScanCoroutine()
{
isInScan = true;
while (scanRadius < maxScanRange)
{
scanRadius += scanSpeed;
yield return new WaitForSecondsRealtime(.01f);
}
scanRadius = maxScanRange;
isInScan = false;
}
private IEnumerator ScanBackCoroutine()
{
isInScan = true;
while (scanRadius > startScanRange)
{
scanRadius -= scanSpeed;
yield return new WaitForSecondsRealtime(.01f);
}
scanRadius = startScanRange;
isInScan = false;
}
}
|