예제 #1
0
        protected override void DrawCore(RenderDrawContext context)
        {
            var originalColorBuffer = GetSafeInput(0);
            var originalDepthBuffer = GetSafeInput(1);

            var outputTexture = GetSafeOutput(0);

            if (configurationDirty)
            {
                SetupTechnique();
            }

            // Preparation phase: create different downscaled versions of the original image, later needed by the bokeh blur shaders.
            // TODO use ImageMultiScaler instead?
            downscaledSources.Clear();

            // First we linearize the depth and compute the CoC map based on the user lens configuration.
            // Render target will contain "CoC"(16 bits) "Linear depth"(16bits).
            var cocLinearDepthTexture = GetScopedRenderTarget(originalColorBuffer.Description, 1f, PixelFormat.R16G16_Float);

            var renderView = context.RenderContext.RenderView;
            var farPlane   = renderView.FarClipPlane;

            var depthAreas = DOFAreas;

            if (AutoFocus)
            {
                // TODO replace this by physical camera parameters (aperture, focus distance...)
                var diffToTarget = (autoFocusDistanceTarget - autoFocusDistanceCurrent);
                var maxAmplitude = farPlane * 0.2f;
                diffToTarget             = MathUtil.Clamp(diffToTarget, -maxAmplitude, maxAmplitude);
                autoFocusDistanceCurrent = autoFocusDistanceCurrent + 0.1f * diffToTarget;
                if (autoFocusDistanceCurrent < renderView.NearClipPlane * 2.0f)
                {
                    autoFocusDistanceCurrent = renderView.NearClipPlane * 2.0f;
                }
                depthAreas = new Vector4(renderView.NearClipPlane, autoFocusDistanceCurrent, autoFocusDistanceCurrent, autoFocusDistanceCurrent + farPlane * 0.5f);
            }

            coclinearDepthMapEffect.SetInput(0, originalDepthBuffer);
            coclinearDepthMapEffect.SetOutput(cocLinearDepthTexture);
            coclinearDepthMapEffect.Parameters.Set(CircleOfConfusionKeys.depthAreas, ref depthAreas);
            coclinearDepthMapEffect.Parameters.Set(CameraKeys.ZProjection, CameraKeys.ZProjectionACalculate(renderView.NearClipPlane, renderView.FarClipPlane));
            coclinearDepthMapEffect.Draw(context, "CoC_LinearDepth");

            if (AutoFocus)
            {
                // Reads the center depth of the previous frame and use it as a new target
                // TODO single pixel is really small, average some disk area instead?
                pointDepthShader.Parameters.Set(PointDepthKeys.Coordinate, new Vector2(0.5f, 0.5f));
                pointDepthShader.SetInput(cocLinearDepthTexture);
                pointDepthShader.SetOutput(depthCenter1x1);
                pointDepthShader.Draw(context, "Center Depth");

                depthReadBack.SetInput(depthCenter1x1);
                depthReadBack.Draw(context, "Center_Depth_Readback");
                var centerDepth = depthReadBack.Result[0];
                autoFocusDistanceTarget = centerDepth;
            }

            // Find the smallest downscale we should go down to.
            var maxDownscale = 0;

            foreach (var cocLevel in cocLevels)
            {
                if (cocLevel.DownscaleFactor > maxDownscale)
                {
                    maxDownscale = cocLevel.DownscaleFactor;
                }
            }

            // Create a series of downscale, with anti-bleeding treatment
            for (int i = 0; i <= maxDownscale; i++)
            {
                var downSizedTexture = originalColorBuffer;
                if (i > 0)
                {
                    downSizedTexture = GetScopedRenderTarget(originalColorBuffer.Description, 1f / (float)Math.Pow(2f, i), originalColorBuffer.Description.Format);
                    textureScaler.SetInput(0, downscaledSources[i - 1]);
                    textureScaler.SetOutput(downSizedTexture);
                    textureScaler.Draw(context, "DownScale_Factor{0}", i);
                }

                downscaledSources[i] = downSizedTexture;
            }

            // We create a blurred version of the CoC map.
            // This is useful to avoid silhouettes appearing when the CoC changes abruptly.
            var blurredCoCTexture = NewScopedRenderTarget2D(cocLinearDepthTexture.Description);

            cocMapBlur.Radius = 6f / 720f * cocLinearDepthTexture.Description.Height; // 6 pixels at 720p
            cocMapBlur.SetInput(0, cocLinearDepthTexture);
            cocMapBlur.SetOutput(blurredCoCTexture);
            cocMapBlur.Draw(context, "CoC_BlurredMap");

            // Creates all the levels with different CoC strengths.
            // (Skips level with CoC 0 which is always the original buffer.)
            combineLevelsEffect.Parameters.Set(CombineLevelsFromCoCKeys.LevelCount, cocLevels.Count);
            combineLevelsEffect.SetInput(0, cocLinearDepthTexture);
            combineLevelsEffect.SetInput(1, blurredCoCTexture);
            combineLevelsEffect.SetInput(2, originalColorBuffer);

            combineLevelsFrontEffect.Parameters.Set(CombineLevelsFromCoCKeys.LevelCount, cocLevels.Count);
            combineLevelsFrontEffect.SetInput(0, cocLinearDepthTexture);
            combineLevelsFrontEffect.SetInput(1, blurredCoCTexture);
            combineLevelsFrontEffect.SetInput(2, originalColorBuffer);

            float previousCoC = 0f;

            for (int i = 1; i < cocLevels.Count; i++)
            {
                // We render a blurred version of the original scene into a downscaled render target.
                // Blur strength depends on the current level CoC value.

                var   levelConfig     = cocLevels[i];
                var   textureToBlur   = downscaledSources[levelConfig.DownscaleFactor];
                float downscaleFactor = 1f / (float)(Math.Pow(2f, levelConfig.DownscaleFactor));
                var   blurOutput      = GetScopedRenderTarget(originalColorBuffer.Description, downscaleFactor, originalColorBuffer.Description.Format);
                var   blurOutputFront = NewScopedRenderTarget2D(blurOutput.Description);
                float blurRadius      = (MaxBokehSize * BokehSizeFactor) * levelConfig.CoCValue * downscaleFactor * originalColorBuffer.Width;
                if (blurRadius < 1f)
                {
                    blurRadius = 1f;
                }

                //---------------------------------
                // Far out-of-focus
                //---------------------------------

                // Pre-process the layer for the current CoC
                // This removes areas which might wrongly bleed into our image when blurring.
                var alphaTextureToBlur = NewScopedRenderTarget2D(textureToBlur.Description);
                thresholdAlphaCoC.Parameters.Set(ThresholdAlphaCoCKeys.CoCReference, previousCoC);
                thresholdAlphaCoC.Parameters.Set(ThresholdAlphaCoCKeys.CoCCurrent, levelConfig.CoCValue);
                thresholdAlphaCoC.SetInput(0, textureToBlur);
                thresholdAlphaCoC.SetInput(1, cocLinearDepthTexture);
                thresholdAlphaCoC.SetOutput(alphaTextureToBlur);
                thresholdAlphaCoC.Draw(context, "Alphaize_Far_{0}", i);
                textureToBlur = alphaTextureToBlur;

                // TODO Quality up: make the opaque areas "bleed" into the areas we just made transparent

                // Apply the bokeh blur effect
                BokehBlur levelBlur = levelConfig.BlurEffect;
                levelBlur.CoCStrength = levelConfig.CoCValue;
                levelBlur.Radius      = blurRadius; // This doesn't generate garbage if the radius value doesn't change.
                levelBlur.SetInput(0, textureToBlur);
                levelBlur.SetOutput(blurOutput);
                levelBlur.Draw(context, "CoC_LoD_Layer_Far_{0}", i);
                combineLevelsEffect.SetInput(i + 2, blurOutput);

                //---------------------------------
                // Near out-of-focus
                //---------------------------------

                // Negates CoC values and makes background objects transparent
                thresholdAlphaCoCFront.Parameters.Set(ThresholdAlphaCoCFrontKeys.CoCReference, previousCoC);
                thresholdAlphaCoCFront.Parameters.Set(ThresholdAlphaCoCFrontKeys.CoCCurrent, levelConfig.CoCValue);
                thresholdAlphaCoCFront.SetInput(0, downscaledSources[levelConfig.DownscaleFactor]);
                thresholdAlphaCoCFront.SetInput(1, cocLinearDepthTexture);
                thresholdAlphaCoCFront.SetOutput(alphaTextureToBlur);
                thresholdAlphaCoCFront.Draw(context, "Alphaize_Near_{0}", i);
                textureToBlur = alphaTextureToBlur;

                // Apply the bokeh blur effect
                levelBlur.SetInput(0, textureToBlur);
                levelBlur.SetOutput(blurOutputFront);
                levelBlur.Draw(context, "CoC_LoD_Layer_Near_{0}", i);
                combineLevelsFrontEffect.SetInput(i + 2, blurOutputFront);

                previousCoC = levelConfig.CoCValue;
            }

            // Far out-of-focus: each pixel, depending on its CoC, interpolates its color from
            // the original color buffer and blurred buffer(s).
            combineLevelsEffect.Parameters.Set(CombineLevelsFromCoCShaderKeys.CoCLevelValues, combineShaderCocLevelValues);
            combineLevelsEffect.SetOutput(outputTexture);
            combineLevelsEffect.Draw(context, "CoCLevelCombineInterpolation");

            // Finally add front out-of-focus objects on the top of the scene

            // TODO Quality up: instead of merging all the layers for each pixel, merge only
            // the relevant layer(s) closest to the pixel CoC.
            combineLevelsFrontEffect.SetOutput(outputTexture);
            combineLevelsFrontEffect.Draw(context, "CoCLevelCombineInterpolationFront");

            // Release any reference
            downscaledSources.Clear();
        }
