Exemple #1
0
        // HDR color pipeline is rendered to a 3D lut; it requires Texture3D & compute shaders
        // support - Desktop / Consoles / Some high-end mobiles
        void RenderHDRPipeline(PostProcessRenderContext context)
        {
            // Unfortunately because AnimationCurve doesn't implement GetHashCode and we don't have
            // any reliable way to figure out if a curve data is different from another one we can't
            // skip regenerating the Lut if nothing has changed. So it has to be done on every
            // frame...
            // It's not a very expensive operation anyway (we're talking about filling a 33x33x33
            // Lut on the GPU) but every little thing helps, especially on mobile.
            {
                CheckInternalLogLut();

                // Lut setup
                var compute = context.resources.computeShaders.lut3DBaker;
                int kernel  = 0;

                switch (settings.tonemapper.value)
                {
                case Tonemapper.None: kernel = compute.FindKernel("KGenLut3D_NoTonemap");
                    break;

                case Tonemapper.Neutral: kernel = compute.FindKernel("KGenLut3D_NeutralTonemap");
                    break;

                case Tonemapper.ACES: kernel = compute.FindKernel("KGenLut3D_AcesTonemap");
                    break;

                case Tonemapper.Custom: kernel = compute.FindKernel("KGenLut3D_CustomTonemap");
                    break;
                }

                int groupSize = Mathf.CeilToInt(k_Lut3DSize / 8f);
                var cmd       = context.command;
                cmd.SetComputeTextureParam(compute, kernel, "_Output", m_InternalLogLut);
                cmd.SetComputeVectorParam(compute, "_Size", new Vector4(k_Lut3DSize, 1f / (k_Lut3DSize - 1f), 0f, 0f));

                var colorBalance = ColorUtilities.ComputeColorBalance(settings.temperature.value, settings.tint.value);
                cmd.SetComputeVectorParam(compute, "_ColorBalance", colorBalance);
                cmd.SetComputeVectorParam(compute, "_ColorFilter", settings.colorFilter.value);

                float hue = settings.hueShift.value / 360f;         // Remap to [-0.5;0.5]
                float sat = settings.saturation.value / 100f + 1f;  // Remap to [0;2]
                float con = settings.contrast.value / 100f + 1f;    // Remap to [0;2]
                cmd.SetComputeVectorParam(compute, "_HueSatCon", new Vector4(hue, sat, con, 0f));

                var channelMixerR = new Vector4(settings.mixerRedOutRedIn, settings.mixerRedOutGreenIn, settings.mixerRedOutBlueIn, 0f);
                var channelMixerG = new Vector4(settings.mixerGreenOutRedIn, settings.mixerGreenOutGreenIn, settings.mixerGreenOutBlueIn, 0f);
                var channelMixerB = new Vector4(settings.mixerBlueOutRedIn, settings.mixerBlueOutGreenIn, settings.mixerBlueOutBlueIn, 0f);
                cmd.SetComputeVectorParam(compute, "_ChannelMixerRed", channelMixerR / 100f); // Remap to [-2;2]
                cmd.SetComputeVectorParam(compute, "_ChannelMixerGreen", channelMixerG / 100f);
                cmd.SetComputeVectorParam(compute, "_ChannelMixerBlue", channelMixerB / 100f);

                var lift     = ColorUtilities.ColorToLift(settings.lift.value * 0.2f);
                var gain     = ColorUtilities.ColorToGain(settings.gain.value * 0.8f);
                var invgamma = ColorUtilities.ColorToInverseGamma(settings.gamma.value * 0.8f);
                cmd.SetComputeVectorParam(compute, "_Lift", new Vector4(lift.x, lift.y, lift.z, 0f));
                cmd.SetComputeVectorParam(compute, "_InvGamma", new Vector4(invgamma.x, invgamma.y, invgamma.z, 0f));
                cmd.SetComputeVectorParam(compute, "_Gain", new Vector4(gain.x, gain.y, gain.z, 0f));

                cmd.SetComputeTextureParam(compute, kernel, "_Curves", GetCurveTexture(true));

                if (settings.tonemapper.value == Tonemapper.Custom)
                {
                    m_HableCurve.Init(
                        settings.toneCurveToeStrength.value,
                        settings.toneCurveToeLength.value,
                        settings.toneCurveShoulderStrength.value,
                        settings.toneCurveShoulderLength.value,
                        settings.toneCurveShoulderAngle.value,
                        settings.toneCurveGamma.value
                        );

                    var curve = new Vector4(m_HableCurve.inverseWhitePoint, m_HableCurve.x0, m_HableCurve.x1, 0f);
                    cmd.SetComputeVectorParam(compute, "_CustomToneCurve", curve);

                    var toe         = m_HableCurve.segments[0];
                    var mid         = m_HableCurve.segments[1];
                    var sho         = m_HableCurve.segments[2];
                    var toeSegmentA = new Vector4(toe.offsetX, toe.offsetY, toe.scaleX, toe.scaleY);
                    var toeSegmentB = new Vector4(toe.lnA, toe.B, 0f, 0f);
                    var midSegmentA = new Vector4(mid.offsetX, mid.offsetY, mid.scaleX, mid.scaleY);
                    var midSegmentB = new Vector4(mid.lnA, mid.B, 0f, 0f);
                    var shoSegmentA = new Vector4(sho.offsetX, sho.offsetY, sho.scaleX, sho.scaleY);
                    var shoSegmentB = new Vector4(sho.lnA, sho.B, 0f, 0f);
                    cmd.SetComputeVectorParam(compute, "_ToeSegmentA", toeSegmentA);
                    cmd.SetComputeVectorParam(compute, "_ToeSegmentB", toeSegmentB);
                    cmd.SetComputeVectorParam(compute, "_MidSegmentA", midSegmentA);
                    cmd.SetComputeVectorParam(compute, "_MidSegmentB", midSegmentB);
                    cmd.SetComputeVectorParam(compute, "_ShoSegmentA", shoSegmentA);
                    cmd.SetComputeVectorParam(compute, "_ShoSegmentB", shoSegmentB);
                }

                // Generate the lut
                context.command.BeginSample("HdrColorGradingLut");
                cmd.DispatchCompute(compute, kernel, groupSize, groupSize, groupSize);
                context.command.EndSample("HdrColorGradingLut");
            }

            var lut       = m_InternalLogLut;
            var uberSheet = context.uberSheet;

            uberSheet.EnableKeyword("COLOR_GRADING_HDR");
            uberSheet.properties.SetTexture(Uniforms._Lut3D, lut);
            uberSheet.properties.SetVector(Uniforms._Lut3D_Params, new Vector2(1f / lut.width, lut.width - 1f));
            uberSheet.properties.SetFloat(Uniforms._PostExposure, RuntimeUtilities.Exp2(settings.postExposure.value));

            context.logLut = lut;
        }
 internal void BeginFrame(PostProcessRenderContext context)
 {
     m_Command        = context.command;
     m_PropertySheets = context.propertySheets;
     m_Resources      = context.resources;
 }
