using System; using System.Collections.Generic; using System.Linq; using System.Text; using UnityEngine; using UnityEngine.Rendering; namespace Thousandto.Launcher.ExternalLibs { /// /// 离屏特效 /// public class OffScreenVfxScript :MonoBehaviour { private const CameraEvent CN_TRIGGER_EVENT = CameraEvent.AfterForwardAlpha; private List _renders = new List(); private CommandBuffer _cmd; private Camera _camera; private Material _mat; private int _offScreenTexID; public BlendOp _bop = BlendOp.Blend; private void Start() { InitPropertyID(); InitMat(); InitCamera(); InitCmd(); } private void OnEnable() { if (_cmd != null && _camera != null) { _camera.AddCommandBuffer(CN_TRIGGER_EVENT, _cmd); } if (_cmd != null) { RefreshCameraOrVfx(); } } private void OnDisable() { if (_cmd != null && _camera != null) { _camera.RemoveCommandBuffer(CN_TRIGGER_EVENT, _cmd); } ClearRenderList(); } 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; } ClearRenderList(); } private void OnValidate() { RefreshCmd(); } private void RefreshCameraOrVfx() { var camera = GetComponentsInChildren(false); var render = GetComponentsInChildren(true); if (camera.Length > 0) { OnSceneCameraChanged(camera[0]); } else { OnSceneCameraChanged(null); } if (render.Length > 0) { OnCameraVfxChanged(new List(render)); } else { OnCameraVfxChanged(null); } } private void InitPropertyID() { _offScreenTexID = Shader.PropertyToID("_OffScreenTex"); } private void InitCamera() { _camera = GetComponent(); if (_camera != null) { _camera.forceIntoRenderTexture = true; } } private void InitCmd() { if (_cmd == null) { _cmd = new CommandBuffer(); _cmd.name = "OffScreenVfxCmd"; if (_camera != null) { _camera.AddCommandBuffer(CN_TRIGGER_EVENT, _cmd); } } } private void InitMat() { var sh = RuntimeUtilities.FindShader("Hidden/Ares/PostEffect/OffScreenVfx"); if (sh != null) { _mat = new Material(sh); _mat.hideFlags = HideFlags.DontSave; } else { Debug.LogError("Hidden/Ares/PostEffect/OffScreenVfx"); } } private void RefreshCmd() { if (_cmd != null) { _cmd.Clear(); if (_renders.Count > 0) { _cmd.GetTemporaryRT(_offScreenTexID, -4, -4, 0, FilterMode.Bilinear); _cmd.GetTemporaryRT(CmdBufferUtils.FullScreenTexID, -1, -1, 0, FilterMode.Bilinear); _cmd.SetRenderTarget(_offScreenTexID); _cmd.ClearRenderTarget(true, true, Color.black); //0.把需要处理的模型进行处理 for (int i = 0; i < _renders.Count; i++) { if (_renders[i] != null) { _renders[i].enabled = false; _cmd.DrawRenderer(_renders[i], _renders[i].sharedMaterial); } } //1.把FrameBuffer中的数据进行组合 _cmd.SetGlobalTexture("_OffScreenTex", _offScreenTexID); _cmd.SetGlobalTexture(CmdBufferUtils.MainTexID, BuiltinRenderTextureType.CameraTarget); _cmd.SetRenderTarget(CmdBufferUtils.FullScreenTexID); _cmd.DrawMesh(CmdBufferUtils.QuadMesh, Matrix4x4.identity, _mat,0, (int)_bop); //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(_offScreenTexID); } } } private void OnPostEffectActive(int val) { Debug.LogError("OffScreenVfx:OnPostEffectActive:" + 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); ClearRenderList(); } } } public void OnSceneCameraChanged() { OnSceneCameraChanged(null); } public void OnSceneCameraChanged(object obj) { Camera cam = obj as Camera; Debug.LogError("OnSceneCameraChanged:" + (cam != null ? cam.name : "NULL")); if (_camera != null) { if (_cmd != null) { _camera.RemoveCommandBuffer(CN_TRIGGER_EVENT, _cmd); } } _camera = cam; if (_camera != null) { _camera.forceIntoRenderTexture = true; if (_cmd != null) { _camera.AddCommandBuffer(CN_TRIGGER_EVENT, _cmd); } } } public void OnCameraVfxChanged() { OnCameraVfxChanged(null); } public void OnCameraVfxChanged(object obj) { List list = obj as List; Debug.LogError("OnCameraVfxChanged:" + (list!= null ?list.Count.ToString():"NULL")); ClearRenderList(); if (list != null && list.Count > 0) { _renders.AddRange(list); } RefreshCmd(); } private void ClearRenderList() { for (int i = 0; i < _renders.Count; i++) { _renders[i].enabled = true; } _renders.Clear(); } public enum BlendOp { Blend = 0, Add = 1, Skill = 2, } } }