334 lines
10 KiB
C#
334 lines
10 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
|
|
namespace Thousandto.Launcher.ExternalLibs
|
|
{
|
|
/// <summary>
|
|
/// 对标记的特效进行扭曲渲染
|
|
/// </summary>
|
|
[RequireComponent(typeof(Camera))]
|
|
public class DistortVfxScript : MonoBehaviour
|
|
{
|
|
//触发事件
|
|
private const CameraEvent CN_TRIGGER_EVENT = CameraEvent.AfterForwardAlpha;
|
|
|
|
private Camera _camera;
|
|
private CommandBuffer _cmd;
|
|
private Material _mat;
|
|
private int _distortTexID;
|
|
private int _strengthID;
|
|
|
|
//扭曲的强度
|
|
[Range(0.0f, 0.2f)]
|
|
public float DistortStrength = 0.01f;
|
|
|
|
private List<Renderer> _renders;
|
|
private List<RenderVisibleInfo> _visibledRenders = new List<RenderVisibleInfo>();
|
|
private int _visibleCount = 0;
|
|
private CameraInfo _ci = new CameraInfo();
|
|
|
|
private void Start()
|
|
{
|
|
InitPropertyID();
|
|
InitCamera();
|
|
InitMat();
|
|
InitCmd();
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
|
|
if (DistortVfxMarkScript.GetAllRenders(out _renders))
|
|
{
|
|
ConvertRenderVisibleInfo(_renders, _visibledRenders);
|
|
RefreshCmd();
|
|
}
|
|
else
|
|
{
|
|
if (TestVisibled(_visibledRenders))
|
|
{
|
|
RefreshCmd();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
if (_cmd != null && _camera != null)
|
|
{
|
|
_camera.AddCommandBuffer(CN_TRIGGER_EVENT, _cmd);
|
|
}
|
|
RefreshMat();
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
if (_cmd != null && _camera != null)
|
|
{
|
|
_camera.RemoveCommandBuffer(CN_TRIGGER_EVENT, _cmd);
|
|
}
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (_cmd != null)
|
|
{
|
|
if (_camera != null)
|
|
{
|
|
_camera.RemoveCommandBuffer(CN_TRIGGER_EVENT, _cmd);
|
|
}
|
|
_cmd.Release();
|
|
_cmd = null;
|
|
}
|
|
|
|
if (_mat != null)
|
|
{
|
|
GameObject.Destroy(_mat);
|
|
_mat = null;
|
|
}
|
|
}
|
|
|
|
private void OnValidate()
|
|
{
|
|
RefreshMat();
|
|
}
|
|
|
|
private void InitPropertyID()
|
|
{
|
|
_distortTexID = Shader.PropertyToID("_DistortTex");
|
|
_strengthID = Shader.PropertyToID("_Strength");
|
|
}
|
|
|
|
private void InitCamera()
|
|
{
|
|
_camera = GetComponent<Camera>();
|
|
_camera.forceIntoRenderTexture = true;
|
|
_ci.SetCamera(_camera);
|
|
}
|
|
|
|
private void InitCmd()
|
|
{
|
|
if (_cmd == null)
|
|
{
|
|
_cmd = new CommandBuffer();
|
|
_cmd.name = "DistortVfxCmd";
|
|
|
|
if (_camera != null)
|
|
{
|
|
_camera.AddCommandBuffer(CN_TRIGGER_EVENT, _cmd);
|
|
}
|
|
}
|
|
}
|
|
private void InitMat()
|
|
{
|
|
var sh = RuntimeUtilities.FindShader("Hidden/Ares/PostEffect/DistortVfx");
|
|
if (sh != null)
|
|
{
|
|
_mat = new Material(sh);
|
|
_mat.hideFlags = HideFlags.DontSave;
|
|
RefreshMat();
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError("没有找到Shader:Hidden/Ares/PostEffect/DistortVfx");
|
|
}
|
|
}
|
|
|
|
private void RefreshCmd()
|
|
{
|
|
if (_cmd != null)
|
|
{
|
|
_cmd.Clear();
|
|
|
|
if (_visibleCount > 0)
|
|
{
|
|
_cmd.GetTemporaryRT(_distortTexID, -4, -4, 0, FilterMode.Bilinear);
|
|
_cmd.GetTemporaryRT(CmdBufferUtils.FullScreenTexID, -1, -1, 0, FilterMode.Bilinear);
|
|
_cmd.SetRenderTarget(_distortTexID);
|
|
_cmd.ClearRenderTarget(false, true, Color.black);
|
|
//把需要处理的模型进行处理
|
|
for (int i = 0; i < _visibledRenders.Count; i++)
|
|
{
|
|
if (_visibledRenders[i].Render != null && _visibledRenders[i].IsVisible)
|
|
{
|
|
_cmd.DrawRenderer(_visibledRenders[i].Render, _visibledRenders[i].Render.sharedMaterial);
|
|
}
|
|
}
|
|
|
|
//1.把FrameBuffer中的数据进行扭曲处理
|
|
_cmd.SetGlobalTexture("_DistortTex", _distortTexID);
|
|
_cmd.SetGlobalTexture(CmdBufferUtils.MainTexID, BuiltinRenderTextureType.CameraTarget);
|
|
_cmd.SetRenderTarget(CmdBufferUtils.FullScreenTexID);
|
|
_cmd.DrawMesh(CmdBufferUtils.QuadMesh, Matrix4x4.identity, _mat);
|
|
|
|
//2.把扭曲的页面复制到FrameBuffer中.
|
|
_cmd.SetGlobalTexture(CmdBufferUtils.MainTexID, CmdBufferUtils.FullScreenTexID);
|
|
_cmd.SetRenderTarget(BuiltinRenderTextureType.CameraTarget);
|
|
_cmd.DrawMesh(CmdBufferUtils.QuadMesh, Matrix4x4.identity, CmdBufferUtils.BlitMat, 0, 0);
|
|
|
|
_cmd.ReleaseTemporaryRT(CmdBufferUtils.FullScreenTexID);
|
|
_cmd.ReleaseTemporaryRT(_distortTexID);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RefreshMat()
|
|
{
|
|
if (_mat != null)
|
|
{
|
|
_mat.SetFloat(_strengthID, DistortStrength);
|
|
}
|
|
}
|
|
|
|
private void OnPostEffectActive(int val)
|
|
{
|
|
if (_camera != null && _cmd != null)
|
|
{
|
|
//根据激活状态来处理
|
|
if (val > 0)
|
|
{
|
|
_camera.RemoveCommandBuffer(CN_TRIGGER_EVENT, _cmd);
|
|
_camera.AddCommandBuffer(CN_TRIGGER_EVENT, _cmd);
|
|
}
|
|
else
|
|
{
|
|
_camera.RemoveCommandBuffer(CN_TRIGGER_EVENT, _cmd);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ConvertRenderVisibleInfo(List<Renderer> all, List<RenderVisibleInfo> vs)
|
|
{
|
|
vs.Clear();
|
|
for (int i = 0; i < all.Count; i++)
|
|
{
|
|
if (all[i] != null)
|
|
{
|
|
vs.Add(new RenderVisibleInfo()
|
|
{
|
|
Render = all[i],
|
|
IsVisible = false
|
|
});
|
|
}
|
|
}
|
|
TestVisibled(vs);
|
|
}
|
|
|
|
//简单测试,只判断位置是否在摄像机的视图内
|
|
private bool TestVisibled(List<RenderVisibleInfo> vs)
|
|
{
|
|
if (vs.Count <= 0) return false;
|
|
bool result = false;
|
|
var planes = _ci.GetPlanes();
|
|
_visibleCount = 0;
|
|
for (int i = 0; i < vs.Count; i++)
|
|
{
|
|
var rv = vs[i];
|
|
//检测是否在范围内
|
|
var isVisibled = CheckIsVisibled(planes, rv.Render.bounds);
|
|
if (rv.IsVisible != isVisibled)
|
|
{
|
|
rv.IsVisible = isVisibled;
|
|
result = true;
|
|
Debug.Log("是否可视改变:"+isVisibled+"::"+ rv.Render.name);
|
|
}
|
|
|
|
//统计显示的Renderer
|
|
if (rv.IsVisible)
|
|
{
|
|
_visibleCount++;
|
|
}
|
|
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//判断是否显示: 判断位置点 ,当数量少的时候会有优化
|
|
private bool CheckIsVisibled(Camera camera,float near,float far,Bounds bounds)
|
|
{
|
|
var vp = camera.WorldToViewportPoint(bounds.center);
|
|
return vp.x >= 0 && vp.x <= 1 && vp.y >= 0 && vp.y <= 1 && vp.z <= far && vp.z >= near;
|
|
}
|
|
|
|
//判断是否显示 判断AABB 更准确
|
|
private bool CheckIsVisibled(Plane[] planes, Bounds bounds)
|
|
{
|
|
return GeometryUtility.TestPlanesAABB(planes, bounds);
|
|
}
|
|
|
|
//渲染器是否显示的信息
|
|
private class RenderVisibleInfo
|
|
{
|
|
public Renderer Render;
|
|
public bool IsVisible;
|
|
}
|
|
|
|
//摄像机的信息
|
|
private class CameraInfo
|
|
{
|
|
private Camera _camera;
|
|
private Transform _cameraTrans;
|
|
private Plane[] _planes;
|
|
private float _near;
|
|
private float _far;
|
|
private Vector3 _pos;
|
|
private Vector3 _angle;
|
|
private float _fov;
|
|
|
|
public void SetCamera(Camera c)
|
|
{
|
|
_camera = c;
|
|
_cameraTrans = c.transform;
|
|
_near = c.nearClipPlane;
|
|
_far = c.farClipPlane;
|
|
_fov = c.fieldOfView;
|
|
_pos = _cameraTrans.position;
|
|
_angle = _cameraTrans.eulerAngles;
|
|
_planes = GeometryUtility.CalculateFrustumPlanes(_camera);
|
|
}
|
|
|
|
public Plane[] GetPlanes()
|
|
{
|
|
if (_camera != null)
|
|
{
|
|
if (!(FloatIsEquip(ref _near,_camera.nearClipPlane)
|
|
&& FloatIsEquip(ref _far, _camera.farClipPlane)
|
|
&& FloatIsEquip(ref _fov, _camera.fieldOfView)
|
|
&& Vector3IsEquip(ref _pos, _cameraTrans.position)
|
|
&& Vector3IsEquip(ref _angle, _cameraTrans.eulerAngles))
|
|
)
|
|
{
|
|
_planes = GeometryUtility.CalculateFrustumPlanes(_camera);
|
|
}
|
|
return _planes;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private bool Vector3IsEquip(ref Vector3 v1, Vector3 v2)
|
|
{
|
|
var v = v1 - v2;
|
|
if (Mathf.Abs(v.x) > 0.001f || Mathf.Abs(v.y) > 0.001f || Mathf.Abs(v.z) > 0.001f)
|
|
{
|
|
v1 = v2;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private bool FloatIsEquip(ref float f1, float f2)
|
|
{
|
|
if (Mathf.Abs(f1 - f2) > 0.001f)
|
|
{
|
|
f1 = f2;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|