Exemple #3
0
        public override void Render(PostProcessRenderContext context)
        {
            var cmd = context.command;

            cmd.BeginSample("BloomPyramid");

            var sheet = context.propertySheets.Get(context.resources.shaders.bloom);

            // Apply auto exposure adjustment in the prefiltering pass
            sheet.properties.SetTexture(Uniforms._AutoExposureTex, context.autoExposureTexture);

            // Determine the iteration count
            float logh        = Mathf.Log(context.height, 2f) + settings.diffusion.value - 10f;
            int   logh_i      = Mathf.FloorToInt(logh);
            int   iterations  = Mathf.Clamp(logh_i, 1, k_MaxPyramidSize);
            float sampleScale = 0.5f + logh - logh_i;

            sheet.properties.SetFloat(Uniforms._SampleScale, sampleScale);

            // Do bloom on a half-res buffer, full-res doesn't bring much and kills performances on
            // fillrate limited platforms
            int tw = context.width / 2;
            int th = context.height / 2;

            // Prefiltering parameters
            float lthresh   = Mathf.GammaToLinearSpace(settings.threshold.value);
            float knee      = lthresh * settings.softKnee.value + 1e-5f;
            var   threshold = new Vector4(lthresh, lthresh - knee, knee * 2f, 0.25f / knee);

            sheet.properties.SetVector(Uniforms._Threshold, threshold);

            int qualityOffset = settings.mobileOptimized ? 1 : 0;

            // Downsample
            var last = context.source;

            for (int i = 0; i < iterations; i++)
            {
                int mipDown = m_Pyramid[i].down;
                int mipUp   = m_Pyramid[i].up;
                int pass    = i == 0
                    ? (int)Pass.Prefilter13 + qualityOffset
                    : (int)Pass.Downsample13 + qualityOffset;

                cmd.GetTemporaryRT(mipDown, tw, th, 0, FilterMode.Bilinear, context.sourceFormat);
                cmd.GetTemporaryRT(mipUp, tw, th, 0, FilterMode.Bilinear, context.sourceFormat);
                cmd.BlitFullscreenTriangle(last, mipDown, sheet, pass);

                last = mipDown;
                tw  /= 2; th /= 2;
            }

            // Upsample
            last = m_Pyramid[iterations - 1].down;
            for (int i = iterations - 2; i >= 0; i--)
            {
                int mipDown = m_Pyramid[i].down;
                int mipUp   = m_Pyramid[i].up;
                cmd.SetGlobalTexture(Uniforms._BloomTex, mipDown);
                cmd.BlitFullscreenTriangle(last, mipUp, sheet, (int)Pass.UpsampleTent + qualityOffset);
                last = mipUp;
            }

            var shaderSettings = new Vector4(
                sampleScale,
                RuntimeUtilities.Exp2(settings.intensity.value / 10f) - 1f,
                settings.lensIntensity.value,
                iterations
                );

            var dirtTexture = settings.lensTexture.value == null
                ? RuntimeUtilities.blackTexture
                : settings.lensTexture.value;

            var uberSheet = context.uberSheet;

            uberSheet.EnableKeyword("BLOOM");
            uberSheet.properties.SetVector(Uniforms._Bloom_Settings, shaderSettings);
            uberSheet.properties.SetColor(Uniforms._Bloom_Color, settings.color.value.linear);
            uberSheet.properties.SetTexture(Uniforms._Bloom_DirtTex, dirtTexture);
            cmd.SetGlobalTexture(Uniforms._BloomTex, m_Pyramid[0].up);

            // Cleanup
            for (int i = 0; i < iterations; i++)
            {
                cmd.ReleaseTemporaryRT(m_Pyramid[i].down);
                cmd.ReleaseTemporaryRT(m_Pyramid[i].up);
            }

            cmd.EndSample("BloomPyramid");
        }
