public void HomogeneousDivide() { Vector4F v4 = new Vector4F(1.0f, 2.0f, 3.0f, 1.0f); Vector3F v3 = Vector4F.HomogeneousDivide(v4); Assert.AreEqual(new Vector3F(1.0f, 2.0f, 3.0f), v3); v4 = new Vector4F(1.0f, 2.0f, 3.0f, 10.0f); v3 = Vector4F.HomogeneousDivide(v4); Assert.AreEqual(new Vector3F(1.0f / 10.0f, 2.0f / 10.0f, 3.0f / 10.0f), v3); }
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; }