Esempio n. 1
0
        // Naive approach: 4 passes. (Reference version)
        private void DrawCoreNaive(RenderDrawContext context)
        {
            var originalTexture = GetSafeInput(0);
            var outputTexture   = GetSafeOutput(0);

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

            // Blur in one direction
            var blurAngle = Phase;

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

            var firstBlurTexture = NewScopedRenderTarget2D(originalTexture.Description);

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

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

            var diagonalBlurA = NewScopedRenderTarget2D(originalTexture.Description);

            directionalBlurEffect.SetInput(0, firstBlurTexture);
            directionalBlurEffect.SetOutput(diagonalBlurA);
            directionalBlurEffect.Draw((RenderDrawContext)context, "McIntoshBokehPass2A_tap{0}_radius{1}", tapNumber, (int)Radius);

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

            var diagonalBlurB = NewScopedRenderTarget2D(originalTexture.Description);

            directionalBlurEffect.SetInput(0, firstBlurTexture);
            directionalBlurEffect.SetOutput(diagonalBlurB);
            directionalBlurEffect.Draw((RenderDrawContext)context, "McIntoshBokehPass2B_tap{0}_radius{1}", tapNumber, (int)Radius);

            // Final pass outputting the min of A and B
            finalCombineEffect.SetInput(0, diagonalBlurA);
            finalCombineEffect.SetInput(1, diagonalBlurB);
            finalCombineEffect.SetOutput(outputTexture);
            finalCombineEffect.Draw(context, name: "McIntoshBokehPassCombine");
        }
Esempio n. 2
0
            public void Draw(RenderDrawContext context, float sigmaRatio, Texture inputTexture, Texture outputTexture)
            {
                // Check if we need to regenerate offsetsWeights
                if (offsetsWeights == null || this.sigmaRatio != sigmaRatio)
                {
                    offsetsWeights = GaussianUtil.Calculate1D(Radius, sigmaRatio);

                    // Update parameters
                    blurH.Parameters.Set(GaussianBlurShaderKeys.OffsetsWeights, offsetsWeights);
                    blurV.Parameters.Set(GaussianBlurShaderKeys.OffsetsWeights, offsetsWeights);

                    this.sigmaRatio = sigmaRatio;
                }

                // Get a temporary texture for the intermediate pass
                // This texture will be allocated only in the scope of this draw and returned to the pool at the exit of this method
                var desc = inputTexture.Description;

                desc.MultisampleCount = MultisampleCount.None; // TODO we should have a method to get a non-multisampled RT
                var outputTextureH = gaussianBlur.NewScopedRenderTarget2D(desc);

                // Horizontal pass
                blurH.SetInput(inputTexture);
                blurH.SetOutput(outputTextureH);
                blurH.Draw(context, nameGaussianBlurH);

                // Vertical pass
                blurV.SetInput(outputTextureH);
                blurV.SetOutput(outputTexture);
                blurV.Draw(context, nameGaussianBlurV);
            }
Esempio n. 3
0
        protected override void DrawCore(RenderDrawContext context)
        {
            // Update the weight array if necessary
            if (weightsDirty || tapCount == 0)
            {
                weightsDirty = false;
                Vector2[] gaussianWeights = GaussianUtil.Calculate1D((int)Radius, 2f, true);
                tapCount   = gaussianWeights.Length;
                tapWeights = new float[tapCount];
                for (int i = 0; i < tapCount; i++)
                {
                    tapWeights[i] = gaussianWeights[i].Y;
                }
            }

            var originalTexture = GetSafeInput(0);
            var outputTexture   = GetSafeOutput(0);

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

            // Blur in one direction
            var blurAngle = 0f;

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

            var firstBlurTexture = NewScopedRenderTarget2D(originalTexture.Description);

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

            // Second blur pass to ouput the final result
            blurAngle = MathUtil.PiOverTwo;
            directionalBlurEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.Direction, new Vector2((float)Math.Cos(blurAngle), (float)Math.Sin(blurAngle)));

            directionalBlurEffect.SetInput(0, firstBlurTexture);
            directionalBlurEffect.SetOutput(outputTexture);
            directionalBlurEffect.Draw(context, "GaussianBokehPass2_tap{0}_radius{1}", tapNumber, (int)Radius);
        }
