Esempio n. 1
0
        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);
        }