Exemple #4
0
        void RenderList(List <PostProcessBundle> list, PostProcessRenderContext context, string marker)
        {
            var cmd = context.command;

            cmd.BeginSample(marker);

            // First gather active effects - we need this to manage render targets more efficiently
            m_ActivePool.Clear();
            for (int i = 0; i < list.Count; i++)
            {
                var effect = list[i];
                if (effect.settings.IsEnabledAndSupported())
                {
                    if (!m_IsRenderingInSceneView || (m_IsRenderingInSceneView && effect.attribute.allowInSceneView))
                    {
                        m_ActivePool.Add(effect.renderer);
                    }
                }
            }

            int count = m_ActivePool.Count;

            // If there's only one active effect, we can simply execute it and skip the rest
            if (count == 1)
            {
                m_ActivePool[0].Render(context);
            }
            else
            {
                // Else create the target chain
                m_TargetPool.Clear();
                m_TargetPool.Add(context.source); // First target is always source

                for (int i = 0; i < count - 1; i++)
                {
                    m_TargetPool.Add(Uniforms._TempTargetPool[i % 2]);
                }

                m_TargetPool.Add(context.destination); // Last target is always destination

                // Render
                cmd.GetTemporaryRT(Uniforms._TempTargetPool[0], context.width, context.height, 24, FilterMode.Bilinear, context.sourceFormat);
                if (count > 2)
                {
                    cmd.GetTemporaryRT(Uniforms._TempTargetPool[1], context.width, context.height, 24, FilterMode.Bilinear, context.sourceFormat);
                }

                for (int i = 0; i < count; i++)
                {
                    context.source      = m_TargetPool[i];
                    context.destination = m_TargetPool[i + 1];
                    m_ActivePool[i].Render(context);
                }

                cmd.ReleaseTemporaryRT(Uniforms._TempTargetPool[0]);
                if (count > 2)
                {
                    cmd.ReleaseTemporaryRT(Uniforms._TempTargetPool[1]);
                }
            }

            cmd.EndSample(marker);
        }