Esempio n. 4
0
        protected override void DrawCore(RenderDrawContext context)
        {
            var input  = GetInput(0);
            var output = GetOutput(0);

            if (FadeOutSpeed == 0f)
            {
                // Nothing to do
                if (input != output)
                {
                    context.CommandList.Copy(input, output);
                }
                return;
            }

            if (input == output)
            {
                var newInput = NewScopedRenderTarget2D(input.Description);
                context.CommandList.Copy(input, newInput);
                input = newInput;
            }

            // Check we have a render target to hold the persistence over a few frames
            if (persistenceTexture == null || persistenceTexture.Description != output.Description)
            {
                // We need to re-allocate the texture
                if (persistenceTexture != null)
                {
                    Context.Allocator.ReleaseReference(persistenceTexture);
                }

                persistenceTexture = Context.Allocator.GetTemporaryTexture2D(output.Description);
                // Initializes to black
                context.CommandList.Clear(persistenceTexture, Color.Black);
            }

            var accumulationPersistence = NewScopedRenderTarget2D(persistenceTexture.Description);

            // For persistence, we combine the current brightness with the one of the previous frames.
            bloomAfterimageShader.Parameters.Set(BloomAfterimageShaderKeys.FadeOutSpeed, FadeOutSpeed);
            bloomAfterimageShader.Parameters.Set(BloomAfterimageShaderKeys.Sensitivity, Sensitivity / 100f);
            bloomAfterimageShader.SetInput(0, input);
            bloomAfterimageShader.SetInput(1, persistenceTexture);
            bloomAfterimageShader.SetOutput(accumulationPersistence);
            bloomAfterimageShader.Draw(context, "Afterimage persistence accumulation");

            // Keep the final brightness buffer for the following frames
            context.CommandList.Copy(accumulationPersistence, persistenceTexture);

            // Merge persistence and current bloom into the final result
            bloomAfterimageCombineShader.SetInput(0, input);
            bloomAfterimageCombineShader.SetInput(1, persistenceTexture);
            bloomAfterimageCombineShader.SetOutput(output);
            bloomAfterimageCombineShader.Draw(context, "Afterimage persistence combine");
        }
Esempio n. 5
0
        protected override void DrawCore(RenderDrawContext context)
        {
            // Updates the weight array if necessary
            if (weightsDirty || tapCount == 0)
            {
                weightsDirty = false;
                Vector2[] gaussianWeights = GaussianUtil.Calculate1D((int)radius, 2f, true);
                tapCount   = gaussianWeights.Length;
                tapWeights = gaussianWeights;
            }

            var originalTexture = GetSafeInput(0);
            var outputTexture   = GetSafeOutput(0);

            cocBlurEffect.Parameters.Set(DepthAwareDirectionalBlurKeys.Count, tapCount);
            cocBlurEffect.EffectInstance.UpdateEffect(context.GraphicsDevice);
            cocBlurEffect.Parameters.Set(CoCMapBlurShaderKeys.Radius, radius);
            cocBlurEffect.Parameters.Set(CoCMapBlurShaderKeys.OffsetsWeights, tapWeights);
            var tapNumber = 2 * tapCount - 1;

            // Blur in one direction
            var blurAngle = 0f;

            cocBlurEffect.Parameters.Set(CoCMapBlurShaderKeys.Direction, new Vector2(MathF.Cos(blurAngle), MathF.Sin(blurAngle)));

            var firstBlurTexture = NewScopedRenderTarget2D(originalTexture.Description);

            cocBlurEffect.SetInput(0, originalTexture);
            cocBlurEffect.SetOutput(firstBlurTexture);
            cocBlurEffect.Draw(context, "CoCMapBlurPass1_tap{0}_radius{1}", tapNumber, (int)radius);

            // Second blur pass to ouput the final result
            blurAngle = MathUtil.PiOverTwo;
            cocBlurEffect.Parameters.Set(CoCMapBlurShaderKeys.Direction, new Vector2(MathF.Cos(blurAngle), MathF.Sin(blurAngle)));

            cocBlurEffect.SetInput(0, firstBlurTexture);
            cocBlurEffect.SetOutput(outputTexture);
            cocBlurEffect.Draw(context, "CoCMapBlurPass2_tap{0}_radius{1}", tapNumber, (int)radius);
        }
