Beispiel #1
0
        private void DoDepthOfField(RenderTexture source, RenderTexture destination)
        {
            m_CurrentQualitySettings = QualitySettings.presetQualitySettings[(int)settings.filteringQuality];

            float radiusAdjustement = source.height / 720f;

            float textureBokehScale     = radiusAdjustement;
            float textureBokehMaxRadius = Mathf.Max(focus.nearBlurRadius, focus.farBlurRadius) * textureBokehScale * 0.75f;

            float nearBlurRadius = focus.nearBlurRadius * radiusAdjustement;
            float farBlurRadius  = focus.farBlurRadius * radiusAdjustement;
            float maxBlurRadius  = Mathf.Max(nearBlurRadius, farBlurRadius);

            switch (settings.apertureShape)
            {
            case ApertureShape.Hexagonal:
                maxBlurRadius *= 1.2f;
                break;

            case ApertureShape.Octogonal:
                maxBlurRadius *= 1.15f;
                break;
            }

            if (maxBlurRadius < 0.5f)
            {
                Graphics.Blit(source, destination);
                return;
            }

            // Quarter resolution
            int rtW           = source.width / 2;
            int rtH           = source.height / 2;
            var blurrinessCoe = new Vector4(nearBlurRadius * 0.5f, farBlurRadius * 0.5f, 0f, 0f);
            var colorAndCoc   = m_RTU.GetTemporaryRenderTexture(rtW, rtH);
            var colorAndCoc2  = m_RTU.GetTemporaryRenderTexture(rtW, rtH);

            // Downsample to Color + COC buffer
            Vector4 cocParam;
            Vector4 cocCoe;

            ComputeCocParameters(out cocParam, out cocCoe);
            filmicDepthOfFieldMaterial.SetVector("_BlurParams", cocParam);
            filmicDepthOfFieldMaterial.SetVector("_BlurCoe", cocCoe);
            Graphics.Blit(source, colorAndCoc2, filmicDepthOfFieldMaterial, (int)Passes.CaptureCocExplicit);
            var src = colorAndCoc2;
            var dst = colorAndCoc;

            // Collect texture bokeh candidates and replace with a darker pixel
            if (shouldPerformBokeh)
            {
                // Blur a bit so we can do a frequency check
                var blurred = m_RTU.GetTemporaryRenderTexture(rtW, rtH);
                Graphics.Blit(src, blurred, filmicDepthOfFieldMaterial, (int)Passes.BoxBlur);
                filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(0f, 1.5f, 0f, 1.5f));
                Graphics.Blit(blurred, dst, filmicDepthOfFieldMaterial, (int)Passes.BlurAlphaWeighted);
                filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(1.5f, 0f, 0f, 1.5f));
                Graphics.Blit(dst, blurred, filmicDepthOfFieldMaterial, (int)Passes.BlurAlphaWeighted);

                // Collect texture bokeh candidates and replace with a darker pixel
                textureBokehMaterial.SetTexture("_BlurredColor", blurred);
                textureBokehMaterial.SetFloat("_SpawnHeuristic", bokehTexture.spawnHeuristic);
                textureBokehMaterial.SetVector("_BokehParams", new Vector4(bokehTexture.scale * textureBokehScale, bokehTexture.intensity, bokehTexture.threshold, textureBokehMaxRadius));
                Graphics.SetRandomWriteTarget(1, computeBufferPoints);
                Graphics.Blit(src, dst, textureBokehMaterial, (int)BokehTexturesPasses.Collect);
                Graphics.ClearRandomWriteTargets();
                SwapRenderTexture(ref src, ref dst);
                m_RTU.ReleaseTemporaryRenderTexture(blurred);
            }

            filmicDepthOfFieldMaterial.SetVector("_BlurParams", cocParam);
            filmicDepthOfFieldMaterial.SetVector("_BlurCoe", blurrinessCoe);

            // Dilate near blur factor
            RenderTexture blurredFgCoc = null;

            if (m_CurrentQualitySettings.dilateNearBlur)
            {
                var blurredFgCoc2 = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, RenderTextureFormat.RGHalf);
                blurredFgCoc = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, RenderTextureFormat.RGHalf);
                filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(0f, nearBlurRadius * 0.75f, 0f, 0f));
                Graphics.Blit(src, blurredFgCoc2, filmicDepthOfFieldMaterial, (int)Passes.DilateFgCocFromColor);
                filmicDepthOfFieldMaterial.SetVector("_Offsets", new Vector4(nearBlurRadius * 0.75f, 0f, 0f, 0f));
                Graphics.Blit(blurredFgCoc2, blurredFgCoc, filmicDepthOfFieldMaterial, (int)Passes.DilateFgCoc);
                m_RTU.ReleaseTemporaryRenderTexture(blurredFgCoc2);
                blurredFgCoc.filterMode = FilterMode.Point;
            }

            // Blur downsampled color to fill the gap between samples
            if (m_CurrentQualitySettings.prefilterBlur)
            {
                Graphics.Blit(src, dst, filmicDepthOfFieldMaterial, (int)Passes.CocPrefilter);
                SwapRenderTexture(ref src, ref dst);
            }

            // Apply blur : Circle / Hexagonal or Octagonal (blur will create bokeh if bright pixel where not removed by "m_UseBokehTexture")
            switch (settings.apertureShape)
            {
            case ApertureShape.Circular:
                DoCircularBlur(blurredFgCoc, ref src, ref dst, maxBlurRadius);
                break;

            case ApertureShape.Hexagonal:
                DoHexagonalBlur(blurredFgCoc, ref src, ref dst, maxBlurRadius);
                break;

            case ApertureShape.Octogonal:
                DoOctogonalBlur(blurredFgCoc, ref src, ref dst, maxBlurRadius);
                break;
            }

            // Smooth result
            switch (m_CurrentQualitySettings.medianFilter)
            {
            case FilterQuality.Normal:
            {
                medianFilterMaterial.SetVector("_Offsets", new Vector4(1f, 0f, 0f, 0f));
                Graphics.Blit(src, dst, medianFilterMaterial, (int)MedianPasses.Median3);
                SwapRenderTexture(ref src, ref dst);
                medianFilterMaterial.SetVector("_Offsets", new Vector4(0f, 1f, 0f, 0f));
                Graphics.Blit(src, dst, medianFilterMaterial, (int)MedianPasses.Median3);
                SwapRenderTexture(ref src, ref dst);
                break;
            }

            case FilterQuality.High:
            {
                Graphics.Blit(src, dst, medianFilterMaterial, (int)MedianPasses.Median3X3);
                SwapRenderTexture(ref src, ref dst);
                break;
            }
            }

            // Merge to full resolution (with boost) + upsampling (linear or bicubic)
            filmicDepthOfFieldMaterial.SetVector("_BlurCoe", blurrinessCoe);
            filmicDepthOfFieldMaterial.SetVector("_Convolved_TexelSize", new Vector4(src.width, src.height, 1f / src.width, 1f / src.height));
            filmicDepthOfFieldMaterial.SetTexture("_SecondTex", src);
            int mergePass = (int)Passes.MergeExplicit;

            // Apply texture bokeh
            if (shouldPerformBokeh)
            {
                var tmp = m_RTU.GetTemporaryRenderTexture(source.height, source.width, 0, source.format);
                Graphics.Blit(source, tmp, filmicDepthOfFieldMaterial, mergePass);

                Graphics.SetRenderTarget(tmp);
                ComputeBuffer.CopyCount(computeBufferPoints, computeBufferDrawArgs, 0);
                textureBokehMaterial.SetBuffer("pointBuffer", computeBufferPoints);
                textureBokehMaterial.SetTexture("_MainTex", bokehTexture.texture);
                textureBokehMaterial.SetVector("_Screen", new Vector3(1f / (1f * source.width), 1f / (1f * source.height), textureBokehMaxRadius));
                textureBokehMaterial.SetPass((int)BokehTexturesPasses.Apply);
                Graphics.DrawProceduralIndirect(MeshTopology.Points, computeBufferDrawArgs, 0);
                Graphics.Blit(tmp, destination); // Hackaround for DX11 flipfun (OPTIMIZEME)
            }
            else
            {
                Graphics.Blit(source, destination, filmicDepthOfFieldMaterial, mergePass);
            }
        }