Exemple #5
0
        // Renders before-stack, builtin stack and after-stack effects
        // TODO: Refactor this, it's a mess and it's hard to maintain
        public void Render(PostProcessRenderContext context)
        {
            // Update & override layer settings first (volume blending) if the opaque only pass
            // hasn't been called this frame.
            UpdateSettingsIfNeeded(context);

            SetupContext(context);
            var finalDestination = context.destination;
            var cmd = context.command;

            // Do temporal anti-aliasing first
            if (context.IsTemporalAntialiasingActive() && !m_IsRenderingInSceneView)
            {
                temporalAntialiasing.SetProjectionMatrix(context.camera);

                cmd.GetTemporaryRT(Uniforms._AATemp, context.width, context.height, 24, FilterMode.Bilinear, context.sourceFormat);
                context.destination = Uniforms._AATemp;
                temporalAntialiasing.Render(context);
                context.source      = Uniforms._AATemp;
                context.destination = Uniforms._TempTargetPool[4];
            }

            bool hasBeforeStack = HasActiveEffects(m_SortedBundles[PostProcessEvent.BeforeStack]);
            bool hasAfterStack  = HasActiveEffects(m_SortedBundles[PostProcessEvent.AfterStack]);

            // Render builtin stack and user effects
            if (hasBeforeStack)
            {
                cmd.GetTemporaryRT(Uniforms._TempTargetPool[2], context.width, context.height, 24, FilterMode.Bilinear, context.sourceFormat);
                context.destination = Uniforms._TempTargetPool[2];
                RenderList(m_SortedBundles[PostProcessEvent.BeforeStack], context, "BeforeStack");
                context.source      = Uniforms._TempTargetPool[2];
                context.destination = Uniforms._TempTargetPool[4];
            }

            if (hasAfterStack)
            {
                cmd.GetTemporaryRT(Uniforms._TempTargetPool[3], context.width, context.height, 24, FilterMode.Bilinear, context.sourceFormat);
                context.destination = Uniforms._TempTargetPool[3];
                RenderBuiltins(context);

                if (hasBeforeStack)
                {
                    cmd.ReleaseTemporaryRT(Uniforms._TempTargetPool[2]);
                }

                context.source      = Uniforms._TempTargetPool[3];
                context.destination = Uniforms._TempTargetPool[4];
                cmd.GetTemporaryRT(Uniforms._TempTargetPool[4], context.width, context.height, 24, FilterMode.Bilinear, context.sourceFormat);
                RenderList(m_SortedBundles[PostProcessEvent.AfterStack], context, "AfterStack");
                cmd.ReleaseTemporaryRT(Uniforms._TempTargetPool[3]);
            }
            else // Should be skippable if nothing's enabled in builtins
            {
                context.destination = Uniforms._TempTargetPool[4];
                cmd.GetTemporaryRT(Uniforms._TempTargetPool[4], context.width, context.height, 24, FilterMode.Bilinear, context.sourceFormat);
                RenderBuiltins(context);

                if (hasBeforeStack)
                {
                    cmd.ReleaseTemporaryRT(Uniforms._TempTargetPool[2]);
                }
            }

            context.source      = Uniforms._TempTargetPool[4];
            context.destination = finalDestination;
            RenderFinalPass(context);
            cmd.ReleaseTemporaryRT(Uniforms._TempTargetPool[4]);

            m_SettingsUpdateNeeded = true;
        }