Esempio n. 6
0
        // Optimized approach: 2 passes.
        private void DrawCoreOptimized(RenderDrawContext context)
        {
            var originalTexture = GetSafeInput(0);

            var outputTexture = GetSafeOutput(0);

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

            // Blur in one direction
            var blurAngle = Phase;

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

            var firstBlurTexture = NewScopedRenderTarget2D(originalTexture.Description);

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

            // Calculates the 2 diagonal blurs and keep the min of them
            var diagonalBlurAngleA = +MathUtil.Pi / 3f + Phase;
            var diagonalBlurAngleB = -MathUtil.Pi / 3f + Phase;

            optimizedEffect.SetInput(0, firstBlurTexture);
            optimizedEffect.SetOutput(outputTexture);
            optimizedEffect.Parameters.Set(DepthAwareDirectionalBlurKeys.Count, tapCount);
            optimizedEffect.Parameters.Set(DepthAwareDirectionalBlurKeys.TotalTap, tapNumber);
            optimizedEffect.EffectInstance.UpdateEffect(context.GraphicsDevice);
            optimizedEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.Radius.ComposeWith("directionalBlurA"), Radius);
            optimizedEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.Direction.ComposeWith("directionalBlurA"), new Vector2((float)Math.Cos(diagonalBlurAngleA), (float)Math.Sin(diagonalBlurAngleA)));
            optimizedEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.TapWeights.ComposeWith("directionalBlurA"), tapWeights);
            optimizedEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.Radius.ComposeWith("directionalBlurB"), Radius);
            optimizedEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.Direction.ComposeWith("directionalBlurB"), new Vector2((float)Math.Cos(diagonalBlurAngleB), (float)Math.Sin(diagonalBlurAngleB)));
            optimizedEffect.Parameters.Set(DepthAwareDirectionalBlurUtilKeys.TapWeights.ComposeWith("directionalBlurB"), tapWeights);
            optimizedEffect.Draw((RenderDrawContext)context, "McIntoshBokehPass2_BlurABCombine_tap{0}_radius{1}", tapNumber, (int)Radius);
        }
Esempio n. 7
0
        protected override void DrawCore(RenderDrawContext context)
        {
            Texture color  = GetInput(0);
            Texture output = GetOutput(0);

            if (color is null || output is null || depthTexture is null)
            {
                return;
            }

            fogFilter.Parameters.Set(FogEffectKeys.FogColor, Color);
            fogFilter.Parameters.Set(FogEffectKeys.Density, Density);
            fogFilter.Parameters.Set(FogEffectKeys.DepthTexture, depthTexture);
            fogFilter.Parameters.Set(FogEffectKeys.zFar, zMax);
            fogFilter.Parameters.Set(FogEffectKeys.zNear, zMin);
            fogFilter.Parameters.Set(FogEffectKeys.FogStart, FogStart);
            fogFilter.Parameters.Set(FogEffectKeys.skipBackground, SkipBackground);

            fogFilter.SetInput(0, color);
            fogFilter.SetOutput(output);

            fogFilter.Draw(context);
        }
Esempio n. 8
0
        protected override void DrawCore(RenderDrawContext context)
        {
            Texture color  = GetInput(0);
            Texture output = GetOutput(0);

            if (color is null || output is null || depthTexture is null)
            {
                return;
            }

            outlineFilter.Parameters.Set(OutlineEffectKeys.ScreenDiffs, new Vector2(0.5f / color.Width, 0.5f / color.Height));
            outlineFilter.Parameters.Set(OutlineEffectKeys.DepthTexture, depthTexture);
            outlineFilter.Parameters.Set(OutlineEffectKeys.zFar, zMax);
            outlineFilter.Parameters.Set(OutlineEffectKeys.zNear, zMin);

            outlineFilter.Parameters.Set(OutlineEffectKeys.NormalWeight, NormalWeight);
            outlineFilter.Parameters.Set(OutlineEffectKeys.DepthWeight, DepthWeight);
            outlineFilter.Parameters.Set(OutlineEffectKeys.NormalNearCutoff, NormalNearCutoff);

            outlineFilter.SetInput(0, color);
            outlineFilter.SetOutput(output);
            outlineFilter.Draw(context);
        }
Esempio n. 9
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();
        }
Esempio n. 10
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
        }
Esempio n. 11
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");
        }
