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; }