| | |
| | | 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 != null && 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; |
| | | } |
| | | } |
| | | } |
| | | 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 != null && 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;
|
| | | }
|
| | | }
|
| | | }
|