예제 #2
0
        // Naive approach: 6 passes
        protected void DrawCoreNaive(RenderDrawContext context)
        {
            var originalTexture = GetSafeInput(0);
            var outputTexture   = GetSafeOutput(0);

            if (rhombiTapOffsetsDirty)
            {
                CalculateRhombiOffsets();
            }

            var tapNumber = 2 * tapCount - 1;

            directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurKeys.Count, tapCount);
            directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurKeys.TotalTap, tapNumber);
            directionalBlurEffect.EffectInstance.UpdateEffect(context.GraphicsDevice);
            directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.Radius, Radius);
            directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.TapWeights, tapWeights);
            directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.CoCReference, CoCStrength);

            // Vertical blur
            var blurAngle = MathUtil.PiOverTwo + Phase;

            directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.Direction, new Vector2((float)Math.Cos(blurAngle), (float)Math.Sin(blurAngle)));

            var verticalBlurTexture = NewScopedRenderTarget2D(originalTexture.Description);

            directionalBlurEffect.SetInput(0, originalTexture);
            directionalBlurEffect.SetOutput(verticalBlurTexture);
            directionalBlurEffect.Draw(context, "TripleRhombiBokeh_RhombiABVertical_tap{0}_radius{1}", tapNumber, (int)Radius);

            // Rhombi A (top left)
            blurAngle = 7f * MathUtil.Pi / 6f + Phase;
            directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.Direction, new Vector2((float)Math.Cos(blurAngle), (float)Math.Sin(blurAngle)));

            var rhombiA = NewScopedRenderTarget2D(originalTexture.Description);

            directionalBlurEffect.SetInput(0, verticalBlurTexture);
            directionalBlurEffect.SetOutput(rhombiA);
            directionalBlurEffect.Draw(context, "TripleRhombiBokeh_RhombiA_tap{0}_radius{1}", tapNumber, (int)Radius);

            // Rhombi B (top right)
            blurAngle = -MathUtil.Pi / 6f + Phase;
            directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.Direction, new Vector2((float)Math.Cos(blurAngle), (float)Math.Sin(blurAngle)));

            var rhombiB = NewScopedRenderTarget2D(originalTexture.Description);

            directionalBlurEffect.SetInput(0, verticalBlurTexture);
            directionalBlurEffect.SetOutput(rhombiB);
            directionalBlurEffect.Draw(context, "TripleRhombiBokeh_RhombiB_tap{0}_radius{1}", tapNumber, (int)Radius);

            //Rhombi C (bottom)
            blurAngle = 7f * MathUtil.Pi / 6f + Phase;
            directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.Direction, new Vector2((float)Math.Cos(blurAngle), (float)Math.Sin(blurAngle)));

            var rhombiCTmp = NewScopedRenderTarget2D(originalTexture.Description);

            directionalBlurEffect.SetInput(0, originalTexture);
            directionalBlurEffect.SetOutput(rhombiCTmp);
            directionalBlurEffect.Draw(context, "TripleRhombiBokeh_RhombiCTmp_tap{0}_radius{1}", tapNumber, (int)Radius);

            blurAngle = -MathUtil.Pi / 6f + Phase;
            directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.Direction, new Vector2((float)Math.Cos(blurAngle), (float)Math.Sin(blurAngle)));

            var rhombiC = NewScopedRenderTarget2D(originalTexture.Description);

            directionalBlurEffect.SetInput(0, rhombiCTmp);
            directionalBlurEffect.SetOutput(rhombiC);
            directionalBlurEffect.Draw(context, "TripleRhombiBokeh_RhombiC_tap{0}_radius{1}", tapNumber, (int)Radius);

            // Final pass outputting the average of the 3 blurs
            finalCombineEffect.SetInput(0, rhombiA);
            finalCombineEffect.SetInput(1, rhombiB);
            finalCombineEffect.SetInput(2, rhombiC);
            finalCombineEffect.SetOutput(outputTexture);
            finalCombineEffect.Parameters.Set(TripleRhombiCombineShaderKeys.RhombiTapOffsets, rhombiTapOffsets);
            finalCombineEffect.Draw(context, name: "TripleRhombiBokehCombine");
        }