Esempio n. 12
0
        protected override void DrawCore(RenderDrawContext context)
        {
            var input  = GetInput(0);
            var output = GetOutput(0);

            if (input is null || output is null)
            {
                return;
            }

            var inputDepthTexture = GetInput(1); // Depth

            // Update the parameters for this post effect
            if (!Enabled)
            {
                if (input != output)
                {
                    Scaler.SetInput(input);
                    Scaler.SetOutput(output);
                    Scaler.Draw(context);
                }
                return;
            }

            // If input == output, copy the input to a temporary texture
            if (input == output)
            {
                var newInput = NewScopedRenderTarget2D(input.Width, input.Height, input.Format);
                context.CommandList.Copy(input, newInput);
                input = newInput;
            }

            var currentInput = input;

            // Draw outline before AA
            if (Outline.Enabled && inputDepthTexture != null)
            {
                // Outline
                var outlineOutput = NewScopedRenderTarget2D(input.Width, input.Height, input.Format);
                Outline.SetColorDepthInput(currentInput, inputDepthTexture, context.RenderContext.RenderView.NearClipPlane, context.RenderContext.RenderView.FarClipPlane);
                Outline.SetOutput(outlineOutput);
                Outline.Draw(context);
                currentInput = outlineOutput;
            }

            var  fxaa    = Antialiasing as FXAAEffect;
            bool aaFirst = Bloom != null && Bloom.StableConvolution;
            bool needAA  = Antialiasing != null && Antialiasing.Enabled;

            // Do AA here, first. (hybrid method from Karis2013)
            if (aaFirst && needAA)
            {
                // do AA:
                if (fxaa != null)
                {
                    fxaa.InputLuminanceInAlpha = true;
                }

                var bufferIndex = 1;
                if (Antialiasing.RequiresDepthBuffer)
                {
                    Antialiasing.SetInput(bufferIndex++, inputDepthTexture);
                }

                bool requiresVelocityBuffer = Antialiasing.RequiresVelocityBuffer;
                if (requiresVelocityBuffer)
                {
                    Antialiasing.SetInput(bufferIndex++, GetInput(6));
                }

                var aaSurface = NewScopedRenderTarget2D(input.Width, input.Height, input.Format);
                if (Antialiasing.NeedRangeDecompress)
                {
                    // Explanation:
                    //   The Karis method (Unreal Engine 4.1x), uses a hybrid pipeline to execute AA.
                    //   The AA is usually done at the end of the pipeline, but we don't benefit from
                    //   AA for the posteffects, which is a shame.
                    //   The Karis method, executes AA at the beginning, but for AA to be correct, it
                    //   must work post tonemapping, and even more in fact, in gamma space too. Plus,
                    //   it waits for the alpha=luma to be a "perceptive luma" so also gamma space.
                    //   In our case, working in gamma space created monstruous outlining artefacts
                    //   around exageratedly strong constrasted objects (way in HDR range).
                    //   So AA works in linear space, but still with gamma luma, as a light tradeoff
                    //   to supress artefacts.

                    // Create a 16 bits target for FXAA:

                    // Render range compression & perceptual luma to alpha channel:
                    rangeCompress.SetInput(currentInput);
                    rangeCompress.SetOutput(aaSurface);
                    rangeCompress.Draw(context);

                    Antialiasing.SetInput(0, aaSurface);
                    Antialiasing.SetOutput(currentInput);
                    Antialiasing.Draw(context);

                    // Reverse tone LDR to HDR:
                    rangeDecompress.SetInput(currentInput);
                    rangeDecompress.SetOutput(aaSurface);
                    rangeDecompress.Draw(context);
                }
                else
                {
                    Antialiasing.SetInput(0, currentInput);
                    Antialiasing.SetOutput(aaSurface);
                    Antialiasing.Draw(context);
                }

                currentInput = aaSurface;
            }

            if (AmbientOcclusion.Enabled && inputDepthTexture != null)
            {
                // Ambient Occlusion
                var aoOutput = NewScopedRenderTarget2D(input.Width, input.Height, input.Format);
                AmbientOcclusion.SetColorDepthInput(currentInput, inputDepthTexture);
                AmbientOcclusion.SetOutput(aoOutput);
                AmbientOcclusion.Draw(context);
                currentInput = aoOutput;
            }

            if (LocalReflections.Enabled && inputDepthTexture != null)
            {
                var normalsBuffer           = GetInput(2);
                var specularRoughnessBuffer = GetInput(3);

                if (normalsBuffer != null && specularRoughnessBuffer != null)
                {
                    // Local reflections
                    var rlrOutput = NewScopedRenderTarget2D(input.Width, input.Height, input.Format);
                    LocalReflections.SetInputSurfaces(currentInput, inputDepthTexture, normalsBuffer, specularRoughnessBuffer);
                    LocalReflections.SetOutput(rlrOutput);
                    LocalReflections.Draw(context);
                    currentInput = rlrOutput;
                }
            }

            if (DepthOfField.Enabled && inputDepthTexture != null)
            {
                // DoF
                var dofOutput = NewScopedRenderTarget2D(input.Width, input.Height, input.Format);
                DepthOfField.SetColorDepthInput(currentInput, inputDepthTexture);
                DepthOfField.SetOutput(dofOutput);
                DepthOfField.Draw(context);
                currentInput = dofOutput;
            }

            if (Fog.Enabled && inputDepthTexture != null)
            {
                // Fog
                var fogOutput = NewScopedRenderTarget2D(input.Width, input.Height, input.Format);
                Fog.SetColorDepthInput(currentInput, inputDepthTexture, context.RenderContext.RenderView.NearClipPlane, context.RenderContext.RenderView.FarClipPlane);
                Fog.SetOutput(fogOutput);
                Fog.Draw(context);
                currentInput = fogOutput;
            }

            // Luminance pass (only if tone mapping is enabled)
            // TODO: This is not super pluggable to have this kind of dependencies. Check how to improve this
            var toneMap = colorTransformsGroup.Transforms.Get <ToneMap>();

            if (colorTransformsGroup.Enabled && toneMap != null && toneMap.Enabled)
            {
                Texture luminanceTexture = null;
                if (toneMap.UseLocalLuminance)
                {
                    const int localLuminanceDownScale = 3;

                    // The luminance chain uses power-of-two intermediate targets, so it expects to output to one as well
                    var lumWidth = Math.Min(MathUtil.NextPowerOfTwo(currentInput.Size.Width), MathUtil.NextPowerOfTwo(currentInput.Size.Height));
                    lumWidth = Math.Max(1, lumWidth / 2);

                    var lumSize = new Size3(lumWidth, lumWidth, 1).Down2(localLuminanceDownScale);
                    luminanceTexture = NewScopedRenderTarget2D(lumSize.Width, lumSize.Height, PixelFormat.R16_Float, 1);

                    luminanceEffect.SetOutput(luminanceTexture);
                }

                luminanceEffect.EnableLocalLuminanceCalculation = toneMap.UseLocalLuminance;
                luminanceEffect.SetInput(currentInput);
                luminanceEffect.Draw(context);

                // Set this parameter that will be used by the tone mapping
                colorTransformsGroup.Parameters.Set(LuminanceEffect.LuminanceResult, new LuminanceResult(luminanceEffect.AverageLuminance, luminanceTexture));
            }

            if (BrightFilter.Enabled && (Bloom.Enabled || LightStreak.Enabled || LensFlare.Enabled))
            {
                Texture brightTexture = NewScopedRenderTarget2D(currentInput.Width, currentInput.Height, currentInput.Format, 1);

                // Bright filter pass

                BrightFilter.SetInput(currentInput);
                BrightFilter.SetOutput(brightTexture);
                BrightFilter.Draw(context);

                // Bloom pass
                if (Bloom.Enabled)
                {
                    Bloom.SetInput(brightTexture);
                    Bloom.SetOutput(currentInput);
                    Bloom.Draw(context);
                }

                // Light streak pass
                if (LightStreak.Enabled)
                {
                    LightStreak.SetInput(brightTexture);
                    LightStreak.SetOutput(currentInput);
                    LightStreak.Draw(context);
                }

                // Lens flare pass
                if (LensFlare.Enabled)
                {
                    LensFlare.SetInput(brightTexture);
                    LensFlare.SetOutput(currentInput);
                    LensFlare.Draw(context);
                }
            }

            bool aaLast     = needAA && !aaFirst;
            var  toneOutput = aaLast ? NewScopedRenderTarget2D(input.Width, input.Height, input.Format) : output;

            // When FXAA is enabled we need to detect whether the ColorTransformGroup should output the Luminance into the alpha or not
            var luminanceToChannelTransform = colorTransformsGroup.PostTransforms.Get <LuminanceToChannelTransform>();

            if (fxaa != null)
            {
                if (luminanceToChannelTransform is null)
                {
                    luminanceToChannelTransform = new LuminanceToChannelTransform {
                        ColorChannel = ColorChannel.A
                    };
                    colorTransformsGroup.PostTransforms.Add(luminanceToChannelTransform);
                }

                // Only enabled when FXAA is enabled and InputLuminanceInAlpha is true
                luminanceToChannelTransform.Enabled = fxaa.Enabled && fxaa.InputLuminanceInAlpha;
            }
            else if (luminanceToChannelTransform != null)
            {
                luminanceToChannelTransform.Enabled = false;
            }

            // Color transform group pass (tonemap, color grading)
            var lastEffect = colorTransformsGroup.Enabled ? (ImageEffect)colorTransformsGroup : Scaler;

            lastEffect.SetInput(currentInput);
            lastEffect.SetOutput(toneOutput);
            lastEffect.Draw(context);

            // Do AA here, last, if not already done.
            if (aaLast)
            {
                Antialiasing.SetInput(toneOutput);
                Antialiasing.SetOutput(output);
                Antialiasing.Draw(context);
            }
        }