Beispiel #2
0
        public void OnRenderImage(RenderTexture source, RenderTexture destination)
        {
            if (material == null)
            {
                Graphics.Blit(source, destination);
                return;
            }
            if (m_HasInformationFromPreviousFrame)
            {
                m_HasInformationFromPreviousFrame = (m_PreviousDepthBuffer != null) &&
                                                    (source.width == m_PreviousDepthBuffer.width) &&
                                                    (source.height == m_PreviousDepthBuffer.height);
            }
            bool doTemporalFilterThisFrame = m_HasInformationFromPreviousFrame && settings.advancedSettings.temporalFilterStrength > 0.0;

            m_HasInformationFromPreviousFrame = false;

            // Not using deferred shading? Just blit source to destination.
            if (Camera.current.actualRenderingPath != RenderingPath.DeferredShading)
            {
                Graphics.Blit(source, destination);
                return;
            }

            var rtW = source.width;
            var rtH = source.height;

            // RGB: Normals, A: Roughness.
            // Has the nice benefit of allowing us to control the filtering mode as well.
            RenderTexture bilateralKeyTexture = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, RenderTextureFormat.ARGB32);

            bilateralKeyTexture.filterMode = FilterMode.Point;
            Graphics.Blit(source, bilateralKeyTexture, material, (int)PassIndex.BilateralKeyPack);
            material.SetTexture("_NormalAndRoughnessTexture", bilateralKeyTexture);

            float sWidth  = source.width;
            float sHeight = source.height;

            Vector2 sourceToTempUV = new Vector2(sWidth / rtW, sHeight / rtH);

            int downsampleAmount = (settings.advancedSettings.resolution == SSRResolution.FullResolution) ? 1 : 2;

            rtW = rtW / downsampleAmount;
            rtH = rtH / downsampleAmount;

            material.SetVector("_SourceToTempUV", new Vector4(sourceToTempUV.x, sourceToTempUV.y, 1.0f / sourceToTempUV.x, 1.0f / sourceToTempUV.y));


            Matrix4x4 P        = GetComponent <Camera>().projectionMatrix;
            Vector4   projInfo = new Vector4
                                     ((-2.0f / (sWidth * P[0])),
                                     (-2.0f / (sHeight * P[5])),
                                     ((1.0f - P[2]) / P[0]),
                                     ((1.0f + P[6]) / P[5]));

            /** The height in pixels of a 1m object if viewed from 1m away. */
            float pixelsPerMeterAtOneMeter = sWidth / (-2.0f * (float)(Math.Tan(GetComponent <Camera>().fieldOfView / 180.0 * Math.PI * 0.5)));

            material.SetFloat("_PixelsPerMeterAtOneMeter", pixelsPerMeterAtOneMeter);


            float sx = sWidth / 2.0f;
            float sy = sHeight / 2.0f;

            Matrix4x4 warpToScreenSpaceMatrix = new Matrix4x4();

            warpToScreenSpaceMatrix.SetRow(0, new Vector4(sx, 0.0f, 0.0f, sx));
            warpToScreenSpaceMatrix.SetRow(1, new Vector4(0.0f, sy, 0.0f, sy));
            warpToScreenSpaceMatrix.SetRow(2, new Vector4(0.0f, 0.0f, 1.0f, 0.0f));
            warpToScreenSpaceMatrix.SetRow(3, new Vector4(0.0f, 0.0f, 0.0f, 1.0f));

            Matrix4x4 projectToPixelMatrix = warpToScreenSpaceMatrix * P;

            material.SetVector("_ScreenSize", new Vector2(sWidth, sHeight));
            material.SetVector("_ReflectionBufferSize", new Vector2(rtW, rtH));
            Vector2 invScreenSize = new Vector2((float)(1.0 / sWidth), (float)(1.0 / sHeight));

            Matrix4x4 worldToCameraMatrix = GetComponent <Camera>().worldToCameraMatrix;
            Matrix4x4 cameraToWorldMatrix = GetComponent <Camera>().worldToCameraMatrix.inverse;

            material.SetVector("_InvScreenSize", invScreenSize);
            material.SetVector("_ProjInfo", projInfo); // used for unprojection
            material.SetMatrix("_ProjectToPixelMatrix", projectToPixelMatrix);
            material.SetMatrix("_WorldToCameraMatrix", worldToCameraMatrix);
            material.SetMatrix("_CameraToWorldMatrix", cameraToWorldMatrix);
            material.SetInt("_EnableRefine", settings.advancedSettings.reduceBanding ? 1 : 0);
            material.SetInt("_AdditiveReflection", settings.basicSettings.additiveReflection ? 1 : 0);
            material.SetInt("_ImproveCorners", settings.advancedSettings.improveCorners ? 1 : 0);
            material.SetFloat("_ScreenEdgeFading", settings.basicSettings.screenEdgeFading);
            material.SetFloat("_MipBias", mipBias);
            material.SetInt("_UseOcclusion", useOcclusion ? 1 : 0);
            material.SetInt("_BilateralUpsampling", settings.advancedSettings.bilateralUpsample ? 1 : 0);
            material.SetInt("_FallbackToSky", fallbackToSky ? 1 : 0);
            material.SetInt("_TreatBackfaceHitAsMiss", settings.advancedSettings.treatBackfaceHitAsMiss ? 1 : 0);
            material.SetInt("_AllowBackwardsRays", settings.advancedSettings.allowBackwardsRays ? 1 : 0);
            material.SetInt("_TraceEverywhere", settings.advancedSettings.traceEverywhere ? 1 : 0);

            float z_f = GetComponent <Camera>().farClipPlane;
            float z_n = GetComponent <Camera>().nearClipPlane;

            Vector3 cameraClipInfo = (float.IsPositiveInfinity(z_f)) ?
                                     new Vector3(z_n, -1.0f, 1.0f) :
                                     new Vector3(z_n * z_f, z_n - z_f, z_f);

            material.SetVector("_CameraClipInfo", cameraClipInfo);
            material.SetFloat("_MaxRayTraceDistance", settings.basicSettings.maxDistance);
            material.SetFloat("_FadeDistance", settings.basicSettings.fadeDistance);
            material.SetFloat("_LayerThickness", settings.reflectionSettings.widthModifier);

            const int maxMip = 5;

            RenderTexture[]     reflectionBuffers;
            RenderTextureFormat intermediateFormat = settings.basicSettings.enableHDR ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32;

            reflectionBuffers = new RenderTexture[maxMip];
            for (int i = 0; i < maxMip; ++i)
            {
                if (fullResolutionFiltering)
                {
                    reflectionBuffers[i] = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, intermediateFormat);
                }
                else
                {
                    reflectionBuffers[i] = m_RTU.GetTemporaryRenderTexture(rtW >> i, rtH >> i, 0, intermediateFormat);
                }
                // We explicitly interpolate during bilateral upsampling.
                reflectionBuffers[i].filterMode = settings.advancedSettings.bilateralUpsample ? FilterMode.Point : FilterMode.Bilinear;
            }

            material.SetInt("_EnableSSR", 1);
            material.SetInt("_DebugMode", (int)settings.debugSettings.debugMode);

            material.SetInt("_TraceBehindObjects", settings.advancedSettings.traceBehindObjects ? 1 : 0);

            material.SetInt("_MaxSteps", settings.reflectionSettings.maxSteps);

            RenderTexture rayHitTexture = m_RTU.GetTemporaryRenderTexture(rtW, rtH);

            // We have 5 passes for different step sizes
            int tracePass = Mathf.Clamp(settings.reflectionSettings.rayStepSize, 0, 4);

            Graphics.Blit(source, rayHitTexture, material, tracePass);

            material.SetTexture("_HitPointTexture", rayHitTexture);
            // Resolve the hitpoints into the mirror reflection buffer
            Graphics.Blit(source, reflectionBuffers[0], material, (int)PassIndex.HitPointToReflections);

            material.SetTexture("_ReflectionTexture0", reflectionBuffers[0]);
            material.SetInt("_FullResolutionFiltering", fullResolutionFiltering ? 1 : 0);

            material.SetFloat("_MaxRoughness", 1.0f - settings.reflectionSettings.smoothFallbackThreshold);
            material.SetFloat("_RoughnessFalloffRange", settings.reflectionSettings.smoothFallbackDistance);

            material.SetFloat("_SSRMultiplier", settings.basicSettings.reflectionMultiplier);

            RenderTexture[] edgeTextures = new RenderTexture[maxMip];
            if (settings.advancedSettings.bilateralUpsample && useEdgeDetector)
            {
                edgeTextures[0] = m_RTU.GetTemporaryRenderTexture(rtW, rtH);
                Graphics.Blit(source, edgeTextures[0], material, (int)PassIndex.EdgeGeneration);
                for (int i = 1; i < maxMip; ++i)
                {
                    edgeTextures[i] = m_RTU.GetTemporaryRenderTexture(rtW >> i, rtH >> i);
                    material.SetInt("_LastMip", i - 1);
                    Graphics.Blit(edgeTextures[i - 1], edgeTextures[i], material, (int)PassIndex.MinMipGeneration);
                }
            }

            if (settings.advancedSettings.highQualitySharpReflections)
            {
                RenderTexture filteredReflections = m_RTU.GetTemporaryRenderTexture(reflectionBuffers[0].width, reflectionBuffers[0].height, 0, reflectionBuffers[0].format);
                filteredReflections.filterMode  = reflectionBuffers[0].filterMode;
                reflectionBuffers[0].filterMode = FilterMode.Bilinear;
                Graphics.Blit(reflectionBuffers[0], filteredReflections, material, (int)PassIndex.PoissonBlur);

                // Replace the unfiltered buffer with the newly filtered one.
                m_RTU.ReleaseTemporaryRenderTexture(reflectionBuffers[0]);
                reflectionBuffers[0] = filteredReflections;
                material.SetTexture("_ReflectionTexture0", reflectionBuffers[0]);
            }

            // Generate the blurred low-resolution buffers
            for (int i = 1; i < maxMip; ++i)
            {
                RenderTexture inputTex = reflectionBuffers[i - 1];

                RenderTexture hBlur;
                if (fullResolutionFiltering)
                {
                    hBlur = m_RTU.GetTemporaryRenderTexture(rtW, rtH, 0, intermediateFormat);
                }
                else
                {
                    int lowMip = i;
                    hBlur = m_RTU.GetTemporaryRenderTexture(rtW >> lowMip, rtH >> (i - 1), 0, intermediateFormat);
                }
                for (int j = 0; j < (fullResolutionFiltering ? (i * i) : 1); ++j)
                {
                    // Currently we blur at the resolution of the previous mip level, we could save bandwidth by blurring directly to the lower resolution.
                    material.SetVector("_Axis", new Vector4(1.0f, 0.0f, 0.0f, 0.0f));
                    material.SetFloat("_CurrentMipLevel", i - 1.0f);

                    Graphics.Blit(inputTex, hBlur, material, (int)PassIndex.Blur);

                    material.SetVector("_Axis", new Vector4(0.0f, 1.0f, 0.0f, 0.0f));

                    inputTex = reflectionBuffers[i];
                    Graphics.Blit(hBlur, inputTex, material, (int)PassIndex.Blur);
                }

                material.SetTexture("_ReflectionTexture" + i, reflectionBuffers[i]);

                m_RTU.ReleaseTemporaryRenderTexture(hBlur);
            }


            if (settings.advancedSettings.bilateralUpsample && useEdgeDetector)
            {
                for (int i = 0; i < maxMip; ++i)
                {
                    material.SetTexture("_EdgeTexture" + i, edgeTextures[i]);
                }
            }
            material.SetInt("_UseEdgeDetector", useEdgeDetector ? 1 : 0);

            RenderTexture averageRayDistanceBuffer = m_RTU.GetTemporaryRenderTexture(source.width, source.height, 0, RenderTextureFormat.RHalf);

            if (computeAverageRayDistance)
            {
                Graphics.Blit(source, averageRayDistanceBuffer, material, (int)PassIndex.AverageRayDistanceGeneration);
            }
            material.SetInt("_UseAverageRayDistance", computeAverageRayDistance ? 1 : 0);
            material.SetTexture("_AverageRayDistanceBuffer", averageRayDistanceBuffer);
            bool          resolveDiffersFromTraceRes = (settings.advancedSettings.resolution == SSRResolution.HalfTraceFullResolve);
            RenderTexture finalReflectionBuffer      = m_RTU.GetTemporaryRenderTexture(resolveDiffersFromTraceRes ? source.width : rtW, resolveDiffersFromTraceRes ? source.height : rtH, 0, intermediateFormat);

            material.SetFloat("_FresnelFade", settings.reflectionSettings.fresnelFade);
            material.SetFloat("_FresnelFadePower", settings.reflectionSettings.fresnelFadePower);
            material.SetFloat("_DistanceBlur", settings.reflectionSettings.distanceBlur);
            material.SetInt("_HalfResolution", (settings.advancedSettings.resolution != SSRResolution.FullResolution) ? 1 : 0);
            material.SetInt("_HighlightSuppression", settings.advancedSettings.highlightSuppression ? 1 : 0);
            Graphics.Blit(reflectionBuffers[0], finalReflectionBuffer, material, (int)PassIndex.CompositeSSR);
            material.SetTexture("_FinalReflectionTexture", finalReflectionBuffer);


            RenderTexture temporallyFilteredBuffer = m_RTU.GetTemporaryRenderTexture(resolveDiffersFromTraceRes ? source.width : rtW, resolveDiffersFromTraceRes ? source.height : rtH, 0, intermediateFormat);

            if (doTemporalFilterThisFrame)
            {
                material.SetInt("_UseTemporalConfidence", settings.advancedSettings.useTemporalConfidence ? 1 : 0);
                material.SetFloat("_TemporalAlpha", settings.advancedSettings.temporalFilterStrength);
                material.SetMatrix("_CurrentCameraToPreviousCamera", m_PreviousWorldToCameraMatrix * cameraToWorldMatrix);
                material.SetTexture("_PreviousReflectionTexture", m_PreviousReflectionBuffer);
                material.SetTexture("_PreviousCSZBuffer", m_PreviousDepthBuffer);
                Graphics.Blit(source, temporallyFilteredBuffer, material, (int)PassIndex.TemporalFilter);

                material.SetTexture("_FinalReflectionTexture", temporallyFilteredBuffer);
            }

            if (settings.advancedSettings.temporalFilterStrength > 0.0)
            {
                m_PreviousWorldToCameraMatrix = worldToCameraMatrix;
                PreparePreviousBuffers(source.width, source.height);
                Graphics.Blit(source, m_PreviousDepthBuffer, material, (int)PassIndex.BlitDepthAsCSZ);
                Graphics.Blit(rayHitTexture, m_PreviousHitBuffer);
                Graphics.Blit(doTemporalFilterThisFrame ? temporallyFilteredBuffer : finalReflectionBuffer, m_PreviousReflectionBuffer);

                m_HasInformationFromPreviousFrame = true;
            }


            Graphics.Blit(source, destination, material, (int)PassIndex.CompositeFinal);

            m_RTU.ReleaseAllTemporaryRenderTextures();
        }
        private void OnRenderImage(RenderTexture source, RenderTexture destination)
        {
            if (!vignette.enabled && !chromaticAberration.enabled && !distortion.enabled)
            {
                Graphics.Blit(source, destination);
                return;
            }

            material.shaderKeywords = null;

            if (distortion.enabled)
            {
                float amount = 1.6f * Math.Max(Mathf.Abs(distortion.amount), 1f);
                float theta  = 0.01745329251994f * Math.Min(160f, amount);
                float sigma  = 2f * Mathf.Tan(theta * 0.5f);
                var   p0     = new Vector4(distortion.centerX, distortion.centerY, Mathf.Max(distortion.amountX, 1e-4f), Mathf.Max(distortion.amountY, 1e-4f));
                var   p1     = new Vector3(distortion.amount >= 0f ? theta : 1f / theta, sigma, 1f / distortion.scale);
                material.EnableKeyword(distortion.amount >= 0f ? "DISTORT" : "UNDISTORT");
                material.SetVector(m_DistCenterScale, p0);
                material.SetVector(m_DistAmount, p1);
            }

            if (chromaticAberration.enabled)
            {
                material.EnableKeyword("CHROMATIC_ABERRATION");
                var chromaParams = new Vector4(chromaticAberration.color.r, chromaticAberration.color.g, chromaticAberration.color.b, chromaticAberration.amount * 0.001f);
                material.SetVector(m_ChromaticAberration, chromaParams);
            }

            if (vignette.enabled)
            {
                material.SetColor(m_VignetteColor, vignette.color);

                if (vignette.blur > 0f)
                {
                    // Downscale + gaussian blur (2 passes)
                    int w   = source.width / 2;
                    int h   = source.height / 2;
                    var rt1 = m_RTU.GetTemporaryRenderTexture(w, h, 0, source.format);
                    var rt2 = m_RTU.GetTemporaryRenderTexture(w, h, 0, source.format);

                    material.SetVector(m_BlurPass, new Vector2(1f / w, 0f));
                    Graphics.Blit(source, rt1, material, (int)Pass.BlurPrePass);

                    if (distortion.enabled)
                    {
                        material.DisableKeyword("DISTORT");
                        material.DisableKeyword("UNDISTORT");
                    }

                    material.SetVector(m_BlurPass, new Vector2(0f, 1f / h));
                    Graphics.Blit(rt1, rt2, material, (int)Pass.BlurPrePass);

                    material.SetVector(m_BlurPass, new Vector2(1f / w, 0f));
                    Graphics.Blit(rt2, rt1, material, (int)Pass.BlurPrePass);
                    material.SetVector(m_BlurPass, new Vector2(0f, 1f / h));
                    Graphics.Blit(rt1, rt2, material, (int)Pass.BlurPrePass);

                    material.SetTexture(m_BlurTex, rt2);
                    material.SetFloat(m_VignetteBlur, vignette.blur * 3f);
                    material.EnableKeyword("VIGNETTE_BLUR");

                    if (distortion.enabled)
                    {
                        material.EnableKeyword(distortion.amount >= 0f ? "DISTORT" : "UNDISTORT");
                    }
                }

                if (vignette.desaturate > 0f)
                {
                    material.EnableKeyword("VIGNETTE_DESAT");
                    material.SetFloat(m_VignetteDesat, 1f - vignette.desaturate);
                }

                material.SetVector(m_VignetteCenter, vignette.center);

                if (Mathf.Approximately(vignette.roundness, 1f))
                {
                    material.EnableKeyword("VIGNETTE_CLASSIC");
                    material.SetVector(m_VignetteSettings, new Vector2(vignette.intensity, vignette.smoothness));
                }
                else
                {
                    material.EnableKeyword("VIGNETTE_FILMIC");
                    float roundness = (1f - vignette.roundness) * 6f + vignette.roundness;
                    material.SetVector(m_VignetteSettings, new Vector3(vignette.intensity, vignette.smoothness, roundness));
                }
            }

            int pass = 0;

            if (vignette.enabled && chromaticAberration.enabled && distortion.enabled)
            {
                pass = (int)Pass.ChromaDistortVignette;
            }
            else if (vignette.enabled && chromaticAberration.enabled)
            {
                pass = (int)Pass.ChromaVignette;
            }
            else if (vignette.enabled && distortion.enabled)
            {
                pass = (int)Pass.DistortVignette;
            }
            else if (chromaticAberration.enabled && distortion.enabled)
            {
                pass = (int)Pass.ChromaDistort;
            }
            else if (vignette.enabled)
            {
                pass = (int)Pass.Vignette;
            }
            else if (chromaticAberration.enabled)
            {
                pass = (int)Pass.Chroma;
            }
            else if (distortion.enabled)
            {
                pass = (int)Pass.Distort;
            }

            Graphics.Blit(source, destination, material, pass);

            m_RTU.ReleaseAllTemporaryRenderTextures();
        }