Exemple #6
0
        public override void Render(PostProcessRenderContext context)
        {
            var cmd = context.command;

            if (m_ResetHistory)
            {
                cmd.BlitFullscreenTriangle(context.source, context.destination);
                m_ResetHistory = false;
                return;
            }

            const float kMaxBlurRadius = 5f;
            var         vectorRTFormat = RenderTextureFormat.RGHalf;
            var         packedRTFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGB2101010)
                ? RenderTextureFormat.ARGB2101010
                : RenderTextureFormat.ARGB32;

            var sheet = context.propertySheets.Get(context.resources.shaders.motionBlur);

            cmd.BeginSample("MotionBlur");

            // Calculate the maximum blur radius in pixels.
            int maxBlurPixels = (int)(kMaxBlurRadius * context.height / 100);

            // Calculate the TileMax size.
            // It should be a multiple of 8 and larger than maxBlur.
            int tileSize = ((maxBlurPixels - 1) / 8 + 1) * 8;

            // Pass 1 - Velocity/depth packing
            var velocityScale = settings.shutterAngle / 360f;

            sheet.properties.SetFloat(Uniforms._VelocityScale, velocityScale);
            sheet.properties.SetFloat(Uniforms._MaxBlurRadius, maxBlurPixels);
            sheet.properties.SetFloat(Uniforms._RcpMaxBlurRadius, 1f / maxBlurPixels);

            int vbuffer = Uniforms._VelocityTex;

            cmd.GetTemporaryRT(vbuffer, context.width, context.height, 0, FilterMode.Point,
                               packedRTFormat, RenderTextureReadWrite.Linear);
            cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, vbuffer, sheet, (int)Pass.VelocitySetup);

            // Pass 2 - First TileMax filter (1/2 downsize)
            int tile2 = Uniforms._Tile2RT;

            cmd.GetTemporaryRT(tile2, context.width / 2, context.height / 2, 0, FilterMode.Point,
                               vectorRTFormat, RenderTextureReadWrite.Linear);
            cmd.BlitFullscreenTriangle(vbuffer, tile2, sheet, (int)Pass.TileMax1);

            // Pass 3 - Second TileMax filter (1/2 downsize)
            int tile4 = Uniforms._Tile4RT;

            cmd.GetTemporaryRT(tile4, context.width / 4, context.height / 4, 0, FilterMode.Point,
                               vectorRTFormat, RenderTextureReadWrite.Linear);
            cmd.BlitFullscreenTriangle(tile2, tile4, sheet, (int)Pass.TileMax2);
            cmd.ReleaseTemporaryRT(tile2);

            // Pass 4 - Third TileMax filter (1/2 downsize)
            int tile8 = Uniforms._Tile8RT;

            cmd.GetTemporaryRT(tile8, context.width / 8, context.height / 8, 0, FilterMode.Point,
                               vectorRTFormat, RenderTextureReadWrite.Linear);
            cmd.BlitFullscreenTriangle(tile4, tile8, sheet, (int)Pass.TileMax2);
            cmd.ReleaseTemporaryRT(tile4);

            // Pass 5 - Fourth TileMax filter (reduce to tileSize)
            var tileMaxOffs = Vector2.one * (tileSize / 8f - 1f) * -0.5f;

            sheet.properties.SetVector(Uniforms._TileMaxOffs, tileMaxOffs);
            sheet.properties.SetFloat(Uniforms._TileMaxLoop, (int)(tileSize / 8f));

            int tile = Uniforms._TileVRT;

            cmd.GetTemporaryRT(tile, context.width / tileSize, context.height / tileSize, 0,
                               FilterMode.Point, vectorRTFormat, RenderTextureReadWrite.Linear);
            cmd.BlitFullscreenTriangle(tile8, tile, sheet, (int)Pass.TileMaxV);
            cmd.ReleaseTemporaryRT(tile8);

            // Pass 6 - NeighborMax filter
            int neighborMax       = Uniforms._NeighborMaxTex;
            int neighborMaxWidth  = context.width / tileSize;
            int neighborMaxHeight = context.height / tileSize;

            cmd.GetTemporaryRT(neighborMax, neighborMaxWidth, neighborMaxHeight, 0,
                               FilterMode.Point, vectorRTFormat, RenderTextureReadWrite.Linear);
            cmd.BlitFullscreenTriangle(tile, neighborMax, sheet, (int)Pass.NeighborMax);
            cmd.ReleaseTemporaryRT(tile);

            // Pass 7 - Reconstruction pass
            sheet.properties.SetFloat(Uniforms._LoopCount, Mathf.Clamp(settings.sampleCount / 2, 1, 64));
            cmd.BlitFullscreenTriangle(context.source, context.destination, sheet, (int)Pass.Reconstruction);

            cmd.ReleaseTemporaryRT(vbuffer);
            cmd.ReleaseTemporaryRT(neighborMax);
            cmd.EndSample("MotionBlur");
        }
