Ejemplo n.º 1
0
        unsafe protected override void OnRender(ViewportRenderingContext context, Component_RenderingPipeline.IFrameData frameData, ref Component_Image actualTexture)
        {
            base.OnRender(context, frameData, ref actualTexture);

            //is not supported
            if (!context.RenderingPipeline.GetUseMultiRenderTargets())
            {
                return;
            }

            //downscale for SSAA
            var actualTextureSource = actualTexture;

            if (actualTexture.Result.ResultSize != context.Owner.SizeInPixels)
            {
                actualTexture = context.RenderTarget2D_Alloc(context.Owner.SizeInPixels, actualTextureSource.Result.ResultFormat);

                //copy to scene texture with downscale
                context.SetViewport(actualTexture.Result.GetRenderTarget().Viewports[0]);

                CanvasRenderer.ShaderItem shader = new CanvasRenderer.ShaderItem();
                shader.VertexProgramFileName   = @"Base\Shaders\EffectsCommon_vs.sc";
                shader.FragmentProgramFileName = @"Base\Shaders\Effects\Downscale2_fs.sc";

                shader.Parameters.Set("sourceSizeInv", new Vector2F(1, 1) / actualTextureSource.Result.ResultSize.ToVector2F());

                shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(0 /*"sourceTexture"*/,
                                                                                   actualTextureSource, TextureAddressingMode.Clamp, FilterOption.Linear, FilterOption.Linear, FilterOption.None));

                context.RenderQuadToCurrentViewport(shader);
            }

            // Setup Constants:

            Vector2F viewportPixelSize        = new Vector2F(1.0f / (float)actualTexture.Result.ResultSize.X, 1.0f / (float)actualTexture.Result.ResultSize.Y);
            Vector2F halfViewportPixelSize    = new Vector2F(1.0f / ((float)actualTexture.Result.ResultSize.X * 0.5f), 1.0f / ((float)actualTexture.Result.ResultSize.Y * 0.5f));
            Vector4F quarterViewportPixelSize = new Vector4F(1.0f / ((float)actualTexture.Result.ResultSize.X * 0.25f), 1.0f / ((float)actualTexture.Result.ResultSize.Y * 0.25f), (float)((actualTexture.Result.ResultSize.X / 4) * (actualTexture.Result.ResultSize.Y / 4)), 0.0f);
            Vector2F viewport2xPixelSize      = new Vector2F(viewportPixelSize.X * 2.0f, viewportPixelSize.Y * 2.0f);

            Matrix4F projectionMatrix = context.Owner.CameraSettings.ProjectionMatrix.ToMatrix4F();

            float depthLinearizeMul = -projectionMatrix[3][2];
            float depthLinearizeAdd = projectionMatrix[2][2];

            if (depthLinearizeMul * depthLinearizeAdd < 0.0f)
            {
                depthLinearizeAdd = -depthLinearizeAdd;
            }

            Vector2F depthUnpackConsts = new Vector2F(depthLinearizeMul, depthLinearizeAdd);

            float tanHalfFOVY = 1.0f / projectionMatrix[1][1];
            float tanHalfFOVX = 1.0F / projectionMatrix[0][0];

            Vector2F cameraTanHalfFOV = new Vector2F(tanHalfFOVX, tanHalfFOVY);

            Vector2F NDCToViewMul = new Vector2F(cameraTanHalfFOV.X * 2.0f, cameraTanHalfFOV.Y * -2.0f);
            Vector2F NDCToViewAdd = new Vector2F(cameraTanHalfFOV.X * -1.0f, cameraTanHalfFOV.Y * 1.0f);

            Matrix4F itViewMatrix = (context.Owner.CameraSettings.ViewMatrix.GetInverse().ToMatrix4F()).GetTranspose();

            // Effect Params:

            float effectSamplingRadiusNearLimit = (float)Radius * 1.2f;

            if (Quality.Value == QualityEnum.Low)
            {
                effectSamplingRadiusNearLimit *= 1.50f;
            }

            effectSamplingRadiusNearLimit /= tanHalfFOVY;

            float effectSamplingRadiusNearLimitRec = 1.0f / effectSamplingRadiusNearLimit;

            Vector4F effectRadiusParams = new Vector4F((float)Radius, -1.0f / (float)Radius, effectSamplingRadiusNearLimitRec, 0.0f);

            float effectFadeOutMul = -1.0f / ((float)FadeOutTo - (float)FadeOutFrom);
            float effectFadeOutAdd = (float)FadeOutFrom / ((float)FadeOutTo - (float)FadeOutFrom) + 1.0f;

            float detailAOStrength     = (float)DetailStrength;
            float effectShadowStrength = (float)Multiplier;
            float effectShadowClamp    = 1.0f;
            float effectShadowPow      = (float)Power;

            float invSharpness = 1.0f - (float)Sharpness;

            if (invSharpness < 0.0f)
            {
                invSharpness = 0.0f;
            }
            if (invSharpness > 1.0f)
            {
                invSharpness = 1.0f;
            }

            // First Pass: Prepare 4 Depth half-Buffers:

            Component_Image[] halfDepths = new Component_Image[4];
            for (int i = 0; i < 4; i++)
            {
                halfDepths[i] = context.RenderTarget2D_Alloc(actualTexture.Result.ResultSize / 2, PixelFormat.Float16R);
            }

            var fourDepthsMRT = context.MultiRenderTarget_Create(new[] {
                new MultiRenderTarget.Item(halfDepths[0]),
                new MultiRenderTarget.Item(halfDepths[1]),
                new MultiRenderTarget.Item(halfDepths[2]),
                new MultiRenderTarget.Item(halfDepths[3])
            });

            {
                context.SetViewport(fourDepthsMRT.Viewports[0], Matrix4F.Identity, Matrix4F.Identity, FrameBufferTypes.All, ColorValue.Zero);

                CanvasRenderer.ShaderItem shader = new CanvasRenderer.ShaderItem();
                shader.VertexProgramFileName   = @"Base\Shaders\EffectsCommon_vs.sc";
                shader.FragmentProgramFileName = @"Base\Shaders\Effects\ASSAO\PrepareDepths_fs.sc";

                context.objectsDuringUpdate.namedTextures.TryGetValue("depthTexture", out Component_Image depthTexture);

                shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(0, depthTexture,
                                                                                   TextureAddressingMode.Clamp, FilterOption.Point, FilterOption.Point, FilterOption.None));

                shader.Parameters.Set("depthUnpackConsts", depthUnpackConsts);
                //!!!!use actualTextureSource size?
                shader.Parameters.Set("viewportPixelSize", viewportPixelSize);

                context.RenderQuadToCurrentViewport(shader);
            }

            // Second Pass: prepare 4 Mip-Maps for each Half-Depth-Map:

            Component_Image[,] depthMipMaps = null;

            if (Quality.Value > QualityEnum.Medium)
            {
                Vector2I[] mipMapSizes = new Vector2I[4];                   // Setup Mip-Map sizes:

                mipMapSizes[0] = new Vector2I(actualTexture.Result.ResultSize / 2);
                for (int m = 1; m < 4; m++)
                {
                    mipMapSizes[m] = new Vector2I(mipMapSizes[m - 1] / 2);
                }

                // Prepare MipMaps textures:

                depthMipMaps = new Component_Image[4, 4];

                for (int d = 0; d < 4; d++)
                {
                    depthMipMaps[d, 0] = halfDepths[d];                         // MipMaps 0 is original halfDepthMaps
                    for (int m = 1; m < 4; m++)
                    {
                        depthMipMaps[d, m] = context.RenderTarget2D_Alloc(mipMapSizes[m], PixelFormat.Float16R);
                    }
                }

                for (int m = 1; m < 4; m++)                  // Mip-Maps loop
                {
                    var fourDepthsMipsMRT = context.MultiRenderTarget_Create(new[] {
                        new MultiRenderTarget.Item(depthMipMaps[0, m]),
                        new MultiRenderTarget.Item(depthMipMaps[1, m]),
                        new MultiRenderTarget.Item(depthMipMaps[2, m]),
                        new MultiRenderTarget.Item(depthMipMaps[3, m])
                    });

                    context.SetViewport(fourDepthsMipsMRT.Viewports[0], Matrix4F.Identity, Matrix4F.Identity, FrameBufferTypes.All, ColorValue.Zero);

                    CanvasRenderer.ShaderItem shader = new CanvasRenderer.ShaderItem();
                    shader.VertexProgramFileName   = @"Base\Shaders\EffectsCommon_vs.sc";
                    shader.FragmentProgramFileName = @"Base\Shaders\Effects\ASSAO\PrepareDepthMips_fs.sc";

                    // For current Mip-Map generation using previous Mip-Map:

                    float    prevMipLevel  = (float)(m - 1);
                    var      prevMipSize   = mipMapSizes[m - 1];
                    Vector4F prevMipParams = new Vector4F(1.0f / (float)prevMipSize.X, 1.0f / (float)prevMipSize.Y, prevMipLevel, 0.0f);

                    for (int i = 0; i < 4; i++)
                    {
                        // previous MipMap as input:
                        shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(i, depthMipMaps[i, m - 1],
                                                                                           TextureAddressingMode.Clamp, FilterOption.Point, FilterOption.Point, FilterOption.None));
                    }
                    shader.Parameters.Set("prevMipParams", prevMipParams);
                    shader.Parameters.Set("effectRadiusParams", effectRadiusParams);

                    context.RenderQuadToCurrentViewport(shader);
                }
            }

            Component_Image SSAOTextureArray = new Component_Image();

            Component_Image SSAOBaseTextureArray = null;

            if (Quality.Value == QualityEnum.HighestAdaptive)
            {
                SSAOBaseTextureArray = new Component_Image();
                SSAOBaseTextureArray = context.RenderTarget2D_Alloc(actualTexture.Result.ResultSize / 2, PixelFormat.R8G8_UInt, 0, false, /*0,*/ 4);
            }

            Component_Image importanceMap     = null;
            Component_Image averageImportance = null;

            // Generate Importance Map for Highest/Adaptive Quality mode:
            if (Quality.Value == QualityEnum.HighestAdaptive)
            {
                // 4 SSAO passes:

                for (int pass = 0; pass < 4; pass++)
                {
                    Vector4F[] patternRotScaleMatrices;
                    GeneratePatternRotScaleMatrices(pass, out patternRotScaleMatrices);

                    Vector2F perPassFullResCoordOffset = new Vector2F((float)(pass % 2), (float)(pass / 2));

                    {
                        context.SetViewport(SSAOBaseTextureArray.Result.GetRenderTarget(0, pass).Viewports[0],
                                            Matrix4F.Identity, Matrix4F.Identity, FrameBufferTypes.All, ColorValue.Zero);

                        CanvasRenderer.ShaderItem shader = new CanvasRenderer.ShaderItem();
                        shader.VertexProgramFileName   = @"Base\Shaders\EffectsCommon_vs.sc";
                        shader.FragmentProgramFileName = @"Base\Shaders\Effects\ASSAO\GenerateSSAO_AdaptiveBase_fs.sc";

                        context.objectsDuringUpdate.namedTextures.TryGetValue("normalTexture", out Component_Image normalTexture);

                        for (int m = 0; m < 4; m++)
                        {
                            shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(m, depthMipMaps[pass, m],
                                                                                               TextureAddressingMode.Clamp, FilterOption.Point, FilterOption.Point, FilterOption.None));
                        }

                        shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(4, halfDepths[pass],
                                                                                           TextureAddressingMode.Mirror, FilterOption.Point, FilterOption.Point, FilterOption.None));

                        shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(5, normalTexture,
                                                                                           TextureAddressingMode.Clamp, FilterOption.Point, FilterOption.Point, FilterOption.None));

                        shader.Parameters.Set("NDCToViewMul", NDCToViewMul);
                        shader.Parameters.Set("NDCToViewAdd", NDCToViewAdd);
                        shader.Parameters.Set("effectRadiusParams", effectRadiusParams);
                        shader.Parameters.Set("viewportPixelSize", viewportPixelSize);
                        shader.Parameters.Set("viewport2xPixelSize", viewport2xPixelSize);
                        shader.Parameters.Set("halfViewportPixelSize", halfViewportPixelSize);
                        shader.Parameters.Set("perPassFullResCoordOffset", perPassFullResCoordOffset);
                        shader.Parameters.Set("patternRotScaleMatrices", patternRotScaleMatrices);
                        shader.Parameters.Set("effectFadeOutMul", effectFadeOutMul);
                        shader.Parameters.Set("effectFadeOutAdd", effectFadeOutAdd);
                        shader.Parameters.Set("effectShadowStrength", effectShadowStrength);
                        shader.Parameters.Set("effectShadowClamp", effectShadowClamp);
                        shader.Parameters.Set("effectShadowPow", effectShadowPow);
                        shader.Parameters.Set("detailAOStrength", detailAOStrength);
                        shader.Parameters.Set("itViewMatrix", itViewMatrix);

                        context.RenderQuadToCurrentViewport(shader);
                    }
                }

                // Importance Map Generation:
                importanceMap = context.RenderTarget2D_Alloc(actualTexture.Result.ResultSize / 4, PixelFormat.L8);
                {
                    context.SetViewport(importanceMap.Result.GetRenderTarget().Viewports[0],
                                        Matrix4F.Identity, Matrix4F.Identity, FrameBufferTypes.All, ColorValue.Zero);

                    CanvasRenderer.ShaderItem shader = new CanvasRenderer.ShaderItem();
                    shader.VertexProgramFileName   = @"Base\Shaders\EffectsCommon_vs.sc";
                    shader.FragmentProgramFileName = @"Base\Shaders\Effects\ASSAO\GenerateImportanceMap_fs.sc";

                    shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(0, SSAOBaseTextureArray,
                                                                                       TextureAddressingMode.Clamp, FilterOption.Point, FilterOption.Point, FilterOption.None));

                    shader.Parameters.Set("halfViewportPixelSize", halfViewportPixelSize);
                    shader.Parameters.Set("effectShadowStrength", effectShadowStrength);
                    shader.Parameters.Set("effectShadowPow", effectShadowPow);

                    context.RenderQuadToCurrentViewport(shader);
                }

                // Importance Map Post-Process A:
                var importanceMapPong = context.RenderTarget2D_Alloc(actualTexture.Result.ResultSize / 4, PixelFormat.L8);
                {
                    context.SetViewport(importanceMapPong.Result.GetRenderTarget().Viewports[0],
                                        Matrix4F.Identity, Matrix4F.Identity, FrameBufferTypes.All, ColorValue.Zero);

                    CanvasRenderer.ShaderItem shader = new CanvasRenderer.ShaderItem();
                    shader.VertexProgramFileName   = @"Base\Shaders\EffectsCommon_vs.sc";
                    shader.FragmentProgramFileName = @"Base\Shaders\Effects\ASSAO\PostProcessImportanceMapA_fs.sc";

                    shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(0, importanceMap,
                                                                                       TextureAddressingMode.Clamp, FilterOption.Linear, FilterOption.Linear, FilterOption.None));

                    shader.Parameters.Set("quarterViewportPixelSize", quarterViewportPixelSize);

                    context.RenderQuadToCurrentViewport(shader);
                }

                // Importance Map Post-Process B:
                {
                    context.SetViewport(importanceMap.Result.GetRenderTarget().Viewports[0],
                                        Matrix4F.Identity, Matrix4F.Identity, FrameBufferTypes.All, ColorValue.Zero);

                    CanvasRenderer.ShaderItem shader = new CanvasRenderer.ShaderItem();
                    shader.VertexProgramFileName   = @"Base\Shaders\EffectsCommon_vs.sc";
                    shader.FragmentProgramFileName = @"Base\Shaders\Effects\ASSAO\PostProcessImportanceMapB_fs.sc";

                    shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(0, importanceMapPong,
                                                                                       TextureAddressingMode.Clamp, FilterOption.Linear, FilterOption.Linear, FilterOption.None));

                    shader.Parameters.Set("quarterViewportPixelSize", quarterViewportPixelSize);

                    context.RenderQuadToCurrentViewport(shader);
                }

                context.DynamicTexture_Free(importanceMapPong);

                // Get Average Importance Pass:
                averageImportance = context.RenderTarget2D_Alloc(new Vector2I(1, 1), PixelFormat.L8);
                {
                    context.SetViewport(averageImportance.Result.GetRenderTarget().Viewports[0],
                                        Matrix4F.Identity, Matrix4F.Identity, FrameBufferTypes.All, ColorValue.Zero);

                    CanvasRenderer.ShaderItem shader = new CanvasRenderer.ShaderItem();
                    shader.VertexProgramFileName   = @"Base\Shaders\EffectsCommon_vs.sc";
                    shader.FragmentProgramFileName = @"Base\Shaders\Effects\ASSAO\GetAverageImportance_fs.sc";

                    shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(0, importanceMap,
                                                                                       TextureAddressingMode.Clamp, FilterOption.Point, FilterOption.Point, FilterOption.None));

                    shader.Parameters.Set("quarterViewportPixelSize", quarterViewportPixelSize);

                    context.RenderQuadToCurrentViewport(shader);
                }
            }

            // Third Pass: Generate 4 SSAO buffers:

            Component_Image blurPingTexture = null, blurPongTexture = null;

            if (BlurAmount.Value > 0)
            {
                blurPingTexture = context.RenderTarget2D_Alloc(actualTexture.Result.ResultSize / 2, PixelFormat.R8G8_UInt);
                blurPongTexture = context.RenderTarget2D_Alloc(actualTexture.Result.ResultSize / 2, PixelFormat.R8G8_UInt);
            }

            SSAOTextureArray = context.RenderTarget2D_Alloc(actualTexture.Result.ResultSize / 2, PixelFormat.R8G8_UInt, 0, false, /*0,*/ 4);

            for (int pass = 0; pass < 4; pass++)
            {
                Vector4F[] patternRotScaleMatrices;
                GeneratePatternRotScaleMatrices(pass, out patternRotScaleMatrices);

                Vector2F perPassFullResCoordOffset = new Vector2F((float)(pass % 2), (float)(pass / 2));

                {
                    if (BlurAmount.Value == 0)
                    {
                        context.SetViewport(SSAOTextureArray.Result.GetRenderTarget(0, pass).Viewports[0],
                                            Matrix4F.Identity, Matrix4F.Identity, FrameBufferTypes.All, ColorValue.Zero);
                    }
                    else
                    {
                        context.SetViewport(blurPingTexture.Result.GetRenderTarget().Viewports[0],
                                            Matrix4F.Identity, Matrix4F.Identity, FrameBufferTypes.All, ColorValue.Zero);
                    }

                    CanvasRenderer.ShaderItem shader = new CanvasRenderer.ShaderItem();
                    shader.VertexProgramFileName = @"Base\Shaders\EffectsCommon_vs.sc";

                    if (Quality.Value == QualityEnum.Low)
                    {
                        shader.FragmentProgramFileName = @"Base\Shaders\Effects\ASSAO\GenerateSSAO_LQ_fs.sc";
                    }
                    else if (Quality.Value == QualityEnum.Medium)
                    {
                        shader.FragmentProgramFileName = @"Base\Shaders\Effects\ASSAO\GenerateSSAO_MQ_fs.sc";
                    }
                    else if (Quality.Value == QualityEnum.High)
                    {
                        shader.FragmentProgramFileName = @"Base\Shaders\Effects\ASSAO\GenerateSSAO_HQ_fs.sc";
                    }
                    else if (Quality.Value == QualityEnum.HighestAdaptive)
                    {
                        shader.FragmentProgramFileName = @"Base\Shaders\Effects\ASSAO\GenerateSSAO_HAQ_fs.sc";
                    }

                    context.objectsDuringUpdate.namedTextures.TryGetValue("normalTexture", out Component_Image normalTexture);

                    if (Quality.Value > QualityEnum.Medium)
                    {
                        for (int m = 0; m < 4; m++)
                        {
                            shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(m, depthMipMaps[pass, m],
                                                                                               TextureAddressingMode.Clamp, FilterOption.Point, FilterOption.Point, FilterOption.None));
                        }

                        shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(4, halfDepths[pass],
                                                                                           TextureAddressingMode.Mirror, FilterOption.Point, FilterOption.Point, FilterOption.None));

                        shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(5, normalTexture,
                                                                                           TextureAddressingMode.Clamp, FilterOption.Point, FilterOption.Point, FilterOption.None));

                        if (Quality.Value == QualityEnum.HighestAdaptive)
                        {
                            shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(6, importanceMap,
                                                                                               TextureAddressingMode.Clamp, FilterOption.Linear, FilterOption.Linear, FilterOption.None));
                            shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(7, averageImportance,
                                                                                               TextureAddressingMode.Clamp, FilterOption.Point, FilterOption.Point, FilterOption.None));
                            shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(8, SSAOBaseTextureArray,
                                                                                               TextureAddressingMode.Clamp, FilterOption.Point, FilterOption.Point, FilterOption.None));
                        }
                    }
                    else
                    {
                        shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(0, halfDepths[pass],
                                                                                           TextureAddressingMode.Clamp, FilterOption.Point, FilterOption.Point, FilterOption.None));

                        shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(1, halfDepths[pass],
                                                                                           TextureAddressingMode.Mirror, FilterOption.Point, FilterOption.Point, FilterOption.None));

                        shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(2, normalTexture,
                                                                                           TextureAddressingMode.Clamp, FilterOption.Point, FilterOption.Point, FilterOption.None));
                    }

                    shader.Parameters.Set("NDCToViewMul", NDCToViewMul);
                    shader.Parameters.Set("NDCToViewAdd", NDCToViewAdd);
                    shader.Parameters.Set("effectRadiusParams", effectRadiusParams);
                    shader.Parameters.Set("viewportPixelSize", viewportPixelSize);
                    shader.Parameters.Set("viewport2xPixelSize", viewport2xPixelSize);
                    shader.Parameters.Set("halfViewportPixelSize", halfViewportPixelSize);
                    shader.Parameters.Set("perPassFullResCoordOffset", perPassFullResCoordOffset);
                    shader.Parameters.Set("patternRotScaleMatrices", patternRotScaleMatrices);
                    shader.Parameters.Set("effectFadeOutMul", effectFadeOutMul);
                    shader.Parameters.Set("effectFadeOutAdd", effectFadeOutAdd);
                    shader.Parameters.Set("effectShadowStrength", effectShadowStrength);
                    shader.Parameters.Set("effectShadowClamp", effectShadowClamp);
                    shader.Parameters.Set("effectShadowPow", effectShadowPow);
                    shader.Parameters.Set("detailAOStrength", detailAOStrength);
                    shader.Parameters.Set("itViewMatrix", itViewMatrix);

                    if (Quality.Value == QualityEnum.HighestAdaptive)
                    {
                        shader.Parameters.Set("adaptiveSampleCountLimit", (float)AdaptiveQualityLimit);
                        shader.Parameters.Set("passNumber", (float)pass);
                    }

                    context.RenderQuadToCurrentViewport(shader);
                }

                if (Quality.Value > QualityEnum.Medium)
                {
                    // Free Mip-Maps Targets for this Pass:
                    for (int m = 0; m < 4; m++)
                    {
                        context.DynamicTexture_Free(depthMipMaps[pass, m]);
                    }
                }
                else
                {
                    context.DynamicTexture_Free(halfDepths[pass]);
                }

                // Blur SSAO Texture:

                if (BlurAmount.Value > 0)
                {
                    int wideBlursRemaining = Math.Max(0, BlurAmount.Value - 2);

                    for (int i = 0; i < BlurAmount.Value; i++)
                    {
                        if (i == (BlurAmount.Value - 1))
                        {
                            context.SetViewport(SSAOTextureArray.Result.GetRenderTarget(0, pass).Viewports[0],
                                                Matrix4F.Identity, Matrix4F.Identity, FrameBufferTypes.All, ColorValue.Zero);
                        }
                        else
                        {
                            context.SetViewport(blurPongTexture.Result.GetRenderTarget().Viewports[0],
                                                Matrix4F.Identity, Matrix4F.Identity, FrameBufferTypes.All, ColorValue.Zero);
                        }

                        CanvasRenderer.ShaderItem shader = new CanvasRenderer.ShaderItem();
                        shader.VertexProgramFileName = @"Base\Shaders\EffectsCommon_vs.sc";

                        if (Quality.Value > QualityEnum.Low)
                        {
                            if (wideBlursRemaining > 0)
                            {
                                shader.FragmentProgramFileName = @"Base\Shaders\Effects\ASSAO\SmartBlurWide_fs.sc";
                                wideBlursRemaining--;
                            }
                            else
                            {
                                shader.FragmentProgramFileName = @"Base\Shaders\Effects\ASSAO\SmartBlur_fs.sc";
                            }
                        }
                        else
                        {
                            shader.FragmentProgramFileName = @"Base\Shaders\Effects\ASSAO\NonSmartBlur_fs.sc";
                        }

                        if (Quality.Value > QualityEnum.Low)
                        {
                            shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(0, blurPingTexture,
                                                                                               TextureAddressingMode.Mirror, FilterOption.Point, FilterOption.Point, FilterOption.None));
                            shader.Parameters.Set("invSharpness", invSharpness);
                        }
                        else
                        {
                            shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(0, blurPingTexture,
                                                                                               TextureAddressingMode.Clamp, FilterOption.Linear, FilterOption.Linear, FilterOption.None));
                        }

                        shader.Parameters.Set("halfViewportPixelSize", halfViewportPixelSize);

                        context.RenderQuadToCurrentViewport(shader);

                        // Swap Ping-Pong Blur textures:
                        var tmp_tex = blurPingTexture;
                        blurPingTexture = blurPongTexture;
                        blurPongTexture = tmp_tex;
                    }
                }
            }

            if (Quality.Value == QualityEnum.HighestAdaptive)
            {
                context.DynamicTexture_Free(SSAOBaseTextureArray);
            }

            if (Quality.Value == QualityEnum.HighestAdaptive)
            {
                context.DynamicTexture_Free(importanceMap);
                context.DynamicTexture_Free(averageImportance);
            }

            if (BlurAmount.Value > 0)
            {
                // Free Blur ping/pong Targets:
                context.DynamicTexture_Free(blurPingTexture);
                context.DynamicTexture_Free(blurPongTexture);
            }

            // 4th Pass: Apply 4 SSAO Textures to Final SSAO Result:

            var FullSSAOTexture = context.RenderTarget2D_Alloc(actualTexture.Result.ResultSize, PixelFormat.R8G8_UInt);

            {
                context.SetViewport(FullSSAOTexture.Result.GetRenderTarget().Viewports[0],
                                    Matrix4F.Identity, Matrix4F.Identity, FrameBufferTypes.All, ColorValue.Zero);

                CanvasRenderer.ShaderItem shader = new CanvasRenderer.ShaderItem();
                shader.VertexProgramFileName = @"Base\Shaders\EffectsCommon_vs.sc";

                if (Quality.Value > QualityEnum.Low)
                {
                    shader.FragmentProgramFileName = @"Base\Shaders\Effects\ASSAO\Apply_fs.sc";
                }
                else
                {
                    shader.FragmentProgramFileName = @"Base\Shaders\Effects\ASSAO\Apply_noSmart_fs.sc";
                }

                if (Quality.Value > QualityEnum.Low)
                {
                    shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(0, SSAOTextureArray,
                                                                                       TextureAddressingMode.Clamp, FilterOption.Point, FilterOption.Point, FilterOption.None));

                    shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(1, SSAOTextureArray,
                                                                                       TextureAddressingMode.Clamp, FilterOption.Linear, FilterOption.Linear, FilterOption.None));
                }
                else
                {
                    shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(0, SSAOTextureArray,
                                                                                       TextureAddressingMode.Clamp, FilterOption.Linear, FilterOption.Linear, FilterOption.None));
                }

                if (Quality.Value > QualityEnum.Low)
                {
                    shader.Parameters.Set("invSharpness", invSharpness);
                    shader.Parameters.Set("halfViewportPixelSize", halfViewportPixelSize);
                }

                context.RenderQuadToCurrentViewport(shader);
            }

            // Free SSAO Texture Array Target:
            context.DynamicTexture_Free(SSAOTextureArray);

            // 5th Final Pass:
            var finalTexture = context.RenderTarget2D_Alloc(actualTextureSource.Result.ResultSize, actualTextureSource.Result.ResultFormat);

            {
                context.SetViewport(finalTexture.Result.GetRenderTarget().Viewports[0]);

                CanvasRenderer.ShaderItem shader = new CanvasRenderer.ShaderItem();
                shader.VertexProgramFileName   = @"Base\Shaders\EffectsCommon_vs.sc";
                shader.FragmentProgramFileName = @"Base\Shaders\Effects\ASSAO\Final_fs.sc";

                shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(0, actualTextureSource,
                                                                                   TextureAddressingMode.Clamp, FilterOption.Point, FilterOption.Point, FilterOption.None));

                shader.Parameters.Set(new ViewportRenderingContext.BindTextureData(1, FullSSAOTexture,
                                                                                   TextureAddressingMode.Clamp, FilterOption.Point, FilterOption.Point, FilterOption.None));

                shader.Parameters.Set("intensity", (float)Intensity);
                shader.Parameters.Set("showAO", ShowAO ? 1.0f : -1.0f);

                context.RenderQuadToCurrentViewport(shader);
            }

            // Free Targets:
            context.DynamicTexture_Free(actualTexture);
            if (actualTextureSource != actualTexture)
            {
                context.DynamicTexture_Free(actualTextureSource);
            }
            context.DynamicTexture_Free(FullSSAOTexture);

            // Update actual Texture:
            actualTexture = finalTexture;
        }