protected override void OnProcess(RenderContext context) { context.ThrowIfCameraMissing(); context.ThrowIfGBuffer0Missing(); var graphicsDevice = GraphicsService.GraphicsDevice; var cameraNode = context.CameraNode; var renderTargetPool = GraphicsService.RenderTargetPool; var source = context.SourceTexture; var target = context.RenderTarget; var viewport = context.Viewport; var sourceSize = new Vector2F(source.Width, source.Height); int width = (int)sourceSize.X; int height = (int)sourceSize.Y; int downsampledWidth = Math.Max(1, width / DownsampleFactor); int downsampledHeight = Math.Max(1, height / DownsampleFactor); if (TextureHelper.IsFloatingPointFormat(source.Format)) { graphicsDevice.SamplerStates[0] = SamplerState.PointClamp; InitializeGaussianBlur(new Vector2F(downsampledWidth, downsampledHeight), false); } else { graphicsDevice.SamplerStates[0] = SamplerState.LinearClamp; InitializeGaussianBlur(new Vector2F(downsampledWidth, downsampledHeight), true); } // Get temporary render targets. var downsampleFormat = new RenderTargetFormat(downsampledWidth, downsampledHeight, false, source.Format, DepthFormat.None); RenderTarget2D blurredScene0 = renderTargetPool.Obtain2D(downsampleFormat); RenderTarget2D blurredScene1 = renderTargetPool.Obtain2D(downsampleFormat); var blurredDepthFormat = new RenderTargetFormat(downsampledWidth, downsampledHeight, false, context.GBuffer0.Format, DepthFormat.None); RenderTarget2D blurredDepth0 = renderTargetPool.Obtain2D(blurredDepthFormat); var cocFormat = new RenderTargetFormat(width, height, false, SurfaceFormat.Single, DepthFormat.None); RenderTarget2D cocImage = renderTargetPool.Obtain2D(cocFormat); var downSampledCocFormat = new RenderTargetFormat(downsampledWidth, downsampledHeight, false, cocFormat.SurfaceFormat, DepthFormat.None); RenderTarget2D cocImageBlurred = renderTargetPool.Obtain2D(downSampledCocFormat); // ----- Create CoC map. _effect.CurrentTechnique = _effect.Techniques[0]; graphicsDevice.SetRenderTarget(cocImage); _screenSizeParameter.SetValue(new Vector2(cocImage.Width, cocImage.Height)); _depthTextureParameter.SetValue(context.GBuffer0); _nearBlurDistanceParameter.SetValue(NearBlurDistance); _nearFocusDistanceParameter.SetValue(NearFocusDistance); _farFocusDistanceParameter.SetValue(FarFocusDistance); _farBlurDistanceParameter.SetValue(FarBlurDistance); _farParameter.SetValue(cameraNode.Camera.Projection.Far); _circleOfConfusionPass.Apply(); graphicsDevice.DrawFullScreenQuad(); // ----- Downsample cocImage to cocImageBlurred. context.SourceTexture = cocImage; context.RenderTarget = cocImageBlurred; context.Viewport = new Viewport(0, 0, cocImageBlurred.Width, cocImageBlurred.Height); _downsampleFilter.Process(context); renderTargetPool.Recycle(cocImage); // ----- Downsample source to blurredScene0. context.SourceTexture = source; context.RenderTarget = blurredScene0; context.Viewport = new Viewport(0, 0, blurredScene0.Width, blurredScene0.Height); _downsampleFilter.Process(context); // ----- Downsample depth texture to blurredDepth0. context.SourceTexture = context.GBuffer0; context.RenderTarget = blurredDepth0; context.Viewport = new Viewport(0, 0, blurredDepth0.Width, blurredDepth0.Height); _downsampleFilter.Process(context); // ----- Blur scene. // Horizontal blur graphicsDevice.SetRenderTarget(blurredScene1); _screenSizeParameter.SetValue(new Vector2(blurredScene0.Width, blurredScene0.Height)); _blurTextureParameter.SetValue(blurredScene0); _downsampledDepthTextureParameter.SetValue(blurredDepth0); _downsampledCocTextureParameter.SetValue(cocImageBlurred); _offsetsParameter.SetValue(_horizontalOffsets); _weightsParameter.SetValue(_weights); _blurPass.Apply(); graphicsDevice.DrawFullScreenQuad(); // Vertical blur. graphicsDevice.SetRenderTarget(blurredScene0); _blurTextureParameter.SetValue(blurredScene1); _offsetsParameter.SetValue(_verticalOffsets); _blurPass.Apply(); graphicsDevice.DrawFullScreenQuad(); renderTargetPool.Recycle(blurredScene1); // ----- Blur cocImageBlurred. context.SourceTexture = cocImageBlurred; context.RenderTarget = cocImageBlurred; context.Viewport = new Viewport(0, 0, cocImageBlurred.Width, cocImageBlurred.Height); _cocBlur.Process(context); // We make a two pass blur, so context.SourceTexture can be equal to context.RenderTarget. // ----- Blur depth. context.SourceTexture = blurredDepth0; context.RenderTarget = blurredDepth0; context.Viewport = new Viewport(0, 0, blurredDepth0.Width, blurredDepth0.Height); _cocBlur.Process(context); // ----- Create final DoF image. _effect.CurrentTechnique = _effect.Techniques[0]; graphicsDevice.SetRenderTarget(target); graphicsDevice.Viewport = viewport; _screenSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height)); _sceneTextureParameter.SetValue(source); _blurTextureParameter.SetValue(blurredScene0); _depthTextureParameter.SetValue(context.GBuffer0); _downsampledDepthTextureParameter.SetValue(blurredDepth0); _downsampledCocTextureParameter.SetValue(cocImageBlurred); _depthOfFieldPass.Apply(); graphicsDevice.DrawFullScreenQuad(); // ----- Clean-up _depthTextureParameter.SetValue((Texture2D)null); _blurTextureParameter.SetValue((Texture2D)null); _downsampledDepthTextureParameter.SetValue((Texture2D)null); _downsampledCocTextureParameter.SetValue((Texture2D)null); _sceneTextureParameter.SetValue((Texture2D)null); renderTargetPool.Recycle(blurredScene0); renderTargetPool.Recycle(blurredDepth0); renderTargetPool.Recycle(cocImageBlurred); context.SourceTexture = source; context.RenderTarget = target; context.Viewport = viewport; }
protected override void OnProcess(RenderContext context) { var graphicsDevice = GraphicsService.GraphicsDevice; var renderTargetPool = GraphicsService.RenderTargetPool; var source = context.SourceTexture; var target = context.RenderTarget; var viewport = context.Viewport; int downsampledWidth = Math.Max(1, source.Width / DownsampleFactor); int downsampledHeight = Math.Max(1, source.Height / DownsampleFactor); // ----- Get temporary render targets. var sourceDownsampled = renderTargetPool.Obtain2D(new RenderTargetFormat( downsampledWidth, downsampledHeight, false, source.Format, DepthFormat.None)); var bloom = renderTargetPool.Obtain2D(new RenderTargetFormat( downsampledWidth, downsampledHeight, false, SurfaceFormat.Color, DepthFormat.None)); // ----- Downsample scene. context.RenderTarget = sourceDownsampled; context.Viewport = new Viewport(0, 0, sourceDownsampled.Width, sourceDownsampled.Height); _downsampleFilter.Process(context); // ----- Compute luminance. context.SourceTexture = sourceDownsampled; context.RenderTarget = _luminanceTarget; context.Viewport = new Viewport(0, 0, _luminanceTarget.Width, _luminanceTarget.Height); _luminance.Process(context); // ----- Create bloom image. graphicsDevice.SetRenderTarget(bloom); _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height)); _bloomThresholdParameter.SetValue(BloomThreshold); _middleGrayParameter.SetValue(MiddleGray); _minExposureParameter.SetValue(MinExposure); _maxExposureParameter.SetValue(MaxExposure); _bloomIntensityParameter.SetValue(BloomIntensity); _sceneTextureParameter.SetValue(sourceDownsampled); _luminanceTextureParameter.SetValue(_luminanceTarget); _brightnessPass.Apply(); graphicsDevice.DrawFullScreenQuad(); // sourceDownsampled is not needed anymore. renderTargetPool.Recycle(sourceDownsampled); // We make a two-pass blur, so source can be equal to target. context.SourceTexture = bloom; context.RenderTarget = bloom; context.Viewport = new Viewport(0, 0, bloom.Width, bloom.Height); _blur.Process(context); // ----- Combine scene and bloom. graphicsDevice.SetRenderTarget(target); graphicsDevice.Viewport = viewport; _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height)); _sceneTextureParameter.SetValue(source); _bloomTextureParameter.SetValue(bloom); _luminanceTextureParameter.SetValue(_luminanceTarget); _middleGrayParameter.SetValue(MiddleGray); if (EnableBlueShift) { _blueShiftColorParameter.SetValue((Vector3)BlueShiftColor); _blueShiftParameter.SetValue(new Vector2(1 / BlueShiftCenter, 1 / BlueShiftRange)); _combineWithBlueShiftPass.Apply(); } else { _combinePass.Apply(); } graphicsDevice.DrawFullScreenQuad(); // ----- Clean-up _sceneTextureParameter.SetValue((Texture2D)null); _luminanceTextureParameter.SetValue((Texture2D)null); _bloomTextureParameter.SetValue((Texture2D)null); renderTargetPool.Recycle(bloom); context.SourceTexture = source; context.RenderTarget = target; context.Viewport = viewport; }
protected override void OnProcess(RenderContext context) { context.ThrowIfCameraMissing(); var graphicsDevice = GraphicsService.GraphicsDevice; var renderTargetPool = GraphicsService.RenderTargetPool; var cameraNode = context.CameraNode; var source = context.SourceTexture; var target = context.RenderTarget; var viewport = context.Viewport; if (Quality == 0) { // No ambient occlusion. if (!CombineWithSource) { // CombineWithSource is not set. --> Simply clear the render target to white. graphicsDevice.SetRenderTarget(target); graphicsDevice.Viewport = viewport; graphicsDevice.Clear(Color.White); } else { // Copy source image to target. _copyFilter.Process(context); } return; } // Try to get downsampled depth buffer from render context. // If we cannot find it in the render context, we downsample it manually. Texture2D downsampledDepthTexture = null; RenderTarget2D downsampledDepthTarget = null; if (DownsampleFactor == 2) { object dummy; if (context.Data.TryGetValue(RenderContextKeys.DepthBufferHalf, out dummy)) { downsampledDepthTexture = dummy as Texture2D; } } if (downsampledDepthTexture == null) { context.ThrowIfGBuffer0Missing(); if (DownsampleFactor == 1) { downsampledDepthTexture = context.GBuffer0; } else { // Downsample manually. // If we do not downsample the depth target, we get artifacts (strange horizontal and vertical // lines). TODO: Check what causes the artifacts and try to remove the downsampling. downsampledDepthTarget = renderTargetPool.Obtain2D(new RenderTargetFormat( context.GBuffer0.Width / DownsampleFactor, context.GBuffer0.Height / DownsampleFactor, false, context.GBuffer0.Format, DepthFormat.None)); context.SourceTexture = context.GBuffer0; context.RenderTarget = downsampledDepthTarget; context.Viewport = new Viewport(0, 0, downsampledDepthTarget.Width, downsampledDepthTarget.Height); _downsampleFilter.Process(context); downsampledDepthTexture = downsampledDepthTarget; } } // We use two temporary render targets. // We do not use a floating point format because float textures cannot use hardware filtering. RenderTarget2D temp0; if (!CombineWithSource && target != null && target.Width == context.GBuffer0.Width / DownsampleFactor && target.Height == context.GBuffer0.Height / DownsampleFactor && Strength < 1) { // If we do not have to combine the AO result with the source image, and if the target // image has the half resolution, then we can use the target image directly and do not // need a temporary render target. // Also, a Strength > 1 is always applied in a separate pass because applying a Strength // > 1 before the blur has no effect. temp0 = target; } else { temp0 = renderTargetPool.Obtain2D(new RenderTargetFormat( context.GBuffer0.Width / DownsampleFactor, context.GBuffer0.Height / DownsampleFactor, false, SurfaceFormat.Color, DepthFormat.None)); } // Create SSAO. graphicsDevice.SetRenderTarget(temp0); _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height)); _farParameter.SetValue(cameraNode.Camera.Projection.Far); _radiusParameter.SetValue((Vector2)Radii); _maxDistancesParameter.SetValue((Vector2)MaxDistances); _strengthParameter.SetValue(Strength < 1 ? Strength : 1); _gBuffer0Parameter.SetValue(downsampledDepthTexture); if (Quality == 1) { _createLinesAPass.Apply(); } else { _createLinesBPass.Apply(); } graphicsDevice.DrawFullScreenQuad(); if (UseEdgeAwareBlur) { RenderTarget2D temp1 = renderTargetPool.Obtain2D(new RenderTargetFormat( context.GBuffer0.Width / DownsampleFactor, context.GBuffer0.Height / DownsampleFactor, false, SurfaceFormat.Color, DepthFormat.None)); for (int i = 0; i < NumberOfBlurPasses; i++) { // Blur horizontally. // Note: We use a bilateral filter which is not separable - but the results are still ok // if we use separate the horizontal and vertical blur. graphicsDevice.SetRenderTarget(temp1); _occlusionTextureParameter.SetValue(temp0); _blurHorizontalPass.Apply(); graphicsDevice.DrawFullScreenQuad(); // Blur vertically. graphicsDevice.SetRenderTarget(temp0); _occlusionTextureParameter.SetValue(temp1); _blurVerticalPass.Apply(); graphicsDevice.DrawFullScreenQuad(); } // A few render targets are not needed anymore. renderTargetPool.Recycle(downsampledDepthTarget); renderTargetPool.Recycle(temp1); } else { // A few render targets are not needed anymore. renderTargetPool.Recycle(downsampledDepthTarget); context.SourceTexture = temp0; context.RenderTarget = temp0; context.Viewport = new Viewport(0, 0, temp0.Width, temp0.Height); for (int i = 0; i < NumberOfBlurPasses; i++) { _blur.Process(context); } } _strengthParameter.SetValue(Strength > 1 ? Strength : 1); if (CombineWithSource) { if (TextureHelper.IsFloatingPointFormat(source.Format)) { graphicsDevice.SamplerStates[0] = SamplerState.PointClamp; } else { graphicsDevice.SamplerStates[0] = SamplerState.LinearClamp; } // Combine with scene. graphicsDevice.SetRenderTarget(target); graphicsDevice.Viewport = viewport; _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height)); _occlusionTextureParameter.SetValue(temp0); _sourceTextureParameter.SetValue(source); _combinePass.Apply(); graphicsDevice.DrawFullScreenQuad(); } else { if (temp0 != target) { graphicsDevice.SetRenderTarget(target); graphicsDevice.Viewport = viewport; _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height)); _occlusionTextureParameter.SetValue(temp0); _copyPass.Apply(); graphicsDevice.DrawFullScreenQuad(); } } // Clean-up if (temp0 != target) { renderTargetPool.Recycle(temp0); } _sourceTextureParameter.SetValue((Texture2D)null); _gBuffer0Parameter.SetValue((Texture2D)null); _occlusionTextureParameter.SetValue((Texture2D)null); context.SourceTexture = source; context.RenderTarget = target; context.Viewport = viewport; }
protected override void OnProcess(RenderContext context) { context.ThrowIfCameraMissing(); context.ThrowIfGBuffer0Missing(); var graphicsDevice = GraphicsService.GraphicsDevice; var renderTargetPool = GraphicsService.RenderTargetPool; var source = context.SourceTexture; var target = context.RenderTarget; var viewport = context.Viewport; // Get temporary render targets. var sourceSize = new Vector2F(source.Width, source.Height); var isFloatingPointFormat = TextureHelper.IsFloatingPointFormat(source.Format); var sceneFormat = new RenderTargetFormat(source.Width, source.Height, false, source.Format, DepthFormat.None); var maskedScene = renderTargetPool.Obtain2D(sceneFormat); var rayFormat = new RenderTargetFormat( Math.Max(1, (int)(sourceSize.X / DownsampleFactor)), Math.Max(1, (int)(sourceSize.Y / DownsampleFactor)), false, source.Format, DepthFormat.None); var rayImage0 = renderTargetPool.Obtain2D(rayFormat); var rayImage1 = renderTargetPool.Obtain2D(rayFormat); // Get view and view-projection transforms. var cameraNode = context.CameraNode; Matrix projection = cameraNode.Camera.Projection.ToMatrix(); Matrix view = cameraNode.View; Matrix viewProjection = projection * view; // We simply place the light source "far away" in opposite light ray direction. Vector4 lightPositionWorld = new Vector4(-LightDirection * 10000, 1); // Convert to clip space. Vector4 lightPositionProj = viewProjection * lightPositionWorld; Vector3 lightPositionClip = Vector4.HomogeneousDivide(lightPositionProj); // Convert from clip space [-1, 1] to texture space [0, 1]. Vector2 lightPosition = new Vector2(lightPositionClip.X * 0.5f + 0.5f, -lightPositionClip.Y * 0.5f + 0.5f); // We use dot²(forward, -LightDirection) as a smooth S-shaped attenuation // curve to reduce the god ray effect when we look orthogonal or away from the sun. var lightDirectionView = view.TransformDirection(LightDirection); float z = Math.Max(0, lightDirectionView.Z); float attenuation = z * z; // Common effect parameters. _parameters0Parameter.SetValue(new Vector4(lightPosition.X, lightPosition.Y, LightRadius * LightRadius, Scale)); _parameters1Parameter.SetValue(new Vector2(Softness, graphicsDevice.Viewport.AspectRatio)); _intensityParameter.SetValue((Vector3)Intensity * attenuation); _numberOfSamplesParameter.SetValue(NumberOfSamples); _gBuffer0Parameter.SetValue(context.GBuffer0); // First, create a scene image where occluders are black. graphicsDevice.SetRenderTarget(maskedScene); _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height)); _sourceTextureParameter.SetValue(source); graphicsDevice.SamplerStates[0] = isFloatingPointFormat ? SamplerState.PointClamp : SamplerState.LinearClamp; graphicsDevice.SamplerStates[1] = SamplerState.PointClamp; // G-Buffer 0. _createMaskPass.Apply(); graphicsDevice.DrawFullScreenQuad(); // Downsample image. context.SourceTexture = maskedScene; context.RenderTarget = rayImage0; context.Viewport = new Viewport(0, 0, rayImage0.Width, rayImage0.Height); _downsampleFilter.Process(context); // Compute light shafts. _viewportSizeParameter.SetValue(new Vector2(context.Viewport.Width, context.Viewport.Height)); graphicsDevice.SamplerStates[0] = isFloatingPointFormat ? SamplerState.PointClamp : SamplerState.LinearClamp; for (int i = 0; i < NumberOfPasses; i++) { graphicsDevice.SetRenderTarget(rayImage1); _sourceTextureParameter.SetValue(rayImage0); _blurPass.Apply(); graphicsDevice.DrawFullScreenQuad(); // Put the current result in variable rayImage0. MathHelper.Swap(ref rayImage0, ref rayImage1); } // Combine light shaft image with scene. graphicsDevice.SetRenderTarget(target); graphicsDevice.Viewport = viewport; _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height)); _sourceTextureParameter.SetValue(source); _rayTextureParameter.SetValue(rayImage0); graphicsDevice.SamplerStates[0] = isFloatingPointFormat ? SamplerState.PointClamp : SamplerState.LinearClamp; graphicsDevice.SamplerStates[1] = isFloatingPointFormat ? SamplerState.PointClamp : SamplerState.LinearClamp; _combinePass.Apply(); graphicsDevice.DrawFullScreenQuad(); // Clean-up _sourceTextureParameter.SetValue((Texture2D)null); _gBuffer0Parameter.SetValue((Texture2D)null); _rayTextureParameter.SetValue((Texture2D)null); renderTargetPool.Recycle(maskedScene); renderTargetPool.Recycle(rayImage0); renderTargetPool.Recycle(rayImage1); context.SourceTexture = source; context.RenderTarget = target; context.Viewport = viewport; }
protected override void OnProcess(RenderContext context) { if (TextureHelper.IsFloatingPointFormat(context.SourceTexture.Format)) { throw new GraphicsException("Source texture format must not be a floating-point format."); } var graphicsDevice = GraphicsService.GraphicsDevice; var renderTargetPool = GraphicsService.RenderTargetPool; var source = context.SourceTexture; var target = context.RenderTarget; var viewport = context.Viewport; int downsampledWidth = Math.Max(1, source.Width / DownsampleFactor); int downsampledHeight = Math.Max(1, source.Height / DownsampleFactor); // ----- Get temporary render targets. var bloomFormat = new RenderTargetFormat(downsampledWidth, downsampledHeight, false, SurfaceFormat.Color, DepthFormat.None); RenderTarget2D bloom0 = renderTargetPool.Obtain2D(bloomFormat); RenderTarget2D bloom1 = renderTargetPool.Obtain2D(bloomFormat); // ----- Downsample scene to bloom0. context.RenderTarget = bloom0; context.Viewport = new Viewport(0, 0, bloom0.Width, bloom0.Height); _downsampleFilter.Process(context); // ----- Create bloom image graphicsDevice.SetRenderTarget(bloom1); _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height)); _bloomThresholdParameter.SetValue(Threshold); _bloomIntensityParameter.SetValue(Intensity); _bloomSaturationParameter.SetValue(Saturation); _sceneTextureParameter.SetValue(bloom0); _brightnessPass.Apply(); graphicsDevice.DrawFullScreenQuad(); // bloom0 is not needed anymore. renderTargetPool.Recycle(bloom0); // We make a two-pass blur, so source can be equal to target. context.SourceTexture = bloom1; context.RenderTarget = bloom1; _blur.Process(context); // ----- Combine scene and bloom. graphicsDevice.SetRenderTarget(target); graphicsDevice.Viewport = viewport; _viewportSizeParameter.SetValue(new Vector2(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height)); _sceneTextureParameter.SetValue(source); _bloomTextureParameter.SetValue(bloom1); _combinePass.Apply(); graphicsDevice.DrawFullScreenQuad(); // ----- Clean-up _sceneTextureParameter.SetValue((Texture2D)null); _bloomTextureParameter.SetValue((Texture2D)null); renderTargetPool.Recycle(bloom1); // Restore original context. context.SourceTexture = source; context.RenderTarget = target; context.Viewport = viewport; }
protected override void OnProcess(RenderContext context) { context.ThrowIfCameraMissing(); var graphicsDevice = GraphicsService.GraphicsDevice; var renderTargetPool = GraphicsService.RenderTargetPool; var source = context.SourceTexture; var target = context.RenderTarget; var viewport = context.Viewport; RenderTarget2D temp128x128 = renderTargetPool.Obtain2D( new RenderTargetFormat(128, 128, false, SurfaceFormat.HalfVector4, DepthFormat.None)); RenderTarget2D temp64x64 = renderTargetPool.Obtain2D( new RenderTargetFormat(64, 64, false, SurfaceFormat.HalfVector4, DepthFormat.None)); RenderTarget2D luminance = renderTargetPool.Obtain2D( new RenderTargetFormat(1, 1, false, SurfaceFormat.HalfVector4, DepthFormat.None)); // ----- Downsample scene into temp128x128. context.RenderTarget = temp128x128; context.Viewport = new Viewport(0, 0, temp128x128.Width, temp128x128.Height); _downsampleFilter.Process(context); _useGeometricMeanParameter.SetValue(UseGeometricMean); // Get view-dependent information stored in camera node. var cameraNode = context.CameraNode; object dummy; cameraNode.ViewDependentData.TryGetValue(this, out dummy); var data = dummy as ViewDependentData; if (data == null) { data = new ViewDependentData(GraphicsService); cameraNode.ViewDependentData[this] = data; } if (UseAdaption) { // Use adaption if required by user and if we already have luminance info. _useAdaptionParameter.SetValue(data.LastLuminance != null); _deltaTimeParameter.SetValue((float)context.DeltaTime.TotalSeconds); _adaptionSpeedParameter.SetValue(AdaptionSpeed); _lastLuminanceTextureParameter.SetValue(data.LastLuminance); } else { _useAdaptionParameter.SetValue(false); _lastLuminanceTextureParameter.SetValue((Texture2D)null); // Reset old luminance info. data.Dispose(); } // ----- First downsample temp128x128 into temp64x64 and create luminance info. graphicsDevice.SetRenderTarget(temp64x64); _textureParameter.SetValue(temp128x128); _sourceSizeParameter.SetValue(new Vector2(temp128x128.Width, temp128x128.Height)); _targetSizeParameter.SetValue(new Vector2(temp64x64.Width, temp64x64.Height)); _createPass.Apply(); graphicsDevice.DrawFullScreenQuad(); // temp128x128 is not needed anymore. renderTargetPool.Recycle(temp128x128); // ----- Downsample luminance info. RenderTarget2D last = temp64x64; while (last.Width > 2) { Debug.Assert(last.Width == last.Height, "The render target must be quadratic"); RenderTarget2D temp = renderTargetPool.Obtain2D( new RenderTargetFormat(last.Width / 2, last.Height / 2, false, last.Format, DepthFormat.None)); graphicsDevice.SetRenderTarget(temp); _textureParameter.SetValue(last); _sourceSizeParameter.SetValue(new Vector2(last.Width, last.Height)); _targetSizeParameter.SetValue(new Vector2(temp.Width, temp.Height)); _downsamplePass.Apply(); graphicsDevice.DrawFullScreenQuad(); renderTargetPool.Recycle(last); last = temp; } // ----- Sample 'last' and store final info in 'luminance'. graphicsDevice.SetRenderTarget(luminance); _textureParameter.SetValue(last); _sourceSizeParameter.SetValue(new Vector2(last.Width, last.Height)); _targetSizeParameter.SetValue(new Vector2(luminance.Width, luminance.Height)); _finalPass.Apply(); graphicsDevice.DrawFullScreenQuad(); renderTargetPool.Recycle(last); // ----- Copy luminance to original context.RenderTarget. context.SourceTexture = luminance; context.RenderTarget = target; context.Viewport = viewport; _copyFilter.Process(context); // ----- Store luminance for next frame. renderTargetPool.Recycle(data.LastLuminance); data.LastLuminance = luminance; // Restore original context. context.SourceTexture = source; _textureParameter.SetValue((Texture2D)null); }