using System; using System.Reflection; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; // Unit效果之一,镜头效果,通过command buffer实现 public class UnitLensEffect : UnitComponent { private List renderers; private static ObjectPool m_CommandBufferPool; private List m_Effects; // 每个角色维护单独的command buffers,而不是共享command buffer。有一定开销,但不重要。 private Dictionary m_InUseCommandBuffers; private Dictionary m_CachedCommandBuffers; static UnitLensEffect() { m_CommandBufferPool = new ObjectPool(null, null); } public override void Initialize() { base.Initialize(); renderers = new List(); m_Effects = new List(); m_InUseCommandBuffers = new Dictionary(); m_CachedCommandBuffers = new Dictionary(); } public override void OnPostInitialize() { base.OnPostInitialize(); IBodyRendererAgent body = owner.unitRender.body; if (body == null || body.renderers == null) return; for (int i = 0; i < body.renderers.Length; ++i) { var renderer = body.renderers[i]; if (renderer == null) continue; RendererProxy proxy = renderer.renderer.gameObject.GetOrAddComponent(); proxy.Initialize(renderer); proxy.onWillRenderObject = OnWillRenderObj; proxy.onRenderObject = OnRenderObj; renderers.Add(proxy); } MainCamera.Instance.customRenderingPipeline.onPreCull += OnWillRenderUnit; MainCamera.Instance.customRenderingPipeline.onPostRender += OnRenderUnit; ///// //m_Effects.Add(new LensEffect_MotionBlur()); m_Effects.Add(new LensEffect_BlurRim()); } public override void Release() { base.Release(); MainCamera.Instance.customRenderingPipeline.onPreRender -= OnWillRenderUnit; MainCamera.Instance.customRenderingPipeline.onPostRender -= OnRenderUnit; } private void OnWillRenderUnit() { PrepareCommandBuffers(); IBodyRendererAgent body = owner.unitRender.body; if (body == null || body.renderers == null) return; if (m_Effects == null || m_Effects.Count == 0) return; foreach (var cb in m_InUseCommandBuffers) { cb.Value.Clear(); ERenderingEvent re = cb.Key; CameraEvent ce = re.ToCameraEvent(); for (int i = 0; i < m_Effects.Count; ++i) { LensEffectBase eff = m_Effects[i]; if (!eff.renderingEvents.HasFlag(re)) continue; MethodInfo method = eff.GetType().GetMethod(re.ToString(), BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(LensEffectBase.EStage), typeof(CommandBuffer) }, null); if (method == null) continue; eff.owner = owner; method.Invoke(eff, new object[] { LensEffectBase.EStage.Before, cb.Value }); for (int j = 0; j < body.renderers.Length; ++j) { var renderer = body.renderers[j]; if (renderer == null) continue; eff.curBodypartRenderer = renderer; method.Invoke(eff, new object[] { LensEffectBase.EStage.Iterate, cb.Value }); } method.Invoke(eff, new object[] { LensEffectBase.EStage.After, cb.Value }); } MainCamera.Instance.camera.AddCommandBuffer(ce, cb.Value); } } private void OnRenderUnit() { // 执行每个event的finish foreach (var cb in m_InUseCommandBuffers) { ERenderingEvent re = cb.Key; for (int i = 0; i < m_Effects.Count; ++i) { LensEffectBase eff = m_Effects[i]; if (!eff.renderingEvents.HasFlag(re)) continue; MethodInfo method = eff.GetType().GetMethod(re.ToString(), BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(LensEffectBase.EStage), typeof(CommandBuffer) }, null); if (method == null) continue; method.Invoke(eff, new object[] { LensEffectBase.EStage.Finished, cb.Value }); } } for (int i = 0; i < m_Effects.Count; ++i) { LensEffectBase eff = m_Effects[i]; MethodInfo method = eff.GetType().GetMethod("OnRenderFinish", BindingFlags.Instance | BindingFlags.Public); if (method == null) continue; method.Invoke(eff, new object[] { }); } foreach (var cb in m_InUseCommandBuffers) { CameraEvent ce = cb.Key.ToCameraEvent(); MainCamera.Instance.camera.RemoveCommandBuffer(ce, cb.Value); } var temp = m_CachedCommandBuffers; m_CachedCommandBuffers = m_InUseCommandBuffers; m_InUseCommandBuffers = temp; } private void OnWillRenderObj(BodyPartRenderer renderer) { } private void OnRenderObj(BodyPartRenderer renderer) { } void PrepareCommandBuffers() { ERenderingEvent usedEvent = ERenderingEvent.None; for (int i = 0; i < m_Effects.Count; ++i) { usedEvent |= m_Effects[i].renderingEvents; } foreach(ERenderingEvent evt in Enum.GetValues(typeof(ERenderingEvent))) { if (evt == ERenderingEvent.None) continue; if(usedEvent.HasFlag(evt)) { CommandBuffer cb; if(m_CachedCommandBuffers.TryGetValue(evt, out cb)) { m_CachedCommandBuffers.Remove(evt); } else { cb = m_CommandBufferPool.Get(); cb.name = evt.ToString(); } m_InUseCommandBuffers.Add(evt, cb); } } foreach(var cb in m_CachedCommandBuffers) { m_CommandBufferPool.Release(cb.Value); } m_CachedCommandBuffers.Clear(); } static CommandBuffer ClaimCommandBuffer() { CommandBuffer cb = m_CommandBufferPool.Get(); cb.Clear(); return cb; } static void ReleaseCommandBuffer(ref CommandBuffer cb) { m_CommandBufferPool.Release(cb); cb = null; } }