using Thousandto.Launcher.ExternalLibs; using UnityEngine; using UnityEngine.Rendering; namespace Thousandto.Launcher.ExternalLibs { /// /// 不透明对象的曝光处理. /// 描述: 利用渲染图片的alpha通道,来判断哪些需要曝光哪些不需要,这个只针对不透明的对象(Opaque). /// public class OpaqueBloom { //命令缓存 private CommandBuffer _processCmds; //当前挂载的摄像机 private Camera _camera; //材质球 private Material _mat; //触发事件2 private CameraEvent _triggerEvent = CameraEvent.BeforeImageEffects; //参数:x,y表示偏移处理,z:表示曝光强度 private Vector4 _Params = Vector4.zero; //阈值相关:x:threshold,y:threshold-knee,z:knee*2,w:1/(knee*4) private Vector4 _Threshold = Vector4.zero; private bool _isInited = false; //是否可用 private bool _enabled = true; public bool Enabled { get { return _enabled; } set { if (_enabled != value) { _enabled = value && SystemInfo.supportsImageEffects; } } } public bool IsInited { get { return _isInited; } } //初始化 public void Initialize() { if (!_isInited) { //判断是否支持 _enabled = _enabled && SystemInfo.supportsImageEffects; InitMat(); Debug.Log("Initialize:" + _enabled + ";;;SystemInfo.supportsImageEffects:" + SystemInfo.supportsImageEffects + ";;(_mat != null):" + (_mat != null).ToString()); if (_mat != null) { InitCmd(); _isInited = true; } } } //反初始化 public void UnInitialize() { if (_processCmds != null) { if (_camera != null) { _camera.RemoveCommandBuffer(_triggerEvent, _processCmds); } _processCmds.Release(); _processCmds = null; } if (_mat != null) { GameObject.Destroy(_mat); _mat = null; } } //绑定摄像机 public void BindCamera(Camera cam) { if (_processCmds != null) { if (_camera != null) { _camera.forceIntoRenderTexture = false; _camera.RemoveCommandBuffer(_triggerEvent, _processCmds); } if (cam != null && Enabled) { cam.forceIntoRenderTexture = true; cam.AddCommandBuffer(_triggerEvent, _processCmds); } } _camera = cam; } //设置偏移和强度 public void SetOffsetAndStrength(Vector2 offset, float strength) { _Params = new Vector4(offset.x, offset.y, strength); RefreshMat(); } //设置阈值 public void SeThreshold(float threshold, float knee) { _Threshold = new Vector4(threshold, threshold - knee, knee * 2, 1 / ((knee + 0.0001f) * 4)); RefreshMat(); } //刷新材质球 public void RefreshMat() { if (_mat != null) { _mat.SetVector("_Params", _Params); _mat.SetVector("_Threshold", _Threshold); } } //初始化渲染命令 private void InitCmd() { var mainTexID = CmdBufferUtils.MainTexID; var bloomTexID = Shader.PropertyToID("_BloomTex"); if (_processCmds == null) { _processCmds = new CommandBuffer(); _processCmds.name = "OpaqueBloomCmd"; //准备 _processCmds.GetTemporaryRT(CmdBufferUtils.FullScreenTexID, -1,-1, 0, FilterMode.Bilinear); int tw = Screen.width / 2; int th = Screen.height / 2; int iterations = Mathf.Clamp(Mathf.FloorToInt(Mathf.Log(Mathf.Max(tw, th), 2)), 1, 3); int[] dids = new int[iterations]; int[] uids = new int[iterations]; for (int i = 0; i < iterations; i++) { dids[i] = (Shader.PropertyToID("_CameraBloomEffectTexD" + i)); uids[i] = (Shader.PropertyToID("_CameraBloomEffectTexU" + i)); _processCmds.GetTemporaryRT(dids[i], tw, th, 0, FilterMode.Bilinear); _processCmds.GetTemporaryRT(uids[i], tw, th, 0, FilterMode.Bilinear); tw = tw / 2; th = th / 2; } //0.摄像机的数据读取出来 _processCmds.SetRenderTarget(CmdBufferUtils.FullScreenTexID); _processCmds.SetGlobalTexture(mainTexID, BuiltinRenderTextureType.CameraTarget); _processCmds.DrawMesh(CmdBufferUtils.QuadMesh, Matrix4x4.identity, _mat, 0, 3); //1.过滤一下 _processCmds.SetRenderTarget(dids[0]); _processCmds.SetGlobalTexture(mainTexID, CmdBufferUtils.FullScreenTexID); _processCmds.DrawMesh(CmdBufferUtils.QuadMesh, Matrix4x4.identity, _mat, 0, 0); //2.进行采样处理 for (int i = 0; i < iterations; i++) { //2.1 处理行 _processCmds.SetRenderTarget(uids[i]); _processCmds.SetGlobalTexture(mainTexID, dids[0]); _processCmds.DrawMesh(CmdBufferUtils.QuadMesh, Matrix4x4.identity, _mat, 0, 1); //2.2 处理列 _processCmds.SetRenderTarget(dids[i]); _processCmds.SetGlobalTexture(mainTexID, uids[i]); _processCmds.DrawMesh(CmdBufferUtils.QuadMesh, Matrix4x4.identity, _mat, 0, 2); } //4.先把最后一个复制了 _processCmds.SetRenderTarget(uids[iterations - 1]); _processCmds.SetGlobalTexture(mainTexID, dids[iterations - 1]); _processCmds.DrawMesh(CmdBufferUtils.QuadMesh, Matrix4x4.identity, _mat, 0, 3); //5.把bloom纹理给组合起来 for (int i = iterations - 2; i >= 0; i--) { _processCmds.SetRenderTarget(uids[i]); _processCmds.SetGlobalTexture(mainTexID, uids[i + 1]); _processCmds.SetGlobalTexture(bloomTexID, dids[i]); _processCmds.DrawMesh(CmdBufferUtils.QuadMesh, Matrix4x4.identity, _mat, 0, 4); } //6.把bloom纹理与显示帧的数据给组合起来 _processCmds.SetRenderTarget(BuiltinRenderTextureType.CameraTarget); _processCmds.SetGlobalTexture(mainTexID, CmdBufferUtils.FullScreenTexID); _processCmds.SetGlobalTexture(bloomTexID, uids[0]); _processCmds.DrawMesh(CmdBufferUtils.QuadMesh, Matrix4x4.identity, _mat, 0, 4); _processCmds.SetRenderTarget(uids[0]); //7.释放RT资源 for (int i = 0; i < iterations; i++) { _processCmds.ReleaseTemporaryRT(dids[i]); _processCmds.ReleaseTemporaryRT(uids[i]); } _processCmds.ReleaseTemporaryRT(CmdBufferUtils.FullScreenTexID); if (_camera != null && Enabled) { _camera.forceIntoRenderTexture = true; _camera.AddCommandBuffer(_triggerEvent, _processCmds); } } } //初始化材质球 private void InitMat() { if (_mat == null) { var sh = RuntimeUtilities.FindShader("Hidden/Ares/PostEffect/BloomCmd"); if (sh != null) { _mat = new Material(sh); _mat.hideFlags = HideFlags.DontSave; //初始化材质球 SetOffsetAndStrength(new Vector2(4, 4), 1.5f); SeThreshold(0.9f, 0.5f); RefreshMat(); } else { Debug.LogError("没有找到Shader:Hidden/Ares/PostEffect/BloomCmd,OpaqueBloom无效!"); } } } } }