// 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"); }
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 }
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"); }