| using UnityEngine.Rendering; | 
|   | 
| namespace UnityEngine.PostProcessing | 
| { | 
|     using DebugMode = BuiltinDebugViewsModel.Mode; | 
|   | 
|     public sealed class DepthOfFieldComponent : PostProcessingComponentRenderTexture<DepthOfFieldModel> | 
|     { | 
|         static class Uniforms | 
|         { | 
|             internal static readonly int _DepthOfFieldTex    = Shader.PropertyToID("_DepthOfFieldTex"); | 
|             internal static readonly int _DepthOfFieldCoCTex = Shader.PropertyToID("_DepthOfFieldCoCTex"); | 
|             internal static readonly int _Distance           = Shader.PropertyToID("_Distance"); | 
|             internal static readonly int _LensCoeff          = Shader.PropertyToID("_LensCoeff"); | 
|             internal static readonly int _MaxCoC             = Shader.PropertyToID("_MaxCoC"); | 
|             internal static readonly int _RcpMaxCoC          = Shader.PropertyToID("_RcpMaxCoC"); | 
|             internal static readonly int _RcpAspect          = Shader.PropertyToID("_RcpAspect"); | 
|             internal static readonly int _MainTex            = Shader.PropertyToID("_MainTex"); | 
|             internal static readonly int _CoCTex             = Shader.PropertyToID("_CoCTex"); | 
|             internal static readonly int _TaaParams          = Shader.PropertyToID("_TaaParams"); | 
|             internal static readonly int _DepthOfFieldParams = Shader.PropertyToID("_DepthOfFieldParams"); | 
|         } | 
|   | 
|         const string k_ShaderString = "Hidden/Post FX/Depth Of Field"; | 
|   | 
|         public override bool active | 
|         { | 
|             get | 
|             { | 
|                 return model.enabled | 
|                        && !context.interrupted; | 
|             } | 
|         } | 
|   | 
|         public override DepthTextureMode GetCameraFlags() | 
|         { | 
|             return DepthTextureMode.Depth; | 
|         } | 
|   | 
|         RenderTexture m_CoCHistory; | 
|   | 
|         // Height of the 35mm full-frame format (36mm x 24mm) | 
|         const float k_FilmHeight = 0.024f; | 
|   | 
|         float CalculateFocalLength() | 
|         { | 
|             var settings = model.settings; | 
|   | 
|             if (!settings.useCameraFov) | 
|                 return settings.focalLength / 1000f; | 
|   | 
|             float fov = context.camera.fieldOfView * Mathf.Deg2Rad; | 
|             return 0.5f * k_FilmHeight / Mathf.Tan(0.5f * fov); | 
|         } | 
|   | 
|         float CalculateMaxCoCRadius(int screenHeight) | 
|         { | 
|             // Estimate the allowable maximum radius of CoC from the kernel | 
|             // size (the equation below was empirically derived). | 
|             float radiusInPixels = (float)model.settings.kernelSize * 4f + 6f; | 
|   | 
|             // Applying a 5% limit to the CoC radius to keep the size of | 
|             // TileMax/NeighborMax small enough. | 
|             return Mathf.Min(0.05f, radiusInPixels / screenHeight); | 
|         } | 
|   | 
|         bool CheckHistory(int width, int height) | 
|         { | 
|             return m_CoCHistory != null && m_CoCHistory.IsCreated() && | 
|                 m_CoCHistory.width == width && m_CoCHistory.height == height; | 
|         } | 
|   | 
|         RenderTextureFormat SelectFormat(RenderTextureFormat primary, RenderTextureFormat secondary) | 
|         { | 
|             if (SystemInfo.SupportsRenderTextureFormat(primary)) return primary; | 
|             if (SystemInfo.SupportsRenderTextureFormat(secondary)) return secondary; | 
|             return RenderTextureFormat.Default; | 
|         } | 
|   | 
|         public void Prepare(RenderTexture source, Material uberMaterial, bool antialiasCoC, Vector2 taaJitter, float taaBlending) | 
|         { | 
|             var settings = model.settings; | 
|             var colorFormat = RenderTextureFormat.DefaultHDR; | 
|             var cocFormat = SelectFormat(RenderTextureFormat.R8, RenderTextureFormat.RHalf); | 
|   | 
|             // Avoid using R8 on OSX with Metal. #896121, https://goo.gl/MgKqu6 | 
|             #if (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX) && !UNITY_2017_1_OR_NEWER | 
|             if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Metal) | 
|                 cocFormat = SelectFormat(RenderTextureFormat.RHalf, RenderTextureFormat.Default); | 
|             #endif | 
|   | 
|             // Material setup | 
|             var f = CalculateFocalLength(); | 
|             var s1 = Mathf.Max(settings.focusDistance, f); | 
|             var aspect = (float)source.width / source.height; | 
|             var coeff = f * f / (settings.aperture * (s1 - f) * k_FilmHeight * 2); | 
|             var maxCoC = CalculateMaxCoCRadius(source.height); | 
|   | 
|             var material = context.materialFactory.Get(k_ShaderString); | 
|             material.SetFloat(Uniforms._Distance, s1); | 
|             material.SetFloat(Uniforms._LensCoeff, coeff); | 
|             material.SetFloat(Uniforms._MaxCoC, maxCoC); | 
|             material.SetFloat(Uniforms._RcpMaxCoC, 1f / maxCoC); | 
|             material.SetFloat(Uniforms._RcpAspect, 1f / aspect); | 
|   | 
|             // CoC calculation pass | 
|             var rtCoC = context.renderTextureFactory.Get(context.width, context.height, 0, cocFormat, RenderTextureReadWrite.Linear); | 
|             Graphics.Blit(null, rtCoC, material, 0); | 
|   | 
|             if (antialiasCoC) | 
|             { | 
|                 // CoC temporal filter pass | 
|                 material.SetTexture(Uniforms._CoCTex, rtCoC); | 
|   | 
|                 var blend = CheckHistory(context.width, context.height) ? taaBlending : 0f; | 
|                 material.SetVector(Uniforms._TaaParams, new Vector3(taaJitter.x, taaJitter.y, blend)); | 
|   | 
|                 var rtFiltered = RenderTexture.GetTemporary(context.width, context.height, 0, cocFormat); | 
|                 Graphics.Blit(m_CoCHistory, rtFiltered, material, 1); | 
|   | 
|                 context.renderTextureFactory.Release(rtCoC); | 
|                 if (m_CoCHistory != null) RenderTexture.ReleaseTemporary(m_CoCHistory); | 
|   | 
|                 m_CoCHistory = rtCoC = rtFiltered; | 
|             } | 
|   | 
|             // Downsampling and prefiltering pass | 
|             var rt1 = context.renderTextureFactory.Get(context.width / 2, context.height / 2, 0, colorFormat); | 
|             material.SetTexture(Uniforms._CoCTex, rtCoC); | 
|             Graphics.Blit(source, rt1, material, 2); | 
|   | 
|             // Bokeh simulation pass | 
|             var rt2 = context.renderTextureFactory.Get(context.width / 2, context.height / 2, 0, colorFormat); | 
|             Graphics.Blit(rt1, rt2, material, 3 + (int)settings.kernelSize); | 
|   | 
|             // Postfilter pass | 
|             Graphics.Blit(rt2, rt1, material, 7); | 
|   | 
|             // Give the results to the uber shader. | 
|             uberMaterial.SetVector(Uniforms._DepthOfFieldParams, new Vector3(s1, coeff, maxCoC)); | 
|   | 
|             if (context.profile.debugViews.IsModeActive(DebugMode.FocusPlane)) | 
|             { | 
|                 uberMaterial.EnableKeyword("DEPTH_OF_FIELD_COC_VIEW"); | 
|                 context.Interrupt(); | 
|             } | 
|             else | 
|             { | 
|                 uberMaterial.SetTexture(Uniforms._DepthOfFieldTex, rt1); | 
|                 uberMaterial.SetTexture(Uniforms._DepthOfFieldCoCTex, rtCoC); | 
|                 uberMaterial.EnableKeyword("DEPTH_OF_FIELD"); | 
|             } | 
|   | 
|             context.renderTextureFactory.Release(rt2); | 
|         } | 
|   | 
|         public override void OnDisable() | 
|         { | 
|             if (m_CoCHistory != null) | 
|                 RenderTexture.ReleaseTemporary(m_CoCHistory); | 
|   | 
|             m_CoCHistory = null; | 
|         } | 
|     } | 
| } |