예제 #3
0
        protected override void DrawCore(RenderDrawContext context)
        {
            // Inputs:
            Texture colorBuffer             = GetSafeInput(0);
            Texture depthBuffer             = GetSafeInput(1);
            Texture normalsBuffer           = GetSafeInput(2);
            Texture specularRoughnessBuffer = GetSafeInput(3);

            // Output:
            Texture outputBuffer = GetSafeOutput(0);

            // Prepare
            var temporalCache = Prepare(context, outputBuffer);

            FlushCache(context.RenderContext.Time.FrameCount);

            // Get temporary buffers
            var     rayTraceBuffersSize = GetBufferResolution(outputBuffer, RayTracePassResolution);
            var     resolveBuffersSize  = GetBufferResolution(outputBuffer, ResolvePassResolution);
            Texture rayTraceBuffer      = NewScopedRenderTarget2D(rayTraceBuffersSize.Width, rayTraceBuffersSize.Height, RayTraceTargetFormat, 1);
            Texture resolveBuffer       = NewScopedRenderTarget2D(resolveBuffersSize.Width, resolveBuffersSize.Height, ReflectionsFormat, 1);

            // Check if resize depth
            Texture smallerDepthBuffer = depthBuffer;

            if (DepthResolution != ResolutionMode.Full)
            {
                // Smaller depth buffer improves ray tracing performance.

                var depthBuffersSize = GetBufferResolution(depthBuffer, DepthResolution);
                smallerDepthBuffer = NewScopedRenderTarget2D(depthBuffersSize.Width, depthBuffersSize.Height, PixelFormat.R32_Float, 1);

                depthPassShader.SetInput(0, depthBuffer);
                depthPassShader.SetOutput(smallerDepthBuffer);
                depthPassShader.Draw(context, "Downscale Depth");
            }

            // Blur Pass
            Texture blurPassBuffer;

            if (UseColorBufferMips)
            {
                // Note: using color buffer mips maps helps with reducing artifacts
                // and improves resolve pass performance (faster color texture lookups, less cache misses)
                // Also for high surface roughness values it adds more blur to the reflection tail which looks more realistic.

                // Get temp targets
                var     colorBuffersSize      = new Size2(outputBuffer.Width / 2, outputBuffer.Height / 2);
                int     colorBuffersMips      = Texture.CalculateMipMapCount(MipMapCount.Auto, colorBuffersSize.Width, colorBuffersSize.Height);
                Texture colorBuffer0          = NewScopedRenderTarget2D(colorBuffersSize.Width, colorBuffersSize.Height, ReflectionsFormat, colorBuffersMips);
                Texture colorBuffer1          = NewScopedRenderTarget2D(colorBuffersSize.Width / 2, colorBuffersSize.Height / 2, ReflectionsFormat, colorBuffersMips - 1);
                int     colorBuffer1MipOffset = 1; // For colorBuffer1 we could use one mip less (optimized)

                // Cache per color buffer mip views
                int colorBuffer0Mips = colorBuffer0.MipLevels;
                if (cachedColorBuffer0Mips == null || cachedColorBuffer0Mips.Length != colorBuffer0Mips || cachedColorBuffer0Mips[0].ParentTexture != colorBuffer0)
                {
                    cachedColorBuffer0Mips?.ForEach(view => view?.Dispose());
                    cachedColorBuffer0Mips = new Texture[colorBuffer0Mips];
                    for (int mipIndex = 0; mipIndex < colorBuffer0Mips; mipIndex++)
                    {
                        cachedColorBuffer0Mips[mipIndex] = colorBuffer0.ToTextureView(ViewType.Single, 0, mipIndex);
                    }
                }
                int colorBuffer1Mips = colorBuffer1.MipLevels;
                if (cachedColorBuffer1Mips == null || cachedColorBuffer1Mips.Length != colorBuffer1Mips || cachedColorBuffer1Mips[0].ParentTexture != colorBuffer1)
                {
                    cachedColorBuffer1Mips?.ForEach(view => view?.Dispose());
                    cachedColorBuffer1Mips = new Texture[colorBuffer1Mips];
                    for (int mipIndex = 0; mipIndex < colorBuffer1Mips; mipIndex++)
                    {
                        cachedColorBuffer1Mips[mipIndex] = colorBuffer1.ToTextureView(ViewType.Single, 0, mipIndex);
                    }
                }

                // Clone scene frame to mip 0 of colorBuffer0
                Scaler.SetInput(0, colorBuffer);
                Scaler.SetOutput(cachedColorBuffer0Mips[0]);
                Scaler.Draw(context, "Copy frame");

                // Downscale with gaussian blur
                for (int mipLevel = 1; mipLevel < colorBuffersMips; mipLevel++)
                {
                    // Blur H
                    var srcMip = cachedColorBuffer0Mips[mipLevel - 1];
                    var dstMip = cachedColorBuffer1Mips[mipLevel - colorBuffer1MipOffset];
                    blurPassShaderH.SetInput(0, srcMip);
                    blurPassShaderH.SetOutput(dstMip);
                    blurPassShaderH.Draw(context, "Blur H");

                    // Blur V
                    srcMip = dstMip;
                    dstMip = cachedColorBuffer0Mips[mipLevel];
                    blurPassShaderV.SetInput(0, srcMip);
                    blurPassShaderV.SetOutput(dstMip);
                    blurPassShaderV.Draw(context, "Blur V");
                }

                blurPassBuffer = colorBuffer0;
            }
            else
            {
                // Don't use color buffer with mip maps
                blurPassBuffer = colorBuffer;

                cachedColorBuffer0Mips?.ForEach(view => view?.Dispose());
                cachedColorBuffer1Mips?.ForEach(view => view?.Dispose());
            }

            // Ray Trace Pass
            rayTracePassShader.SetInput(0, colorBuffer);
            rayTracePassShader.SetInput(1, smallerDepthBuffer);
            rayTracePassShader.SetInput(2, normalsBuffer);
            rayTracePassShader.SetInput(3, specularRoughnessBuffer);
            rayTracePassShader.SetOutput(rayTraceBuffer);
            rayTracePassShader.Draw(context, "Ray Trace");

            // Resolve Pass
            resolvePassShader.SetInput(0, blurPassBuffer);
            resolvePassShader.SetInput(1, ResolvePassResolution == ResolutionMode.Full ? depthBuffer : smallerDepthBuffer);
            resolvePassShader.SetInput(2, normalsBuffer);
            resolvePassShader.SetInput(3, specularRoughnessBuffer);
            resolvePassShader.SetInput(4, rayTraceBuffer);
            resolvePassShader.SetOutput(resolveBuffer);
            resolvePassShader.Draw(context, "Resolve");

            // Temporal Pass
            Texture reflectionsBuffer = resolveBuffer;

            if (TemporalEffect)
            {
                var temporalSize = outputBuffer.Size;
                temporalCache.Resize(GraphicsDevice, ref temporalSize);
                Texture temporalBuffer0 = NewScopedRenderTarget2D(temporalSize.Width, temporalSize.Height, ReflectionsFormat, 1);

                temporalPassShader.SetInput(0, resolveBuffer);
                temporalPassShader.SetInput(1, temporalCache.TemporalBuffer);
                temporalPassShader.SetInput(2, depthBuffer);
                temporalPassShader.SetOutput(temporalBuffer0);
                temporalPassShader.Draw(context, "Temporal");

                context.CommandList.Copy(temporalBuffer0, temporalCache.TemporalBuffer); // TODO: use Texture.Swap from ContentStreaming branch to make it faster!

                reflectionsBuffer = temporalCache.TemporalBuffer;
            }

            // Combine Pass
            combinePassShader.SetInput(0, colorBuffer);
            combinePassShader.SetInput(1, depthBuffer);
            combinePassShader.SetInput(2, normalsBuffer);
            combinePassShader.SetInput(3, specularRoughnessBuffer);
            combinePassShader.SetInput(4, reflectionsBuffer);
            combinePassShader.SetOutput(outputBuffer);
            combinePassShader.Draw(context, "Combine");

#if SSLR_DEBUG
            if (DebugMode != DebugModes.None)
            {
                // Debug preview of temp targets
                switch (DebugMode)
                {
                case DebugModes.RayTrace:
                    Scaler.SetInput(0, rayTraceBuffer);
                    break;

                case DebugModes.Resolve:
                    Scaler.SetInput(0, resolveBuffer);
                    break;

                case DebugModes.Temporal:
                    if (temporalCache != null)
                    {
                        Scaler.SetInput(0, temporalCache.TemporalBuffer);
                    }
                    break;
                }
                Scaler.SetOutput(outputBuffer);
                Scaler.Draw(context);
            }
#endif
        }
