public static void MakeGlobalShadowMatrix(ref Camera camera, out Matrix globalShadowMatrix) { var cameraCb = camera.Constants; ResetFrustumCorners(ref _frustumCorners); var frustumCenter = DxVector3.Zero; for (int i = 0; i < 8; ++i) { DxVector3.TransformCoordinate(ref _frustumCorners[i], ref cameraCb.Data.InverseViewProjection, out _frustumCorners[i]); DxVector3.Add(ref frustumCenter, ref _frustumCorners[i], out frustumCenter); } DxVector3.Divide(ref frustumCenter, 8.0f, out frustumCenter); var upDir = DxVector3.Up; var lightCameraPos = frustumCenter; DxVector3 lookAt; DxVector3.Subtract(ref frustumCenter, ref Direction, out lookAt); Matrix lightView; Matrix.LookAtLH(ref lightCameraPos, ref lookAt, ref upDir, out lightView); DxVector3 shadowCameraPos; //DxVector3.Multiply(ref Lighting.LightDirection, -0.5f, out shadowCameraPos); //DxVector3.Add(ref frustumCenter, ref shadowCameraPos, out shadowCameraPos); shadowCameraPos = frustumCenter + Direction * -0.5f; Matrix viewMatrix; Matrix projMatrix; Matrix viewProjMatrix; Matrix.OrthoOffCenterLH(-0.5f, 0.5f, -0.5f, 0.5f, 0.0f, 1.0f, out projMatrix); Matrix.LookAtLH(ref shadowCameraPos, ref frustumCenter, ref upDir, out viewMatrix); Matrix.Multiply(ref viewMatrix, ref projMatrix, out viewProjMatrix); Matrix.Multiply(ref viewProjMatrix, ref _texScaleBias, out globalShadowMatrix); }
public static void RenderShadowMap(ref DeviceContext context, ref IWorld world, ref Camera camera) { PixHelper.BeginEvent(default(RawColorBGRA), "Shadow Rendering"); { if (ShadowMapsNeedRemade) CreateShadowMaps(); var shadowMapSize = ShadowMap.Width; if (AreSplitsDirty || camera != _lastCamera) ComputeSplits(ref camera); _lastCamera = camera; MakeGlobalShadowMatrix(ref camera, out ReceiverConstants.Data.ShadowMatrix); context.Rasterizer.SetViewport(_viewport); for (int cascadeIndex = 0; cascadeIndex < CascadeCount; ++cascadeIndex) { PixHelper.BeginEvent(default(RawColorBGRA), "Cascade"); { ResetFrustumCorners(ref _frustumCorners); var prevSplitDist = cascadeIndex == 0 ? MinCascadeDistance : _cascadeSplits[cascadeIndex - 1]; var splitDist = _cascadeSplits[cascadeIndex]; for (int i = 0; i < 8; i++) DxVector3.TransformCoordinate(ref _frustumCorners[i], ref camera.Constants.Data.InverseViewProjection, out _frustumCorners[i]); for (int i = 0; i < 4; i++) { DxVector3 cornerRay; DxVector3 nearCornerRay; DxVector3 farCornerRay; DxVector3.Subtract(ref _frustumCorners[i + 4], ref _frustumCorners[i], out cornerRay); DxVector3.Multiply(ref cornerRay, prevSplitDist, out nearCornerRay); DxVector3.Multiply(ref cornerRay, splitDist, out farCornerRay); DxVector3.Add(ref _frustumCorners[i], ref farCornerRay, out _frustumCorners[i + 4]); DxVector3.Add(ref _frustumCorners[i], ref nearCornerRay, out _frustumCorners[i]); } var frustumCenter = DxVector3.Zero; for (int i = 0; i < 8; i++) DxVector3.Add(ref frustumCenter, ref _frustumCorners[i], out frustumCenter); DxVector3.Multiply(ref frustumCenter, 0.125F, out frustumCenter); var upDir = DxVector3.Up; float sphereRadius = 0.0f; for (int i = 0; i < 8; ++i) { DxVector3 sum; DxVector3.Subtract(ref _frustumCorners[i], ref frustumCenter, out sum); sphereRadius = Math.Max(sphereRadius, sum.Length()); } sphereRadius = (float)Math.Ceiling(sphereRadius * 16.0f) / 16.0f; var maxExtents = new DxVector3(sphereRadius, sphereRadius, sphereRadius); DxVector3 minExtents; DxVector3.Negate(ref maxExtents, out minExtents); DxVector3 cascadeExtents; DxVector3.Subtract(ref maxExtents, ref minExtents, out cascadeExtents); // TODO: optimize var shadowCameraPos = frustumCenter + Direction * -minExtents.Z; Matrix viewMatrix; Matrix projectionMatrix; Matrix viewProjMatrix; Matrix.LookAtLH(ref shadowCameraPos, ref frustumCenter, ref upDir, out viewMatrix); Matrix.OrthoOffCenterLH(minExtents.X, maxExtents.X, minExtents.Y, maxExtents.Y, 0.0f, cascadeExtents.Z, out projectionMatrix); Matrix.Multiply(ref viewMatrix, ref projectionMatrix, out viewProjMatrix); var shadowOrigin = DxVector4.UnitW; DxVector4.Transform(ref shadowOrigin, ref viewProjMatrix, out shadowOrigin); DxVector4.Multiply(ref shadowOrigin, shadowMapSize / 2.0f, out shadowOrigin); var roundedOrigin = new DxVector4(Mathf.Round(shadowOrigin.X), Mathf.Round(shadowOrigin.Y), Mathf.Round(shadowOrigin.Z), Mathf.Round(shadowOrigin.W)); DxVector4 roundOffset; DxVector4.Subtract(ref roundedOrigin, ref shadowOrigin, out roundOffset); DxVector4.Multiply(ref roundOffset, 2.0f / shadowMapSize, out roundOffset); roundOffset.Z = 0.0f; roundOffset.W = 0.0f; projectionMatrix.Row4 += roundOffset; // R[3] Matrix.Multiply(ref viewMatrix, ref projectionMatrix, out viewProjMatrix); // RenderDepthCPU SetupRenderDepthState(ref context, ref viewProjMatrix, cascadeIndex); world.RenderObjectProvider.Draw(ref context, ref camera, true); var texScaleBias = new Matrix { Row1 = new SharpDX.Vector4(0.5f, 0.0f, 0.0f, 0.0f), Row2 = new SharpDX.Vector4(0.0f, -0.5f, 0.0f, 0.0f), Row3 = new SharpDX.Vector4(0.0f, 0.0f, 1.0f, 0.0f), Row4 = new SharpDX.Vector4(0.5f, 0.5f, 0.0f, 1.0f) }; Matrix.Multiply(ref viewProjMatrix, ref texScaleBias, out viewProjMatrix); var clipNear = camera.ClipNear; var clipFar = camera.ClipFar; var clipDist = clipFar - clipNear; ReceiverConstants.Data.CascadeSplits[cascadeIndex] = clipNear + splitDist * clipDist; Matrix invCascadeMatrix; Matrix.Invert(ref viewProjMatrix, out invCascadeMatrix); var zero = DxVector3.Zero; DxVector3 cascadeCorner; DxVector3.TransformCoordinate(ref zero, ref invCascadeMatrix, out cascadeCorner); DxVector3.TransformCoordinate(ref cascadeCorner, ref ReceiverConstants.Data.ShadowMatrix, out cascadeCorner); var one = DxVector3.One; DxVector3 otherCorner; DxVector3.TransformCoordinate(ref one, ref invCascadeMatrix, out otherCorner); DxVector3.TransformCoordinate(ref otherCorner, ref ReceiverConstants.Data.ShadowMatrix, out otherCorner); var cascadeScale = DxVector3.One / (otherCorner - cascadeCorner); ReceiverConstants.Data.CascadeOffsets[cascadeIndex] = new DxVector4(-cascadeCorner, 0.0f); ReceiverConstants.Data.CascadeScales[cascadeIndex] = new DxVector4(cascadeScale, 1.0f); if (RenderSettings.UseFilterableShadows) ConvertToVsm(ref context, cascadeIndex, ref ReceiverConstants.Data.CascadeSplits[cascadeIndex], ref ReceiverConstants.Data.CascadeScales[0]); } PixHelper.EndEvent(); } } PixHelper.EndEvent(); DataStream stream; context.MapSubresource(ReceiverConstants.Buffer, MapMode.WriteDiscard, MapFlags.None, out stream); stream.Write(ReceiverConstants.Data.ShadowMatrix); stream.WriteRange(ReceiverConstants.Data.CascadeSplits, 0, 4); stream.WriteRange(ReceiverConstants.Data.CascadeOffsets, 0, 4); stream.WriteRange(ReceiverConstants.Data.CascadeScales, 0, 4); stream.Write(ReceiverConstants.Data.ShadowDepthBias); stream.Write(ReceiverConstants.Data.ShadowOffsetScale); stream.Write(ReceiverConstants.Data.VisualizeCascades); context.UnmapSubresource(ReceiverConstants.Buffer, 0); //ReceiverConstants.Update(ref context); }