private Matrix4x4 UpdateDirectionalLightMatrices( GraphicsDevice gd, SceneContext sc, float near, float far, uint shadowMapWidth, out BoundingFrustum lightFrustum) { Vector3 lightDir = sc.DirectionalLight.Direction; Vector3 viewDir = sc.Camera.LookDirection; Vector3 viewPos = sc.Camera.Position; Vector3 unitY = Vector3.UnitY; FrustumCorners cameraCorners; if (gd.IsDepthRangeZeroToOne) { FrustumHelpers.ComputePerspectiveFrustumCorners( ref viewPos, ref viewDir, ref unitY, sc.Camera.FieldOfView, far, near, sc.Camera.AspectRatio, out cameraCorners); } else { FrustumHelpers.ComputePerspectiveFrustumCorners( ref viewPos, ref viewDir, ref unitY, sc.Camera.FieldOfView, near, far, sc.Camera.AspectRatio, out cameraCorners); } // Approach used: http://alextardif.com/ShadowMapping.html Vector3 frustumCenter = Vector3.Zero; frustumCenter += cameraCorners.NearTopLeft; frustumCenter += cameraCorners.NearTopRight; frustumCenter += cameraCorners.NearBottomLeft; frustumCenter += cameraCorners.NearBottomRight; frustumCenter += cameraCorners.FarTopLeft; frustumCenter += cameraCorners.FarTopRight; frustumCenter += cameraCorners.FarBottomLeft; frustumCenter += cameraCorners.FarBottomRight; frustumCenter /= 8f; float radius = (cameraCorners.NearTopLeft - cameraCorners.FarBottomRight).Length() / 2.0f; float texelsPerUnit = shadowMapWidth / (radius * 2.0f); Matrix4x4 scalar = Matrix4x4.CreateScale(texelsPerUnit, texelsPerUnit, texelsPerUnit); Vector3 baseLookAt = -lightDir; Matrix4x4 lookat = Matrix4x4.CreateLookAt(Vector3.Zero, baseLookAt, Vector3.UnitY); lookat = scalar * lookat; Matrix4x4.Invert(lookat, out Matrix4x4 lookatInv); frustumCenter = Vector3.Transform(frustumCenter, lookat); frustumCenter.X = (int)frustumCenter.X; frustumCenter.Y = (int)frustumCenter.Y; frustumCenter = Vector3.Transform(frustumCenter, lookatInv); Vector3 lightPos = frustumCenter - (lightDir * radius * 2f); Matrix4x4 lightView = Matrix4x4.CreateLookAt(lightPos, frustumCenter, Vector3.UnitY); Matrix4x4 lightProjection = Util.CreateOrtho( gd, gd.IsDepthRangeZeroToOne, -radius * _lScale, radius * _rScale, -radius * _bScale, radius * _tScale, -radius * _nScale, radius * _fScale); Matrix4x4 viewProjectionMatrix = lightView * lightProjection; lightFrustum = new BoundingFrustum(viewProjectionMatrix); return(viewProjectionMatrix); }
private void UpdateLightProjection() { if (MainCamera == null) { return; } if (Light == null) { _lightProjectionProvider.Data = Matrix4x4.Identity; _lightViewProvider.Data = Matrix4x4.Identity; return; } Vector3 cameraDir = MainCamera.Transform.Forward; Vector3 unitY = Vector3.UnitY; Vector3 cameraPosition = MainCamera.Transform.Position; FrustumCorners corners; FrustumHelpers.ComputePerspectiveFrustumCorners( ref cameraPosition, ref cameraDir, ref unitY, MainCamera.FieldOfViewRadians, MainCamera.NearPlaneDistance, MainCamera.FarPlaneDistance, (float)RenderContext.Window.Width / (float)RenderContext.Window.Height, out corners); // Approach used: http://alextardif.com/ShadowMapping.html Vector3 frustumCenter = Vector3.Zero; frustumCenter += corners.NearTopLeft; frustumCenter += corners.NearTopRight; frustumCenter += corners.NearBottomLeft; frustumCenter += corners.NearBottomRight; frustumCenter += corners.FarTopLeft; frustumCenter += corners.FarTopRight; frustumCenter += corners.FarBottomLeft; frustumCenter += corners.FarBottomRight; frustumCenter /= 8f; float radius = (corners.NearTopLeft - corners.FarBottomRight).Length() / 2.0f; float texelsPerUnit = (float)DepthMapWidth / (radius * 2.0f); Matrix4x4 scalar = Matrix4x4.CreateScale(texelsPerUnit, texelsPerUnit, texelsPerUnit); var _lightDirection = Light.Direction; Vector3 baseLookAt = -_lightDirection; Matrix4x4 lookat = Matrix4x4.CreateLookAt(Vector3.Zero, baseLookAt, Vector3.UnitY); lookat = scalar * lookat; Matrix4x4 lookatInv; Matrix4x4.Invert(lookat, out lookatInv); frustumCenter = Vector3.Transform(frustumCenter, lookat); frustumCenter.X = (int)frustumCenter.X; frustumCenter.Y = (int)frustumCenter.Y; frustumCenter = Vector3.Transform(frustumCenter, lookatInv); Vector3 lightPos = frustumCenter - (_lightDirection * radius * 2f); Matrix4x4 lightView = Matrix4x4.CreateLookAt(lightPos, frustumCenter, Vector3.UnitY); _lightProjectionProvider.Data = Matrix4x4.CreateOrthographicOffCenter( -radius, radius, -radius, radius, -radius * 4f, radius * 4f); _lightViewProvider.Data = lightView; }