chenxin
2020-10-22 63133cf5403a9d7fbe3811d20c3d24f26a752449
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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
                       && SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBHalf)
                       && !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.ARGBHalf;
            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
            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);
            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;
        }
    }
}