| using System; | 
| using System.Collections.Generic; | 
| using UnityEngine.Rendering; | 
|   | 
| namespace UnityEngine.PostProcessing | 
| { | 
|     using DebugMode = BuiltinDebugViewsModel.Mode; | 
|   | 
| #if UNITY_5_4_OR_NEWER | 
|     [ImageEffectAllowedInSceneView] | 
| #endif | 
|     [RequireComponent(typeof(Camera)), DisallowMultipleComponent, ExecuteAlways] | 
|     [AddComponentMenu("Effects/Post-Processing Behaviour", -1)] | 
|     public class PostProcessingBehaviour : MonoBehaviour | 
|     { | 
|         // Inspector fields | 
|         public PostProcessingProfile profile; | 
|   | 
|         public Func<Vector2, Matrix4x4> jitteredMatrixFunc; | 
|   | 
|         // Internal helpers | 
|         Dictionary<Type, KeyValuePair<CameraEvent, CommandBuffer>> m_CommandBuffers; | 
|         List<PostProcessingComponentBase> m_Components; | 
|         Dictionary<PostProcessingComponentBase, bool> m_ComponentStates; | 
|   | 
|         MaterialFactory m_MaterialFactory; | 
|         RenderTextureFactory m_RenderTextureFactory; | 
|         PostProcessingContext m_Context; | 
|         Camera m_Camera; | 
|         PostProcessingProfile m_PreviousProfile; | 
|   | 
|         bool m_RenderingInSceneView = false; | 
|   | 
|         // Effect components | 
|         BuiltinDebugViewsComponent m_DebugViews; | 
|         AmbientOcclusionComponent m_AmbientOcclusion; | 
|         ScreenSpaceReflectionComponent m_ScreenSpaceReflection; | 
|         FogComponent m_FogComponent; | 
|         MotionBlurComponent m_MotionBlur; | 
|         TaaComponent m_Taa; | 
|         EyeAdaptationComponent m_EyeAdaptation; | 
|         DepthOfFieldComponent m_DepthOfField; | 
|         BloomComponent m_Bloom; | 
|         ChromaticAberrationComponent m_ChromaticAberration; | 
|         ColorGradingComponent m_ColorGrading; | 
|         UserLutComponent m_UserLut; | 
|         GrainComponent m_Grain; | 
|         VignetteComponent m_Vignette; | 
|         DitheringComponent m_Dithering; | 
|         FxaaComponent m_Fxaa; | 
|   | 
|         void OnEnable() | 
|         { | 
|             m_CommandBuffers = new Dictionary<Type, KeyValuePair<CameraEvent, CommandBuffer>>(); | 
|             m_MaterialFactory = new MaterialFactory(); | 
|             m_RenderTextureFactory = new RenderTextureFactory(); | 
|             m_Context = new PostProcessingContext(); | 
|   | 
|             // Keep a list of all post-fx for automation purposes | 
|             m_Components = new List<PostProcessingComponentBase>(); | 
|   | 
|             // Component list | 
|             m_DebugViews = AddComponent(new BuiltinDebugViewsComponent()); | 
|             m_AmbientOcclusion = AddComponent(new AmbientOcclusionComponent()); | 
|             m_ScreenSpaceReflection = AddComponent(new ScreenSpaceReflectionComponent()); | 
|             m_FogComponent = AddComponent(new FogComponent()); | 
|             m_MotionBlur = AddComponent(new MotionBlurComponent()); | 
|             m_Taa = AddComponent(new TaaComponent()); | 
|             m_EyeAdaptation = AddComponent(new EyeAdaptationComponent()); | 
|             m_DepthOfField = AddComponent(new DepthOfFieldComponent()); | 
|             m_Bloom = AddComponent(new BloomComponent()); | 
|             m_ChromaticAberration = AddComponent(new ChromaticAberrationComponent()); | 
|             m_ColorGrading = AddComponent(new ColorGradingComponent()); | 
|             m_UserLut = AddComponent(new UserLutComponent()); | 
|             m_Grain = AddComponent(new GrainComponent()); | 
|             m_Vignette = AddComponent(new VignetteComponent()); | 
|             m_Dithering = AddComponent(new DitheringComponent()); | 
|             m_Fxaa = AddComponent(new FxaaComponent()); | 
|   | 
|             // Prepare state observers | 
|             m_ComponentStates = new Dictionary<PostProcessingComponentBase, bool>(); | 
|   | 
|             foreach (var component in m_Components) | 
|                 m_ComponentStates.Add(component, false); | 
|   | 
|             useGUILayout = false; | 
|         } | 
|   | 
|         void OnPreCull() | 
|         { | 
|             // All the per-frame initialization logic has to be done in OnPreCull instead of Update | 
|             // because [ImageEffectAllowedInSceneView] doesn't trigger Update events... | 
|   | 
|             m_Camera = GetComponent<Camera>(); | 
|   | 
|             if (profile == null || m_Camera == null) | 
|                 return; | 
|   | 
| #if UNITY_EDITOR | 
|             // Track the scene view camera to disable some effects we don't want to see in the | 
|             // scene view | 
|             // Currently disabled effects : | 
|             //  - Temporal Antialiasing | 
|             //  - Depth of Field | 
|             //  - Motion blur | 
|             m_RenderingInSceneView = UnityEditor.SceneView.currentDrawingSceneView != null | 
|                 && UnityEditor.SceneView.currentDrawingSceneView.camera == m_Camera; | 
| #endif | 
|   | 
|             // Prepare context | 
|             var context = m_Context.Reset(); | 
|             context.profile = profile; | 
|             context.renderTextureFactory = m_RenderTextureFactory; | 
|             context.materialFactory = m_MaterialFactory; | 
|             context.camera = m_Camera; | 
|   | 
|             // Prepare components | 
|             m_DebugViews.Init(context, profile.debugViews); | 
|             m_AmbientOcclusion.Init(context, profile.ambientOcclusion); | 
|             m_ScreenSpaceReflection.Init(context, profile.screenSpaceReflection); | 
|             m_FogComponent.Init(context, profile.fog); | 
|             m_MotionBlur.Init(context, profile.motionBlur); | 
|             m_Taa.Init(context, profile.antialiasing); | 
|             m_EyeAdaptation.Init(context, profile.eyeAdaptation); | 
|             m_DepthOfField.Init(context, profile.depthOfField); | 
|             m_Bloom.Init(context, profile.bloom); | 
|             m_ChromaticAberration.Init(context, profile.chromaticAberration); | 
|             m_ColorGrading.Init(context, profile.colorGrading); | 
|             m_UserLut.Init(context, profile.userLut); | 
|             m_Grain.Init(context, profile.grain); | 
|             m_Vignette.Init(context, profile.vignette); | 
|             m_Dithering.Init(context, profile.dithering); | 
|             m_Fxaa.Init(context, profile.antialiasing); | 
|   | 
|             // Handles profile change and 'enable' state observers | 
|             if (m_PreviousProfile != profile) | 
|             { | 
|                 DisableComponents(); | 
|                 m_PreviousProfile = profile; | 
|             } | 
|   | 
|             CheckObservers(); | 
|   | 
|             // Find out which camera flags are needed before rendering begins | 
|             // Note that motion vectors will only be available one frame after being enabled | 
|             var flags = context.camera.depthTextureMode; | 
|             foreach (var component in m_Components) | 
|             { | 
|                 if (component.active) | 
|                     flags |= component.GetCameraFlags(); | 
|             } | 
|   | 
|             context.camera.depthTextureMode = flags; | 
|   | 
|             // Temporal antialiasing jittering, needs to happen before culling | 
|             if (!m_RenderingInSceneView && m_Taa.active && !profile.debugViews.willInterrupt) | 
|                 m_Taa.SetProjectionMatrix(jitteredMatrixFunc); | 
|         } | 
|   | 
|         void OnPreRender() | 
|         { | 
|             if (profile == null) | 
|                 return; | 
|   | 
|             // Command buffer-based effects should be set-up here | 
|             TryExecuteCommandBuffer(m_DebugViews); | 
|             TryExecuteCommandBuffer(m_AmbientOcclusion); | 
|             TryExecuteCommandBuffer(m_ScreenSpaceReflection); | 
|             TryExecuteCommandBuffer(m_FogComponent); | 
|   | 
|             if (!m_RenderingInSceneView) | 
|                 TryExecuteCommandBuffer(m_MotionBlur); | 
|         } | 
|   | 
|         void OnPostRender() | 
|         { | 
|             if (profile == null || m_Camera == null) | 
|                 return; | 
|   | 
|             if (!m_RenderingInSceneView && m_Taa.active && !profile.debugViews.willInterrupt) | 
|                 m_Context.camera.ResetProjectionMatrix(); | 
|         } | 
|   | 
|         // Classic render target pipeline for RT-based effects | 
|         void OnRenderImage(RenderTexture source, RenderTexture destination) | 
|         { | 
|             if (profile == null || m_Camera == null) | 
|             { | 
|                 Graphics.Blit(source, destination); | 
|                 return; | 
|             } | 
|   | 
|             // Uber shader setup | 
|             bool uberActive = false; | 
|             bool fxaaActive = m_Fxaa.active; | 
|             bool taaActive = m_Taa.active && !m_RenderingInSceneView; | 
|             bool dofActive = m_DepthOfField.active && !m_RenderingInSceneView; | 
|   | 
|             var uberMaterial = m_MaterialFactory.Get("Hidden/Post FX/Uber Shader"); | 
|             uberMaterial.shaderKeywords = null; | 
|   | 
|             var src = source; | 
|             var dst = destination; | 
|   | 
|             if (taaActive) | 
|             { | 
|                 var tempRT = m_RenderTextureFactory.Get(src); | 
|                 m_Taa.Render(src, tempRT); | 
|                 src = tempRT; | 
|             } | 
|   | 
| #if UNITY_EDITOR | 
|             // Render to a dedicated target when monitors are enabled so they can show information | 
|             // about the final render. | 
|             // At runtime the output will always be the backbuffer or whatever render target is | 
|             // currently set on the camera. | 
|             if (profile.monitors.onFrameEndEditorOnly != null) | 
|                 dst = m_RenderTextureFactory.Get(src); | 
| #endif | 
|   | 
|             Texture autoExposure = GraphicsUtils.whiteTexture; | 
|             if (m_EyeAdaptation.active) | 
|             { | 
|                 uberActive = true; | 
|                 autoExposure = m_EyeAdaptation.Prepare(src, uberMaterial); | 
|             } | 
|   | 
|             uberMaterial.SetTexture("_AutoExposure", autoExposure); | 
|   | 
|             if (dofActive) | 
|             { | 
|                 uberActive = true; | 
|                 m_DepthOfField.Prepare(src, uberMaterial, taaActive, m_Taa.jitterVector, m_Taa.model.settings.taaSettings.motionBlending); | 
|             } | 
|   | 
|             if (m_Bloom.active) | 
|             { | 
|                 uberActive = true; | 
|                 m_Bloom.Prepare(src, uberMaterial, autoExposure); | 
|             } | 
|   | 
|             uberActive |= TryPrepareUberImageEffect(m_ChromaticAberration, uberMaterial); | 
|             uberActive |= TryPrepareUberImageEffect(m_ColorGrading, uberMaterial); | 
|             uberActive |= TryPrepareUberImageEffect(m_Vignette, uberMaterial); | 
|             uberActive |= TryPrepareUberImageEffect(m_UserLut, uberMaterial); | 
|   | 
|             var fxaaMaterial = fxaaActive | 
|                 ? m_MaterialFactory.Get("Hidden/Post FX/FXAA") | 
|                 : null; | 
|   | 
|             if (fxaaActive) | 
|             { | 
|                 fxaaMaterial.shaderKeywords = null; | 
|                 TryPrepareUberImageEffect(m_Grain, fxaaMaterial); | 
|                 TryPrepareUberImageEffect(m_Dithering, fxaaMaterial); | 
|   | 
|                 if (uberActive) | 
|                 { | 
|                     var output = m_RenderTextureFactory.Get(src); | 
|                     Graphics.Blit(src, output, uberMaterial, 0); | 
|                     src = output; | 
|                 } | 
|   | 
|                 m_Fxaa.Render(src, dst); | 
|             } | 
|             else | 
|             { | 
|                 uberActive |= TryPrepareUberImageEffect(m_Grain, uberMaterial); | 
|                 uberActive |= TryPrepareUberImageEffect(m_Dithering, uberMaterial); | 
|   | 
|                 if (uberActive) | 
|                 { | 
|                     if (!GraphicsUtils.isLinearColorSpace) | 
|                         uberMaterial.EnableKeyword("UNITY_COLORSPACE_GAMMA"); | 
|   | 
|                     Graphics.Blit(src, dst, uberMaterial, 0); | 
|                 } | 
|             } | 
|   | 
|             if (!uberActive && !fxaaActive) | 
|                 Graphics.Blit(src, dst); | 
|   | 
| #if UNITY_EDITOR | 
|             if (profile.monitors.onFrameEndEditorOnly != null) | 
|             { | 
|                 Graphics.Blit(dst, destination); | 
|   | 
|                 var oldRt = RenderTexture.active; | 
|                 profile.monitors.onFrameEndEditorOnly(dst); | 
|                 RenderTexture.active = oldRt; | 
|             } | 
| #endif | 
|   | 
|             m_RenderTextureFactory.ReleaseAll(); | 
|         } | 
|   | 
|         void OnGUI() | 
|         { | 
|             if (Event.current.type != EventType.Repaint) | 
|                 return; | 
|   | 
|             if (profile == null || m_Camera == null) | 
|                 return; | 
|   | 
|             if (m_EyeAdaptation.active && profile.debugViews.IsModeActive(DebugMode.EyeAdaptation)) | 
|                 m_EyeAdaptation.OnGUI(); | 
|             else if (m_ColorGrading.active && profile.debugViews.IsModeActive(DebugMode.LogLut)) | 
|                 m_ColorGrading.OnGUI(); | 
|             else if (m_UserLut.active && profile.debugViews.IsModeActive(DebugMode.UserLut)) | 
|                 m_UserLut.OnGUI(); | 
|         } | 
|   | 
|         void OnDisable() | 
|         { | 
|             // Clear command buffers | 
|             foreach (var cb in m_CommandBuffers.Values) | 
|             { | 
|                 m_Camera.RemoveCommandBuffer(cb.Key, cb.Value); | 
|                 cb.Value.Dispose(); | 
|             } | 
|   | 
|             m_CommandBuffers.Clear(); | 
|   | 
|             // Clear components | 
|             if (profile != null) | 
|                 DisableComponents(); | 
|   | 
|             m_Components.Clear(); | 
|   | 
|             // Factories | 
|             m_MaterialFactory.Dispose(); | 
|             m_RenderTextureFactory.Dispose(); | 
|             GraphicsUtils.Dispose(); | 
|         } | 
|   | 
|         public void ResetTemporalEffects() | 
|         { | 
|             m_Taa.ResetHistory(); | 
|             m_MotionBlur.ResetHistory(); | 
|             m_EyeAdaptation.ResetHistory(); | 
|         } | 
|   | 
|         #region State management | 
|   | 
|         List<PostProcessingComponentBase> m_ComponentsToEnable = new List<PostProcessingComponentBase>(); | 
|         List<PostProcessingComponentBase> m_ComponentsToDisable = new List<PostProcessingComponentBase>(); | 
|   | 
|         void CheckObservers() | 
|         { | 
|             foreach (var cs in m_ComponentStates) | 
|             { | 
|                 var component = cs.Key; | 
|                 var state = component.GetModel().enabled; | 
|   | 
|                 if (state != cs.Value) | 
|                 { | 
|                     if (state) m_ComponentsToEnable.Add(component); | 
|                     else m_ComponentsToDisable.Add(component); | 
|                 } | 
|             } | 
|   | 
|             for (int i = 0; i < m_ComponentsToDisable.Count; i++) | 
|             { | 
|                 var c = m_ComponentsToDisable[i]; | 
|                 m_ComponentStates[c] = false; | 
|                 c.OnDisable(); | 
|             } | 
|   | 
|             for (int i = 0; i < m_ComponentsToEnable.Count; i++) | 
|             { | 
|                 var c = m_ComponentsToEnable[i]; | 
|                 m_ComponentStates[c] = true; | 
|                 c.OnEnable(); | 
|             } | 
|   | 
|             m_ComponentsToDisable.Clear(); | 
|             m_ComponentsToEnable.Clear(); | 
|         } | 
|   | 
|         void DisableComponents() | 
|         { | 
|             foreach (var component in m_Components) | 
|             { | 
|                 var model = component.GetModel(); | 
|                 if (model != null && model.enabled) | 
|                     component.OnDisable(); | 
|             } | 
|         } | 
|   | 
|         #endregion | 
|   | 
|         #region Command buffer handling & rendering helpers | 
|         // Placeholders before the upcoming Scriptable Render Loop as command buffers will be | 
|         // executed on the go so we won't need of all that stuff | 
|         CommandBuffer AddCommandBuffer<T>(CameraEvent evt, string name) | 
|             where T : PostProcessingModel | 
|         { | 
|             var cb = new CommandBuffer { name = name }; | 
|             var kvp = new KeyValuePair<CameraEvent, CommandBuffer>(evt, cb); | 
|             m_CommandBuffers.Add(typeof(T), kvp); | 
|             m_Camera.AddCommandBuffer(evt, kvp.Value); | 
|             return kvp.Value; | 
|         } | 
|   | 
|         void RemoveCommandBuffer<T>() | 
|             where T : PostProcessingModel | 
|         { | 
|             KeyValuePair<CameraEvent, CommandBuffer> kvp; | 
|             var type = typeof(T); | 
|   | 
|             if (!m_CommandBuffers.TryGetValue(type, out kvp)) | 
|                 return; | 
|   | 
|             m_Camera.RemoveCommandBuffer(kvp.Key, kvp.Value); | 
|             m_CommandBuffers.Remove(type); | 
|             kvp.Value.Dispose(); | 
|         } | 
|   | 
|         CommandBuffer GetCommandBuffer<T>(CameraEvent evt, string name) | 
|             where T : PostProcessingModel | 
|         { | 
|             CommandBuffer cb; | 
|             KeyValuePair<CameraEvent, CommandBuffer> kvp; | 
|   | 
|             if (!m_CommandBuffers.TryGetValue(typeof(T), out kvp)) | 
|             { | 
|                 cb = AddCommandBuffer<T>(evt, name); | 
|             } | 
|             else if (kvp.Key != evt) | 
|             { | 
|                 RemoveCommandBuffer<T>(); | 
|                 cb = AddCommandBuffer<T>(evt, name); | 
|             } | 
|             else cb = kvp.Value; | 
|   | 
|             return cb; | 
|         } | 
|   | 
|         void TryExecuteCommandBuffer<T>(PostProcessingComponentCommandBuffer<T> component) | 
|             where T : PostProcessingModel | 
|         { | 
|             if (component.active) | 
|             { | 
|                 var cb = GetCommandBuffer<T>(component.GetCameraEvent(), component.GetName()); | 
|                 cb.Clear(); | 
|                 component.PopulateCommandBuffer(cb); | 
|             } | 
|             else RemoveCommandBuffer<T>(); | 
|         } | 
|   | 
|         bool TryPrepareUberImageEffect<T>(PostProcessingComponentRenderTexture<T> component, Material material) | 
|             where T : PostProcessingModel | 
|         { | 
|             if (!component.active) | 
|                 return false; | 
|   | 
|             component.Prepare(material); | 
|             return true; | 
|         } | 
|   | 
|         T AddComponent<T>(T component) | 
|             where T : PostProcessingComponentBase | 
|         { | 
|             m_Components.Add(component); | 
|             return component; | 
|         } | 
|   | 
|         #endregion | 
|     } | 
| } |