예제 #4
0
        protected override void DrawCore(RenderDrawContext context)
        {
            var originalColorBuffer = GetSafeInput(0);
            var originalDepthBuffer = GetSafeInput(1);

            var outputTexture = GetSafeOutput(0);

            var renderView = context.RenderContext.RenderView;

            //---------------------------------
            // Ambient Occlusion
            //---------------------------------

            var tempWidth  = (originalColorBuffer.Width * (int)TempSize) / (int)TemporaryBufferSize.SizeFull;
            var tempHeight = (originalColorBuffer.Height * (int)TempSize) / (int)TemporaryBufferSize.SizeFull;
            var aoTexture1 = NewScopedRenderTarget2D(tempWidth, tempHeight, PixelFormat.R8_UNorm, 1);
            var aoTexture2 = NewScopedRenderTarget2D(tempWidth, tempHeight, PixelFormat.R8_UNorm, 1);

            aoRawImageEffect.Parameters.Set(AmbientOcclusionRawAOKeys.Count, NumberOfSamples > 0 ? NumberOfSamples : 9);

            // Set Near/Far pre-calculated factors to speed up the linear depth reconstruction
            aoRawImageEffect.Parameters.Set(CameraKeys.ZProjection, CameraKeys.ZProjectionACalculate(renderView.NearClipPlane, renderView.FarClipPlane));

            Vector4 screenSize = new Vector4(originalColorBuffer.Width, originalColorBuffer.Height, 0, 0);

            screenSize.Z = screenSize.X / screenSize.Y;
            aoRawImageEffect.Parameters.Set(AmbientOcclusionRawAOShaderKeys.ScreenInfo, screenSize);

            // Projection infor used to reconstruct the View space position from linear depth
            var     p00      = renderView.Projection.M11;
            var     p11      = renderView.Projection.M22;
            var     p02      = renderView.Projection.M13;
            var     p12      = renderView.Projection.M23;
            Vector4 projInfo = new Vector4(-2.0f / (screenSize.X * p00), -2.0f / (screenSize.Y * p11), (1.0f - p02) / p00, (1.0f + p12) / p11);

            aoRawImageEffect.Parameters.Set(AmbientOcclusionRawAOShaderKeys.ProjInfo, projInfo);

            //**********************************
            // User parameters
            aoRawImageEffect.Parameters.Set(AmbientOcclusionRawAOShaderKeys.ParamProjScale, ParamProjScale);
            aoRawImageEffect.Parameters.Set(AmbientOcclusionRawAOShaderKeys.ParamIntensity, ParamIntensity);
            aoRawImageEffect.Parameters.Set(AmbientOcclusionRawAOShaderKeys.ParamBias, ParamBias);
            aoRawImageEffect.Parameters.Set(AmbientOcclusionRawAOShaderKeys.ParamRadius, ParamRadius);
            aoRawImageEffect.Parameters.Set(AmbientOcclusionRawAOShaderKeys.ParamRadiusSquared, ParamRadius * ParamRadius);

            aoRawImageEffect.SetInput(0, originalDepthBuffer);
            aoRawImageEffect.SetOutput(aoTexture1);
            aoRawImageEffect.Draw(context, "AmbientOcclusionRawAO");

            for (int bounces = 0; bounces < NumberOfBounces; bounces++)
            {
                if (offsetsWeights == null)
                {
                    offsetsWeights = new[]
                    {
                        //  0.356642f, 0.239400f, 0.072410f, 0.009869f,
                        //  0.398943f, 0.241971f, 0.053991f, 0.004432f, 0.000134f, // stddev = 1.0
                        0.153170f, 0.144893f, 0.122649f, 0.092902f, 0.062970f,     // stddev = 2.0
                        //  0.111220f, 0.107798f, 0.098151f, 0.083953f, 0.067458f, 0.050920f, 0.036108f, // stddev = 3.0
                    };

                    nameGaussianBlurH = string.Format("AmbientOcclusionBlurH{0}x{0}", offsetsWeights.Length);
                    nameGaussianBlurV = string.Format("AmbientOcclusionBlurV{0}x{0}", offsetsWeights.Length);
                }

                // Set Near/Far pre-calculated factors to speed up the linear depth reconstruction
                var zProj = CameraKeys.ZProjectionACalculate(renderView.NearClipPlane, renderView.FarClipPlane);
                blurH.Parameters.Set(CameraKeys.ZProjection, ref zProj);
                blurV.Parameters.Set(CameraKeys.ZProjection, ref zProj);

                // Update permutation parameters
                blurH.Parameters.Set(AmbientOcclusionBlurKeys.Count, offsetsWeights.Length);
                blurH.Parameters.Set(AmbientOcclusionBlurKeys.BlurScale, BlurScale);
                blurH.Parameters.Set(AmbientOcclusionBlurKeys.EdgeSharpness, EdgeSharpness);
                blurH.EffectInstance.UpdateEffect(context.GraphicsDevice);

                blurV.Parameters.Set(AmbientOcclusionBlurKeys.Count, offsetsWeights.Length);
                blurV.Parameters.Set(AmbientOcclusionBlurKeys.BlurScale, BlurScale);
                blurV.Parameters.Set(AmbientOcclusionBlurKeys.EdgeSharpness, EdgeSharpness);
                blurV.EffectInstance.UpdateEffect(context.GraphicsDevice);

                // Update parameters
                blurH.Parameters.Set(AmbientOcclusionBlurShaderKeys.Weights, offsetsWeights);
                blurV.Parameters.Set(AmbientOcclusionBlurShaderKeys.Weights, offsetsWeights);

                // Horizontal pass
                blurH.SetInput(0, aoTexture1);
                blurH.SetInput(1, originalDepthBuffer);
                blurH.SetOutput(aoTexture2);
                blurH.Draw(context, nameGaussianBlurH);

                // Vertical pass
                blurV.SetInput(0, aoTexture2);
                blurV.SetInput(1, originalDepthBuffer);
                blurV.SetOutput(aoTexture1);
                blurV.Draw(context, nameGaussianBlurV);
            }

            aoApplyImageEffect.SetInput(0, originalColorBuffer);
            aoApplyImageEffect.SetInput(1, aoTexture1);
            aoApplyImageEffect.SetOutput(outputTexture);
            aoApplyImageEffect.Draw(context, "AmbientOcclusionApply");
        }