Exemple #7
0
        public override void Render(PostProcessRenderContext context)
        {
            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 == UnityEngine.Rendering.GraphicsDeviceType.Metal)
            {
                cocFormat = SelectFormat(RenderTextureFormat.RHalf, RenderTextureFormat.Default);
            }
            #endif

            // Material setup
            var f      = settings.focalLength.value / 1000f;
            var s1     = Mathf.Max(settings.focusDistance.value, f);
            var aspect = (float)context.width / (float)context.height;
            var coeff  = f * f / (settings.aperture.value * (s1 - f) * k_FilmHeight * 2);
            var maxCoC = CalculateMaxCoCRadius(context.height);

            var sheet = context.propertySheets.Get(context.resources.shaders.depthOfField);
            sheet.properties.Clear();
            sheet.properties.SetFloat(Uniforms._Distance, s1);
            sheet.properties.SetFloat(Uniforms._LensCoeff, coeff);
            sheet.properties.SetFloat(Uniforms._MaxCoC, maxCoC);
            sheet.properties.SetFloat(Uniforms._RcpMaxCoC, 1f / maxCoC);
            sheet.properties.SetFloat(Uniforms._RcpAspect, 1f / aspect);

            var cmd = context.command;
            cmd.BeginSample("DepthOfField");

            // CoC calculation pass
            cmd.GetTemporaryRT(Uniforms._CoCTex, context.width, context.height, 0, FilterMode.Bilinear, cocFormat);
            cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, Uniforms._CoCTex, sheet, (int)Pass.CoCCalculation);

            // CoC temporal filter pass when TAA is enabled
            if (context.IsTemporalAntialiasingActive())
            {
                float motionBlending = context.temporalAntialiasing.motionBlending;
                float blend          = m_ResetHistory ? 0f : motionBlending; // Handles first frame blending
                var   jitter         = context.temporalAntialiasing.jitter;

                sheet.properties.SetVector(Uniforms._TaaParams, new Vector3(jitter.x, jitter.y, blend));

                int pp           = m_HistoryPingPong;
                var historyRead  = CheckHistory(++pp % 2, context.width, context.height, cocFormat);
                var historyWrite = CheckHistory(++pp % 2, context.width, context.height, cocFormat);
                m_HistoryPingPong = ++pp % 2;

                cmd.BlitFullscreenTriangle(historyRead, historyWrite, sheet, (int)Pass.CoCTemporalFilter);
                cmd.ReleaseTemporaryRT(Uniforms._CoCTex);
                cmd.SetGlobalTexture(Uniforms._CoCTex, historyWrite);
            }

            // Downsampling and prefiltering pass
            cmd.GetTemporaryRT(Uniforms._DepthOfFieldTex, context.width / 2, context.height / 2, 0, FilterMode.Bilinear, colorFormat);
            cmd.BlitFullscreenTriangle(context.source, Uniforms._DepthOfFieldTex, sheet, (int)Pass.DownsampleAndPrefilter);

            // Bokeh simulation pass
            cmd.GetTemporaryRT(Uniforms._DepthOfFieldTemp, context.width / 2, context.height / 2, 0, FilterMode.Bilinear, colorFormat);
            cmd.BlitFullscreenTriangle(Uniforms._DepthOfFieldTex, Uniforms._DepthOfFieldTemp, sheet, (int)Pass.BokehSmallKernel + (int)settings.kernelSize.value);

            // Postfilter pass
            cmd.BlitFullscreenTriangle(Uniforms._DepthOfFieldTemp, Uniforms._DepthOfFieldTex, sheet, (int)Pass.PostFilter);
            cmd.ReleaseTemporaryRT(Uniforms._DepthOfFieldTemp);

            // Combine pass
            cmd.BlitFullscreenTriangle(context.source, context.destination, sheet, (int)Pass.Combine);
            cmd.ReleaseTemporaryRT(Uniforms._DepthOfFieldTex);

            if (!context.IsTemporalAntialiasingActive())
            {
                cmd.ReleaseTemporaryRT(Uniforms._CoCTex);
            }

            cmd.EndSample("DepthOfField");

            m_ResetHistory = false;
        }
        void OnLightMeterGUI(PostProcessRenderContext context)
        {
            if (m_TickLabelStyle == null)
            {
                m_TickLabelStyle = new GUIStyle("Label")
                {
                    fontStyle = FontStyle.Bold,
                    fontSize  = 10,
                    alignment = TextAnchor.MiddleCenter
                };
            }

            var histogram = context.logHistogram;
            int kMargin   = 8;
            int x         = kMargin;
            int w         = (int)(context.width * (3 / 5f) - kMargin * 2);
            int h         = context.height / 4;
            int y         = context.height - h - kMargin - 30;
            var rect      = new Rect(x, y, w, h);

            if (Event.current.type == EventType.Repaint)
            {
                CheckTexture(ref m_LightMeterRT, (int)rect.width, (int)rect.height);

                var material = context.propertySheets.Get(context.resources.shaders.lightMeter).material;
                material.shaderKeywords = null;
                material.SetBuffer(Uniforms._HistogramBuffer, histogram.data);

                var scaleOffsetRes = histogram.GetHistogramScaleOffsetRes(context);
                scaleOffsetRes.z = 1f / rect.width;
                scaleOffsetRes.w = 1f / rect.height;

                material.SetVector(Uniforms._ScaleOffsetRes, scaleOffsetRes);

                if (context.logLut != null)
                {
                    material.EnableKeyword("COLOR_GRADING_HDR");
                    material.SetTexture(Uniforms._Lut3D, context.logLut);
                }

                if (context.autoExposure != null)
                {
                    var settings = context.autoExposure;

                    // Make sure filtering values are correct to avoid apocalyptic consequences
                    float       lowPercent  = settings.filtering.value.x;
                    float       highPercent = settings.filtering.value.y;
                    const float kMinDelta   = 1e-2f;
                    highPercent = Mathf.Clamp(highPercent, 1f + kMinDelta, 99f);
                    lowPercent  = Mathf.Clamp(lowPercent, 1f, highPercent - kMinDelta);

                    material.EnableKeyword("AUTO_EXPOSURE");
                    material.SetVector(Uniforms._Params, new Vector4(lowPercent * 0.01f, highPercent * 0.01f, RuntimeUtilities.Exp2(settings.minLuminance.value), RuntimeUtilities.Exp2(settings.maxLuminance.value)));
                }

                RuntimeUtilities.BlitFullscreenTriangle(null, m_LightMeterRT, material, 0);
                GUI.DrawTexture(rect, m_LightMeterRT);
            }

            // Labels
            rect.y     += rect.height;
            rect.height = 30;
            int maxSize = Mathf.FloorToInt(rect.width / (LogHistogram.rangeMax - LogHistogram.rangeMin + 2));

            GUI.DrawTexture(rect, RuntimeUtilities.blackTexture);

            GUILayout.BeginArea(rect);
            {
                GUILayout.BeginHorizontal();
                {
                    GUILayout.Space(4);

                    for (int i = LogHistogram.rangeMin; i < LogHistogram.rangeMax; i++)
                    {
                        GUILayout.Label(i + "\n" + RuntimeUtilities.Exp2(i).ToString("0.###"), m_TickLabelStyle, GUILayout.Width(maxSize));
                        GUILayout.FlexibleSpace();
                    }

                    GUILayout.Label(LogHistogram.rangeMax + "\n" + RuntimeUtilities.Exp2(LogHistogram.rangeMax).ToString("0.###"), m_TickLabelStyle, GUILayout.Width(maxSize));
                    GUILayout.Space(4);
                }
                GUILayout.EndHorizontal();
            }
            GUILayout.EndArea();
        }