Example #1
0
        protected override void DrawCore(RenderContext 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, 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)
                {
                    GraphicsDevice.SetBlendState(GraphicsDevice.BlendStates.Additive);
                }

                combiner.SetInput(0, currentOutput);
                combiner.Factors[0] = (1f / StreakCount) * 0.2f * Amount;
                combiner.SetOutput(accumulationBuffer);
                combiner.Draw(contextParameters);
                GraphicsDevice.SetBlendState(GraphicsDevice.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);
            Scaler.Draw(contextParameters);

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

            // Adds the result to the original color buffer.
            GraphicsDevice.SetBlendState(GraphicsDevice.BlendStates.Additive);
            Scaler.SetInput(accumulationUpscaled);
            Scaler.SetOutput(output);
            Scaler.Draw(contextParameters);
            GraphicsDevice.SetBlendState(GraphicsDevice.BlendStates.Default);
        }
        protected override void DrawCore(RenderDrawContext context)
        {
            var input  = GetSafeInput(0);
            var output = GetSafeOutput(0);

            // Render the luminance to a power-of-two target, so we preserve energy on downscaling
            var startWidth      = Math.Max(1, Math.Min(MathUtil.NextPowerOfTwo(input.Size.Width), MathUtil.NextPowerOfTwo(input.Size.Height)) / 2);
            var startSize       = new Size3(startWidth, startWidth, 1);
            var blurTextureSize = startSize.Down2(UpscaleCount);

            Texture outputTextureDown = null;

            if (blurTextureSize.Width != 1 && blurTextureSize.Height != 1)
            {
                outputTextureDown = NewScopedRenderTarget2D(blurTextureSize.Width, blurTextureSize.Height, luminanceFormat, 1);
            }

            var luminanceMap = NewScopedRenderTarget2D(startSize.Width, startSize.Height, luminanceFormat, 1);

            // Calculate the first luminance map
            luminanceLogEffect.SetInput(input);
            luminanceLogEffect.SetOutput(luminanceMap);
            ((RendererBase)luminanceLogEffect).Draw(context);

            // Downscales luminance up to BlurTexture (optional) and 1x1
            multiScaler.SetInput(luminanceMap);
            if (outputTextureDown == null)
            {
                multiScaler.SetOutput(luminance1x1);
            }
            else
            {
                multiScaler.SetOutput(outputTextureDown, luminance1x1);
            }
            multiScaler.Draw(context);

            // If we have an output texture
            if (outputTextureDown != null)
            {
                // Blur x2 the intermediate output texture
                blur.SetInput(outputTextureDown);
                blur.SetOutput(outputTextureDown);
                ((RendererBase)blur).Draw(context);
                ((RendererBase)blur).Draw(context);

                // Upscale from intermediate to output
                multiScaler.SetInput(outputTextureDown);
                multiScaler.SetOutput(output);
                ((RendererBase)multiScaler).Draw(context);
            }
            else
            {
                // TODO: Workaround to that the output filled with 1x1
                Scaler.SetInput(luminance1x1);
                Scaler.SetOutput(output);
                ((RendererBase)Scaler).Draw(context);
            }

            // Calculate average luminance only if needed
            if (EnableAverageLuminanceReadback)
            {
                readback.SetInput(luminance1x1);
                readback.Draw(context);
                var rawLogValue = readback.Result[0];
                AverageLuminance = (float)Math.Pow(2.0, rawLogValue);

                // In case AvergaeLuminance go crazy because of halp float/infinity precision, some code to save the values here:
                //if (float.IsInfinity(AverageLuminance))
                //{
                //    using (var stream = new FileStream("luminance_input.dds", FileMode.Create, FileAccess.Write))
                //    {
                //        input.Save(stream, ImageFileType.Dds);
                //    }
                //    using (var stream = new FileStream("luminance.dds", FileMode.Create, FileAccess.Write))
                //    {
                //        luminanceMap.Save(stream, ImageFileType.Dds);
                //    }
                //}
            }
        }
Example #3
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 cameraState = context.RenderContext.GetCurrentCamera();

            if (cameraState == null)
            {
                throw new InvalidOperationException("No valid camera");
            }

            var farPlane = cameraState.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 < 1f)
                {
                    autoFocusDistanceCurrent = 1f;
                }
                depthAreas = new Vector4(0.5f, autoFocusDistanceCurrent, autoFocusDistanceCurrent, autoFocusDistanceCurrent + farPlane * 0.5f);
            }

            coclinearDepthMapEffect.SetInput(0, originalDepthBuffer);
            coclinearDepthMapEffect.SetOutput(cocLinearDepthTexture);
            coclinearDepthMapEffect.Parameters.Set(CircleOfConfusionKeys.depthAreas, depthAreas);
            var camera = context.RenderContext.GetCurrentCamera();

            if (camera != null)
            {
                coclinearDepthMapEffect.Parameters.Set(CameraKeys.ZProjection, CameraKeys.ZProjectionACalculate(camera.NearClipPlane, camera.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();
        }
Example #4
0
        protected override void DrawCore(RenderDrawContext context)
        {
            var originalColorBuffer = GetSafeInput(0);
            var originalDepthBuffer = GetSafeInput(1);

            var outputTexture = GetSafeOutput(0);

            var camera = context.RenderContext.GetCurrentCamera();

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

            if (camera != null)
            {
                // Set Near/Far pre-calculated factors to speed up the linear depth reconstruction
                aoRawImageEffect.Parameters.Set(CameraKeys.ZProjection, CameraKeys.ZProjectionACalculate(camera.NearClipPlane, camera.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      = camera.ProjectionMatrix.M11;
                var     p11      = camera.ProjectionMatrix.M22;
                var     p02      = camera.ProjectionMatrix.M13;
                var     p12      = camera.ProjectionMatrix.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);
                }

                if (camera != null)
                {
                    // Set Near/Far pre-calculated factors to speed up the linear depth reconstruction
                    blurH.Parameters.Set(CameraKeys.ZProjection, CameraKeys.ZProjectionACalculate(camera.NearClipPlane, camera.FarClipPlane));
                    blurV.Parameters.Set(CameraKeys.ZProjection, CameraKeys.ZProjectionACalculate(camera.NearClipPlane, camera.FarClipPlane));
                }

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