Esempio n. 13
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);

            // check whether the projection matrix is orthographic
            var isOrthographic = renderView.Projection.M44 == 1;

            aoRawImageEffect.Parameters.Set(AmbientOcclusionRawAOKeys.IsOrthographic, isOrthographic);
            blurH.Parameters.Set(AmbientOcclusionBlurKeys.IsOrthographic, isOrthographic);
            blurV.Parameters.Set(AmbientOcclusionBlurKeys.IsOrthographic, isOrthographic);

            Vector2 zProj;

            if (isOrthographic)
            {
                zProj = new Vector2(renderView.NearClipPlane, renderView.FarClipPlane - renderView.NearClipPlane);
            }
            else
            {
                zProj = CameraKeys.ZProjectionACalculate(renderView.NearClipPlane, renderView.FarClipPlane);
            }

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


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

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

            Vector4 projInfo;

            if (isOrthographic)
            {
                // The orthographic scale to map the xy coordinates
                float scaleX = 1 / renderView.Projection.M11;
                float scaleY = 1 / renderView.Projection.M22;

                // Constant factor to map the ProjScale parameter to the orthographic scale
                float projZScale = System.Math.Max(scaleX, scaleY) * 4;

                projInfo = new Vector4(scaleX, scaleY, projZScale, 0);
            }
            else
            {
                // Projection info 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;

                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, ref 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
                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");
        }
