Пример #1
0
        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;
            Matrix44F projection     = cameraNode.Camera.Projection.ToMatrix44F();
            Matrix44F view           = cameraNode.View;
            Matrix44F viewProjection = projection * view;

            // We simply place the light source "far away" in opposite light ray direction.
            Vector4F lightPositionWorld = new Vector4F(-LightDirection * 10000, 1);

            // Convert to clip space.
            Vector4F lightPositionProj = viewProjection * lightPositionWorld;
            Vector3F lightPositionClip = Vector4F.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;
        }