UnityShader案例篇—光锥扫描效果

一、介绍

      在Unity2018.2.14上,一个实现展示敌方视线扇形光锥效果的Shader,其效果图如图所示,当然这种效果还只是实现了一个视线光锥的简单效果

当这个视线光锥开始扫描的时候,为了表达更加真实的效果,在出现扫描到障碍物的时候,会出现光线被遮挡的效果。如图所示:当光锥扫描到前面的障碍物的时候,会出现光线被遮挡的效果。

二、实现

1、简单半透明扫描扇形光锥Shader代码

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'Shader "ShaderPack/ConeOfSight" {Properties{_Color("Color",Color) = (1,1,1,1)_SightAngle("SightAngle",Float) = 0.5_FarHardness("FarHardness",Float) = 0.5_RangeHardness("RangeHardness",Range(0,100)) = 5_RangeStep("RangeStep",Range(0,1)) = 0.7_SourceWhiteness("SourceWhiteness",Range(0,1)) = 1//_SourceGlow("SourceGlow",Range(1,10)) = 1}SubShader{Tags {"Queue" = "Transparent""RenderType" = "Transparent"}Blend SrcAlpha OneMinusSrcAlphaPass{ZWrite OffCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct v2f {float4 position : SV_POSITION;float4 uv : TEXCOORD0;};half4 _Color;half _SightAngle;half _FarHardness;half _RangeHardness;half _RangeStep;half _SourceWhiteness;//half _SourceGlow;//uniform half _CurrentAngle = 0;//int _BufferSize = 64;uniform float _SightDepthBuffer[256];//Vertexv2f vert(appdata_base IN) {v2f o;o.position = UnityObjectToClipPos(IN.vertex);o.uv = IN.texcoord;return o;}//Fragmentfixed4 frag(v2f IN) : SV_Target{const float PI = 3.14159;IN.uv.x -= 0.5f;IN.uv.y -= 0.5f;half distcenter = 1 - sqrt(IN.uv.x*IN.uv.x + IN.uv.y*IN.uv.y) * 2;half2 fragmentDir = normalize(IN.uv.xy);half viewDotPos = clamp(dot(half2(1,0), fragmentDir),0,1);half sightAngleRads = _SightAngle / 2 * PI / 180;half sightVal = cos(sightAngleRads);half4 col = lerp(_Color,half4(1,1,1,1),distcenter*_SourceWhiteness);col.a *= pow(viewDotPos / sightVal,_RangeHardness) *distcenter * pow(distcenter,_FarHardness);//col.a *= clamp(distcenter*abs(pow(col.a,-_FarHardness*10)),0,1);if (viewDotPos < sightVal) {col.a *= _RangeStep;}else {// --- Depth checkfloat fragmentAngle = asin(fragmentDir.y) + sightAngleRads;float fragmentVal = 1.0f - (fragmentAngle) / (sightAngleRads * 2);int index = fragmentVal * 256;if (_SightDepthBuffer[index] > 0 && (1 - distcenter) > _SightDepthBuffer[index])col *= 0;}col.a *= _Color.a;return col;}ENDCG}}}

这个Shader只是实现了静态的扇形扫描光锥效果,接下来还有实现光锥转动的时候扫描到障碍物时候的效果。

2、动态扫描

先将光锥的角度进行微分处理,每个单位角度的方向指定距离处得到一个点。由物体向该点发射一个射线,进行射线检测。射线碰到有碰撞体的物体就会得到一个碰撞点,然后将点与扫描半径的比值赋给Shader代码里的深度缓存数组  m_aDepthBuffer。如果没有碰撞到障碍物则赋值为-1。在Shader代码里

		if (_SightDepthBuffer[index] > 0 && (1 - distcenter) > _SightDepthBuffer[index])col *= 0;

进行判断的时候就会将碰撞到障碍物的后面的透明度都设置为0,这样就实现了光线被遮挡的效果。代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;public class ConeOfSight : MonoBehaviour {public float SightAngle;public float MaxDistance;public const int BUFFER_SIZE = 256;private float[] m_aDepthBuffer;[SerializeField]private Material m_ConeOfSightMat;[SerializeField]private float rotSpeed;// Use this for initializationvoid Start () {m_aDepthBuffer = new float[BUFFER_SIZE];}// Update is called once per framevoid Update () {}private void FixedUpdate(){transform.Rotate(Vector3.up * rotSpeed * Time.fixedDeltaTime);UpdateViewDepthBuffer();}private void UpdateViewDepthBuffer(){float tempAngleStep = SightAngle / BUFFER_SIZE;float tempViewAngle = transform.eulerAngles.y;int tempBufferIndex = 0;for (int i = 0; i < BUFFER_SIZE; i++){float tempAngle = tempAngleStep * i + (tempViewAngle - SightAngle / 2.0f);Vector3 tempDest = GetVector(-tempAngle * Mathf.Deg2Rad, MaxDistance);Ray tempRay = new Ray(transform.position, tempDest);RaycastHit tempHit = new RaycastHit();if(Physics.Raycast(tempRay,out tempHit)){m_aDepthBuffer[tempBufferIndex] = (tempHit.distance / MaxDistance);// Debug.DrawRay(transform.position, tempHit.point, Color.red);}else{m_aDepthBuffer[tempBufferIndex] = -1;//Debug.DrawRay(transform.position, tempDest);}tempBufferIndex++;}m_ConeOfSightMat.SetFloatArray("_SightDepthBuffer", m_aDepthBuffer);}private void OnDrawGizmos(){Handles.color = Color.yellow;Handles.DrawWireArc(transform.localPosition, transform.up, Vector3.right, 360, MaxDistance);float halfangle = SightAngle * Mathf.Deg2Rad / 2.0f;float viewangle = transform.rotation.eulerAngles.y * Mathf.Deg2Rad;Vector3 p1 = GetVector(-halfangle - viewangle, MaxDistance);Vector3 p2 = GetVector(halfangle - viewangle, MaxDistance);// Handles.DrawLine(myObj.transform.position, p1);//  Handles.DrawLine(myObj.transform.position, p2);Debug.DrawRay(transform.position, p1);Debug.DrawRay(transform.position, p2);}public Vector3 GetVector(float angle, float dist){float x = Mathf.Cos(angle) * dist;float z = Mathf.Sin(angle) * dist;return new Vector3(x, 0, z);}
}

 三、总结

1、实现了光锥扫描到障碍物的动态效果

2、不足之处是该扫描效果紧紧是水平面的效果,不能做到立体的效果

3、工程下载地址https://download.csdn.net/download/zhangxiao13627093203/13076185

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部