Esempio n. 14
0
        protected override void DrawCore(RenderDrawContext contextParameters)
        {
            var input  = GetInput(0);
            var output = GetOutput(0) ?? input;

            if (input == null || StreakCount == 0 || IterationCount == 0)
            {
                return;
            }

            // Downscale to 1 / 4
            var halfSize             = input.Size.Down2();
            var halfSizeRenderTarget = NewScopedRenderTarget2D(halfSize.Width, halfSize.Height, input.Format);

            Scaler.SetInput(input);
            Scaler.SetOutput(halfSizeRenderTarget);
            Scaler.Draw(contextParameters, "Downsize to 0.5");

            var fourthSize             = halfSize.Down2();
            var fourthSizeRenderTarget = NewScopedRenderTarget2D(fourthSize.Width, fourthSize.Height, input.Format);

            Scaler.SetInput(halfSizeRenderTarget);
            Scaler.SetOutput(fourthSizeRenderTarget);
            Scaler.Draw(contextParameters, "Downsize to 0.25");

            var originalDownsize = fourthSizeRenderTarget;

            // Put all the streaks in an accumulation buffer
            var accumulationBuffer = NewScopedRenderTarget2D(fourthSizeRenderTarget.Description);

            // 2 scratch textures to ping-pong between
            var scratchTextureA = NewScopedRenderTarget2D(fourthSizeRenderTarget.Description);
            var scratchTextureB = NewScopedRenderTarget2D(fourthSizeRenderTarget.Description);
            var writeToScratchA = true;

            Vector2 direction;
            Texture currentInput = null, currentOutput = null;

            Vector3 colorAberration;

            colorAberration.X = (float)MathUtil.Lerp(1.0, ColorAberrationCoefficients.X, ColorAberrationStrength);
            colorAberration.Y = (float)MathUtil.Lerp(1.0, ColorAberrationCoefficients.Y, ColorAberrationStrength);
            colorAberration.Z = (float)MathUtil.Lerp(1.0, ColorAberrationCoefficients.Z, ColorAberrationStrength);

            lightStreakEffect.Parameters.Set(LightStreakShaderKeys.ColorAberrationCoefficients, ref colorAberration);

            for (int streak = 0; streak < StreakCount; streak++)
            {
                // Treats one streak

                // Direction vector
                float angle = MathUtil.DegreesToRadians(Phase) + streak * MathUtil.TwoPi / StreakCount;
                direction.X = (float)Math.Cos(angle);
                direction.Y = (float)Math.Sin(angle);

                // Extends the length recursively
                for (int level = 0; level < IterationCount; level++)
                {
                    // Calculates weights and attenuation factors for all the taps
                    float totalWeight = 0;
                    float passLength  = (float)Math.Pow(TapsPerIteration, level);
                    for (int i = 0; i < TapsPerIteration; i++)
                    {
                        tapOffsetsWeights[i].X = i * passLength;
                        tapOffsetsWeights[i].Y = (float)Math.Pow(MathUtil.Lerp(0.7f, 1.0f, Attenuation), i * passLength);
                        totalWeight           += tapOffsetsWeights[i].Y;
                    }
                    // Normalizes the weights
                    for (int i = 0; i < TapsPerIteration; i++)
                    {
                        tapOffsetsWeights[i].Y /= totalWeight;
                    }

                    currentInput = writeToScratchA ? scratchTextureB : scratchTextureA;
                    if (level == 0)
                    {
                        currentInput = originalDownsize;
                    }
                    currentOutput = writeToScratchA ? scratchTextureA : scratchTextureB;

                    lightStreakEffect.Parameters.Set(LightStreakKeys.Count, TapsPerIteration);
                    lightStreakEffect.Parameters.Set(LightStreakKeys.AnamorphicCount, AnamorphicOffsetsWeights.Length);
                    lightStreakEffect.Parameters.Set(LightStreakShaderKeys.TapOffsetsWeights, tapOffsetsWeights);
                    lightStreakEffect.Parameters.Set(LightStreakShaderKeys.AnamorphicOffsetsWeight, AnamorphicOffsetsWeights);
                    lightStreakEffect.Parameters.Set(LightStreakShaderKeys.Direction, direction);
                    lightStreakEffect.SetInput(0, currentInput);
                    lightStreakEffect.SetOutput(currentOutput);
                    lightStreakEffect.Draw(contextParameters, lightStreakDebugStrings[(streak * IterationCount) + level]);

                    writeToScratchA = !writeToScratchA;
                }

                // Writes this streak to the accumulation buffer
                if (streak > 0)
                {
                    combiner.BlendState = BlendStates.Additive;
                }

                combiner.SetInput(0, currentOutput);
                combiner.Factors[0] = (1f / StreakCount) * 0.2f * Amount;
                combiner.SetOutput(accumulationBuffer);
                ((RendererBase)combiner).Draw(contextParameters);
                combiner.BlendState = BlendStates.Default;
            }

            // All the light streaks have been drawn to the accumulation buffer.
            // Upscales and blurs the accumulation buffer.
            var accumulationUpscaled = NewScopedRenderTarget2D(halfSizeRenderTarget.Description);

            Scaler.SetInput(accumulationBuffer);
            Scaler.SetOutput(accumulationUpscaled);
            ((RendererBase)Scaler).Draw(contextParameters);

            blur.Radius = 3;
            blur.SetInput(accumulationUpscaled);
            blur.SetOutput(accumulationUpscaled);
            ((RendererBase)blur).Draw(contextParameters);

            // Adds the result to the original color buffer.
            Scaler.BlendState = BlendStates.Additive;
            Scaler.SetInput(accumulationUpscaled);
            Scaler.SetOutput(output);
            ((RendererBase)Scaler).Draw(contextParameters);
            Scaler.BlendState = BlendStates.Default;
        }