Пример #1
0
        internal void AddDepthPass(MyShadowmapQuery shadowmapQuery)
        {
            var worldToProjection = shadowmapQuery.ProjectionInfo.WorldToProjection;
            int frustumMask       = AddFrustum(ref worldToProjection);

            MyDepthPass pass = MyObjectPoolManager.Allocate <MyDepthPass>();

            pass.DebugName      = MyVisibilityCuller.ToString(shadowmapQuery.QueryType);
            pass.ProcessingMask = frustumMask;
            pass.ViewProjection = shadowmapQuery.ProjectionInfo.CurrentLocalToProjection;
            pass.Viewport       = shadowmapQuery.Viewport;
            pass.FrustumIndex   = shadowmapQuery.Index;

            pass.Dsv = shadowmapQuery.DepthBuffer;
            bool isCascade = shadowmapQuery.QueryType == MyFrustumEnum.ShadowCascade;

            pass.IsCascade         = isCascade;
            pass.DefaultRasterizer = isCascade
                ? MyRasterizerStateManager.CascadesRasterizerStateOld
                : MyRasterizerStateManager.ShadowRasterizerState;

            pass.PerFrame();

            RenderingPasses[Size - 1] = pass;
        }
Пример #2
0
        private void PrepareSpotlights()
        {
            MyLights.SpotlightsBvh.OverlapAllFrustum(ref MyEnvironment.ViewFrustumClippedD, MyLightRendering.VisibleSpotlights);

            if (MyLightRendering.VisibleSpotlights.Count == 0)
            {
                OtherShadowsTriangleCounter = 0;
            }

            MyLightRendering.VisibleSpotlights.Sort(m_spotlightCastersComparer);
            MyArrayHelpers.Reserve(ref MyLightRendering.Spotlights, MyLightRendering.VisibleSpotlights.Count);

            int index       = 0;
            int casterIndex = 0;

            foreach (var id in MyLightRendering.VisibleSpotlights)
            {
                var     nearPlaneDistance   = 0.5f;
                var     worldMatrix         = MatrixD.CreateTranslation(MyEnvironment.CameraPosition);
                var     viewMatrix          = MatrixD.CreateLookAt(id.Position, id.Position + MyLights.Spotlights[id.Index].Direction, MyLights.Spotlights[id.Index].Up);
                var     projectionMatrix    = MatrixD.CreatePerspectiveFieldOfView((float)(Math.Acos(MyLights.Spotlights[id.Index].ApertureCos) * 2), 1.0f, nearPlaneDistance, Math.Max(id.ShadowDistance, nearPlaneDistance));
                var     viewProjection      = viewMatrix * projectionMatrix;
                MatrixD worldViewProjection = worldMatrix * viewProjection;
                MyLightRendering.Spotlights[index].ShadowMatrix = Matrix.Transpose(worldViewProjection * MyMatrixHelpers.ClipspaceToTexture);

                if (id.CastsShadows && casterIndex < MAX_SPOTLIGHT_SHADOWCASTERS)
                {
                    if (ShadowmapsPool.Count <= casterIndex)
                    {
                        ShadowmapsPool.Add(MyRwTextures.CreateShadowmap(SpotlightShadowmapSize, SpotlightShadowmapSize));
                    }

                    MyLights.Lights.Data[id.Index].CastsShadowsThisFrame = true;

                    var query = new MyShadowmapQuery
                    {
                        DepthBuffer    = ShadowmapsPool[casterIndex].Dsv,
                        Viewport       = new MyViewport(SpotlightShadowmapSize, SpotlightShadowmapSize),
                        QueryType      = MyFrustumEnum.ShadowProjection,
                        ProjectionInfo = new MyProjectionInfo
                        {
                            WorldCameraOffsetPosition = MyEnvironment.CameraPosition,
                            WorldToProjection         = viewProjection,
                            LocalToProjection         = worldViewProjection
                        },
                        IgnoredEntities = MyLights.IgnoredEntitites.ContainsKey(id) ? MyLights.IgnoredEntitites[id] : null,
                    };
                    m_shadowmapQueries.Add(query);
                    ++casterIndex;
                }
                else
                {
                    MyLights.Lights.Data[id.Index].CastsShadowsThisFrame = false;
                }
                MyLights.WriteSpotlightConstants(id, ref MyLightRendering.Spotlights[index]);

                index++;
            }
        }
Пример #3
0
        static void PrepareSpotlights()
        {
            MyLights.SpotlightsBvh.OverlapAllFrustum(ref MyEnvironment.ViewFrustum, MyLightRendering.VisibleSpotlights);

            MyLightRendering.VisibleSpotlights.Sort(m_spotlightCastersComparer);
            while (MyLightRendering.VisibleSpotlights.Count > MAX_SPOTLIGHT_SHADOWCASTERS)
            {
                MyLightRendering.VisibleSpotlights.RemoveAtFast(MyLightRendering.VisibleSpotlights.Count - 1);
            }

            MyArrayHelpers.Reserve(ref MyLightRendering.Spotlights, MyLightRendering.VisibleSpotlights.Count);

            int index       = 0;
            int casterIndex = 0;

            foreach (var id in MyLightRendering.VisibleSpotlights)
            {
                MyLights.WriteSpotlightConstants(id, ref MyLightRendering.Spotlights[index]);

                if (id.CastsShadows)
                {
                    var query = new MyShadowmapQuery();

                    if (MyLights.IgnoredEntitites.ContainsKey(id))
                    {
                        query.IgnoredEntities = MyLights.IgnoredEntitites[id];
                    }

                    var shadowMatrix = Matrix.CreateLookAt(id.Position, id.Position + MyLights.Spotlights[id.Index].Direction, MyLights.Spotlights[id.Index].Up) *
                                       Matrix.CreatePerspectiveFieldOfView((float)(Math.Acos(MyLights.Spotlights[id.Index].ApertureCos) * 2), 1.0f, 0.5f, id.ShadowDistance);

                    if (ShadowmapsPool.Count <= casterIndex)
                    {
                        ShadowmapsPool.Add(MyRwTextures.CreateShadowmap(512, 512));
                    }

                    query.DepthBuffer    = ShadowmapsPool[casterIndex].Dsv;
                    query.Viewport       = new MyViewport(512, 512);
                    query.QueryType      = MyFrustumEnum.ShadowProjection;
                    query.ProjectionInfo = new MyProjectionInfo
                    {
                        WorldCameraOffsetPosition = MyEnvironment.CameraPosition,
                        WorldToProjection         = shadowMatrix,
                        LocalToProjection         = Matrix.CreateTranslation(MyEnvironment.CameraPosition) * shadowMatrix
                    };

                    MyLightRendering.Spotlights[index].ShadowMatrix = Matrix.Transpose(query.ProjectionInfo.CurrentLocalToProjection * MyMatrixHelpers.ClipspaceToTexture);

                    m_shadowmapQueries.Add(query);
                    casterIndex++;
                }
                index++;
            }
        }
Пример #4
0
        private void PrepareSpotlights()
        {
            MyLights.Update();

            MyLights.SpotlightsBvh.OverlapAllFrustum(ref MyRender11.Environment.ViewFrustumClippedD, MyLightRendering.VisibleSpotlights);

            if (MyLightRendering.VisibleSpotlights.Count == 0)
            {
                OtherShadowsTriangleCounter = 0;
            }

            MyLightRendering.VisibleSpotlights.Sort(m_spotlightCastersComparer);

            int index       = 0;
            int casterIndex = 0;
            var worldMatrix = MatrixD.CreateTranslation(MyRender11.Environment.CameraPosition);

            foreach (var id in MyLightRendering.VisibleSpotlights)
            {
                if (id.CastsShadows && casterIndex < MAX_SPOTLIGHT_SHADOWCASTERS)
                {
                    if (ShadowmapsPool.Count <= casterIndex)
                    {
                        ShadowmapsPool.Add(MyRwTextures.CreateShadowmap(SpotlightShadowmapSize, SpotlightShadowmapSize));
                    }

                    MyLights.Lights.Data[id.Index].CastsShadowsThisFrame = true;

                    MatrixD viewProjection = MyLights.GetSpotlightViewProjection(id);
                    var     query          = new MyShadowmapQuery
                    {
                        DepthBuffer    = ShadowmapsPool[casterIndex].Dsv,
                        Viewport       = new MyViewport(SpotlightShadowmapSize, SpotlightShadowmapSize),
                        QueryType      = MyFrustumEnum.ShadowProjection,
                        ProjectionInfo = new MyProjectionInfo
                        {
                            WorldCameraOffsetPosition = MyRender11.Environment.CameraPosition,
                            WorldToProjection         = viewProjection,
                            LocalToProjection         = worldMatrix * viewProjection
                        },
                        IgnoredEntities = MyLights.IgnoredEntitites.ContainsKey(id) ? MyLights.IgnoredEntitites[id] : null,
                    };
                    m_shadowmapQueries.Add(query);
                    ++casterIndex;
                }
                else
                {
                    MyLights.Lights.Data[id.Index].CastsShadowsThisFrame = false;
                }

                index++;
            }
        }
Пример #5
0
        static void AddShadowmapQueryIntoCullQuery(MyCullQuery cullQuery, MyShadowmapQuery shadowmapQuery)
        {
            cullQuery.AddDepthPass(shadowmapQuery);

            if (shadowmapQuery.QueryType == MyFrustumEnum.ShadowCascade)
            {
                var smallCulling = new MyCullingSmallObjects
                {
                    ProjectionFactor = shadowmapQuery.ProjectionFactor, // <- this disables culling of objects depending on the previous cascade
                    SkipThreshold    = MyManagers.Shadow.GetSettingsSmallObjectSkipping(shadowmapQuery.Index),
                };
                cullQuery.FrustumCullQueries[cullQuery.Size - 1].SmallObjects = smallCulling;
            }

            cullQuery.FrustumCullQueries[cullQuery.Size - 1].Type    = shadowmapQuery.QueryType;
            cullQuery.FrustumCullQueries[cullQuery.Size - 1].Index   = shadowmapQuery.Index;
            cullQuery.FrustumCullQueries[cullQuery.Size - 1].Ignored = shadowmapQuery.IgnoredEntities;
        }
Пример #6
0
        private void PrepareSpotlights()
        {
            int index       = 0;
            int casterIndex = 0;
            var worldMatrix = MatrixD.CreateTranslation(MyRender11.Environment.Matrices.CameraPosition);

            foreach (var id in MyLightsRendering.VisibleSpotlights)
            {
                if (id.CastsShadows && casterIndex < MAX_SPOTLIGHT_SHADOWCASTERS)
                {
                    if (ShadowmapsPool.Count <= casterIndex)
                    {
                        ShadowmapsPool.Add(MyManagers.RwTextures.CreateDepth("ShadowmapsPool.Item", SpotlightShadowmapSize, SpotlightShadowmapSize, Format.R32_Typeless, Format.R32_Float, Format.D32_Float));
                    }

                    MyLights.SetCastsShadowsThisFrame(id, true);

                    MatrixD viewProjection = MyLights.GetSpotlightViewProjection(id);
                    var     query          = new MyShadowmapQuery
                    {
                        DepthBuffer    = ShadowmapsPool[casterIndex],
                        Viewport       = new MyViewport(SpotlightShadowmapSize, SpotlightShadowmapSize),
                        QueryType      = MyFrustumEnum.ShadowProjection,
                        Index          = casterIndex,
                        ProjectionInfo = new MyProjectionInfo
                        {
                            WorldCameraOffsetPosition = MyRender11.Environment.Matrices.CameraPosition,
                            WorldToProjection         = viewProjection,
                            LocalToProjection         = worldMatrix * viewProjection
                        },
                        IgnoredEntities = MyLights.GetEntitiesIgnoringShadow(id)
                    };
                    m_shadowmapQueries.Add(query);
                    ++casterIndex;
                }
                else
                {
                    MyLights.SetCastsShadowsThisFrame(id, false);
                }

                index++;
            }
        }
        static void AddShadowmapQueryIntoCullQuery(MyCullQuery cullQuery, MyShadowmapQuery shadowmapQuery)
        {
            bool isCascade = shadowmapQuery.QueryType == MyFrustumEnum.ShadowCascade;
            var  matrix    = shadowmapQuery.ProjectionInfo.WorldToProjection;

            cullQuery.AddDepthPass(ref matrix, shadowmapQuery.ProjectionInfo.CurrentLocalToProjection, shadowmapQuery.Viewport, shadowmapQuery.DepthBuffer, isCascade, ToString(shadowmapQuery.QueryType));

            if (isCascade)
            {
                var smallCulling = new MyCullingSmallObjects
                {
                    ProjectionFactor = shadowmapQuery.ProjectionFactor, // <- this disables culling of objects depending on the previous cascade
                    SkipThreshold    = MyManagers.Shadow.GetSettingsSmallObjectSkipping(shadowmapQuery.CascadeIndex),
                };
                cullQuery.FrustumCullQueries[cullQuery.Size - 1].SmallObjects = smallCulling;
                cullQuery.FrustumCullQueries[cullQuery.Size - 1].CascadeIndex = shadowmapQuery.CascadeIndex;
            }

            cullQuery.FrustumCullQueries[cullQuery.Size - 1].Type    = shadowmapQuery.QueryType;
            cullQuery.FrustumCullQueries[cullQuery.Size - 1].Ignored = shadowmapQuery.IgnoredEntities;
        }
Пример #8
0
        static void PrepareCascades()
        {
            MyImmediateRC.RC.Context.CopyResource(m_cascadeShadowmapArray.Resource, m_cascadeShadowmapBackup.Resource);

            bool stabilize = true;

            for (int i = 0; i < 4; i++)
            {
                ++FramesSinceUpdate[i];
            }

            CascadeLightDirection[0] = MyEnvironment.DirectionalLightDir;
            CascadeLightDirection[1] = MyEnvironment.DirectionalLightDir;

            const float DirectionDifferenceThreshold = 0.02f;


            if (FramesSinceUpdate[2] > 180 || MyEnvironment.DirectionalLightDir.Dot(CascadeLightDirection[2]) < (1 - DirectionDifferenceThreshold))
            {
                FramesSinceUpdate[2]     = 0;
                CascadeLightDirection[2] = MyEnvironment.DirectionalLightDir;
            }
            if (FramesSinceUpdate[3] > 180 || MyEnvironment.DirectionalLightDir.Dot(CascadeLightDirection[3]) < (1 - DirectionDifferenceThreshold))
            {
                FramesSinceUpdate[3]     = 0;
                CascadeLightDirection[3] = MyEnvironment.DirectionalLightDir;
            }

            var globalMatrix = CreateGlobalMatrix();

            Matrix[] cascadesMatrices = new Matrix[8];

            var cascadeFrozen = MyRender11.Settings.FreezeCascade.Any(x => x == true);

            if (!cascadeFrozen)
            {
                m_oldView = MyEnvironment.View;
            }

            float cascadesNearClip = 1f;
            float cascadesFarClip  = 1000f;
            float backOffset       = 100f; // more and fit projection to objects inside
            float shadowmapSize    = m_cascadeResolution;

            m_splitDepth[0] = cascadesNearClip;
            m_splitDepth[1] = MyRender11.Settings.CascadesSplit0;
            m_splitDepth[2] = MyRender11.Settings.CascadesSplit1;
            m_splitDepth[3] = MyRender11.Settings.CascadesSplit2;
            m_splitDepth[4] = MyRender11.Settings.CascadesSplit3;

            float unitWidth  = 1 / MyEnvironment.Projection.M11;
            float unitHeight = 1 / MyEnvironment.Projection.M22;
            var   vertices   = new Vector3[]
            {
                new Vector3(-unitWidth, -unitHeight, -1),
                new Vector3(-unitWidth, unitHeight, -1),
                new Vector3(unitWidth, unitHeight, -1),
                new Vector3(unitWidth, -unitHeight, -1),
            };
            var frustumVerticesWS = new Vector3[8];

            for (int c = 0; c < m_cascadesNum; c++)
            {
                for (int i = 0; i < 4; i++)
                {
                    frustumVerticesWS[i]     = vertices[i] * m_splitDepth[c];
                    frustumVerticesWS[i + 4] = vertices[i] * m_splitDepth[c + 1];
                }

                if (MyRender11.Settings.FreezeCascade[c])
                {
                    // draw cascade bounding primtiive
                    if (VisualizeDebug)
                    {
                        var invView = Matrix.Invert(m_oldView);
                        Vector3.Transform(frustumVerticesWS, ref invView, frustumVerticesWS);
                        var batch = MyLinesRenderer.CreateBatch();
                        batch.Add6FacedConvex(frustumVerticesWS, Color.Blue);

                        var bs = BoundingSphere.CreateFromPoints(frustumVerticesWS);
                        var bb = BoundingBox.CreateFromSphere(bs);
                        batch.AddBoundingBox(bb, Color.OrangeRed);

                        batch.Commit();
                    }

                    continue;
                }


                /*
                 * Cascades update scheme:
                 * 0: 1 1 1 1
                 * 1: 1 0 1 0
                 * 2: 0 1 0 0
                 * 3: 0 0 0 1
                 */

                bool skipCascade1 = c == 1 && (MyCommon.FrameCounter % 2) != 0;
                bool skipCascade2 = c == 2 && (MyCommon.FrameCounter % 4) != 1;
                bool skipCascade3 = c == 3 && (MyCommon.FrameCounter % 4) != 3;
                //
                if (skipCascade1 || skipCascade2 || skipCascade3)
                {
                    if (!MyRender11.Settings.UpdateCascadesEveryFrame)
                    {
                        continue;
                    }
                }

                Vector3.Transform(frustumVerticesWS, ref MyEnvironment.InvView, frustumVerticesWS);

                var bSphere = BoundingSphere.CreateFromPoints(frustumVerticesWS);
                if (stabilize)
                {
                    bSphere.Center = bSphere.Center.Round();
                    bSphere.Radius = (float)Math.Ceiling(bSphere.Radius);
                }

                var offset            = bSphere.Radius + cascadesNearClip + backOffset;
                var shadowCameraPosWS = bSphere.Center + CascadeLightDirection[c] * (bSphere.Radius + cascadesNearClip);

                var lightView = VRageMath.Matrix.CreateLookAt(shadowCameraPosWS, shadowCameraPosWS - CascadeLightDirection[c], Math.Abs(Vector3.UnitY.Dot(CascadeLightDirection[c])) < 0.99f ? Vector3.UnitY : Vector3.UnitX);

                Vector3 vMin = new Vector3(-bSphere.Radius, -bSphere.Radius, cascadesNearClip);
                Vector3 vMax = new Vector3(bSphere.Radius, bSphere.Radius, offset + bSphere.Radius);

                var cascadeProjection = Matrix.CreateOrthographicOffCenter(vMin.X, vMax.X, vMin.Y, vMax.Y, vMax.Z, vMin.Z);
                cascadesMatrices[c] = lightView * cascadeProjection;

                var transformed = Vector3.Transform(Vector3.Zero, ref cascadesMatrices[c]) * shadowmapSize / 2;
                var smOffset    = (transformed.Round() - transformed) * 2 / shadowmapSize;

                // stabilize 1st cascade only
                if (stabilize)
                {
                    cascadeProjection.M41 += smOffset.X;
                    cascadeProjection.M42 += smOffset.Y;
                    cascadesMatrices[c]    = lightView * cascadeProjection;
                }

                var inverseCascadeMatrix = Matrix.Invert(cascadesMatrices[c]);
                var corner0 = Vector3.Transform(Vector3.Transform(new Vector3(-1, -1, 0), inverseCascadeMatrix), globalMatrix);
                var corner1 = Vector3.Transform(Vector3.Transform(new Vector3(1, 1, 1), inverseCascadeMatrix), globalMatrix);

                var d = corner1 - corner0;

                var cascadeScale = 1f / (corner1 - corner0);
                m_cascadeScale[c] = new Vector4(cascadeScale, 0);

                var query = new MyShadowmapQuery();
                query.DepthBuffer = m_cascadeShadowmapArray.SubresourceDsv(c);
                query.Viewport    = new MyViewport(shadowmapSize, shadowmapSize);

                m_cascadeInfo[c].WorldCameraOffsetPosition = MyEnvironment.CameraPosition;
                m_cascadeInfo[c].WorldToProjection         = cascadesMatrices[c];
                // todo: skip translation, recalculate matrix in local space, keep world space matrix only for bounding frustum
                m_cascadeInfo[c].LocalToProjection = Matrix.CreateTranslation(MyEnvironment.CameraPosition) * cascadesMatrices[c];

                query.ProjectionInfo   = m_cascadeInfo[c];
                query.ProjectionDir    = CascadeLightDirection[c];
                query.ProjectionFactor = shadowmapSize * shadowmapSize / (bSphere.Radius * bSphere.Radius * 4);

                if (c == 0)
                {
                    query.QueryType = MyFrustumEnum.Cascade0;
                }
                if (c == 1)
                {
                    query.QueryType = MyFrustumEnum.Cascade1;
                }
                if (c == 2)
                {
                    query.QueryType = MyFrustumEnum.Cascade2;
                }
                if (c == 3)
                {
                    query.QueryType = MyFrustumEnum.Cascade3;
                }

                m_shadowmapQueries.Add(query);
            }

            if (true)
            {
                var verticesWS = new Vector3[8];

                var batch = MyLinesRenderer.CreateBatch();

                var cascadeColor = new[]
                {
                    Color.Red,
                    Color.Green,
                    Color.Blue,
                    Color.Yellow
                };

                for (int c = 0; c < m_cascadesNum; c++)
                {
                    if (MyRender11.Settings.FreezeCascade[c])
                    {
                        if (VisualizeDebug)
                        {
                            var inverseViewProj = Matrix.Invert(cascadesMatrices[c]);
                            Vector3.Transform(m_cornersCS, ref inverseViewProj, verticesWS);

                            for (int i = 0; i < verticesWS.Length; i++)
                            {
                                verticesWS[i] += MyEnvironment.CameraPosition;
                            }

                            MyPrimitivesRenderer.Draw6FacedConvex(verticesWS, cascadeColor[c], 0.2f);

                            batch.Add6FacedConvex(verticesWS, Color.Pink);
                        }
                    }
                }

                batch.Commit();
            }

            var mapping = MyMapping.MapDiscard(m_csmConstants);

            for (int c = 0; c < m_cascadesNum; c++)
            {
                mapping.stream.Write(Matrix.Transpose(m_cascadeInfo[c].CurrentLocalToProjection * MyMatrixHelpers.ClipspaceToTexture));
            }
            for (int i = m_cascadesNum; i < 8; i++)
            {
                mapping.stream.Write(Matrix.Zero);
            }

            for (int i = 0; i < m_splitDepth.Length; i++)
            {
                mapping.stream.Write(m_splitDepth[i]);
            }
            for (int i = m_splitDepth.Length; i < 8; i++)
            {
                mapping.stream.Write(0.0f);
            }

            for (int i = 0; i < 4; i++)
            {
                mapping.stream.Write(m_cascadeScale[i] / m_cascadeScale[0]);
            }

            mapping.Unmap();
        }
Пример #9
0
        /// <summary>
        /// Creates shadowmap queries and appends them to the provided list
        /// </summary>
        internal unsafe void PrepareQueries(List <MyShadowmapQuery> appendShadowmapQueries)
        {
            Debug.Assert(appendShadowmapQueries != null, "Shadowmap query list cannot be null!");
            if (!MyRenderProxy.Settings.EnableShadows || !MyRender11.DebugOverrides.Shadows)
            {
                return;
            }

            MyImmediateRC.RC.BeginProfilingBlock("PrepareCascades");
            MyImmediateRC.RC.DeviceContext.CopyResource(m_cascadeShadowmapArray.Resource, m_cascadeShadowmapBackup.Resource);

            bool        stabilize = true;
            const float DirectionDifferenceThreshold = 0.0175f;

            float shadowChangeDelayMultiplier = 180;

            for (int cascadeIndex = 0; cascadeIndex < m_initializedShadowCascadesCount; ++cascadeIndex)
            {
                ++m_shadowCascadeFramesSinceLightUpdate[cascadeIndex];

                if (m_shadowCascadeFramesSinceLightUpdate[cascadeIndex] > cascadeIndex * shadowChangeDelayMultiplier ||
                    MyRender11.Environment.DirectionalLightDir.Dot(m_shadowCascadeLightDirections[cascadeIndex]) < (1 - DirectionDifferenceThreshold))
                {
                    m_shadowCascadeLightDirections[cascadeIndex]        = MyRender11.Environment.DirectionalLightDir;
                    m_shadowCascadeFramesSinceLightUpdate[cascadeIndex] = 0;
                }
            }

            var globalMatrix = CreateGlobalMatrix();


            float cascadesNearClip = 1f;

            float backOffset    = MyRender11.RenderSettings.ShadowQuality.BackOffset();
            float shadowmapSize = MyRender11.RenderSettings.ShadowQuality.ShadowCascadeResolution();

            for (int cascadeIndex = 0; cascadeIndex < ShadowCascadeSplitDepths.Length; ++cascadeIndex)
            {
                ShadowCascadeSplitDepths[cascadeIndex] = MyRender11.RenderSettings.ShadowQuality.ShadowCascadeSplit(cascadeIndex);
            }

            double unitWidth  = 1.0 / MyRender11.Environment.Projection.M11;
            double unitHeight = 1.0 / MyRender11.Environment.Projection.M22;

            Vector3D *untransformedVertices = stackalloc Vector3D[4];

            untransformedVertices[0] = new Vector3D(-unitWidth, -unitHeight, -1);
            untransformedVertices[1] = new Vector3D(-unitWidth, unitHeight, -1);
            untransformedVertices[2] = new Vector3D(unitWidth, unitHeight, -1);
            untransformedVertices[3] = new Vector3D(unitWidth, -unitHeight, -1);

            MatrixD *cascadesMatrices = stackalloc MatrixD[MaxShadowCascades];

            for (int cascadeIndex = 0; cascadeIndex < m_initializedShadowCascadesCount; ++cascadeIndex)
            {
                for (int vertexIndex = 0; vertexIndex < 4; ++vertexIndex)
                {
                    m_frustumVerticesWS[vertexIndex]     = untransformedVertices[vertexIndex] * ShadowCascadeSplitDepths[cascadeIndex];
                    m_frustumVerticesWS[vertexIndex + 4] = untransformedVertices[vertexIndex] * ShadowCascadeSplitDepths[cascadeIndex + 1];
                }

                bool skipCascade = MyCommon.FrameCounter % (ulong)m_shadowCascadeUpdateIntervals[cascadeIndex].Item1 != (ulong)m_shadowCascadeUpdateIntervals[cascadeIndex].Item2;
                bool forceUpdate = ShadowCascadeSplitDepths[cascadeIndex] > 1000f && Vector3D.DistanceSquared(m_shadowCascadeUpdatePositions[cascadeIndex], MyRender11.Environment.CameraPosition) > Math.Pow(1000, 2);
                //
                if (!forceUpdate && skipCascade && !MyRenderProxy.Settings.UpdateCascadesEveryFrame)
                {
                    continue;
                }
                if (MyRenderProxy.Settings.ShadowCascadeFrozen[cascadeIndex])
                {
                    continue;
                }

                m_shadowCascadeUpdatePositions[cascadeIndex] = MyRender11.Environment.CameraPosition;

                MatrixD invView = MyRender11.Environment.InvView;
                Vector3D.Transform(m_frustumVerticesWS, ref invView, m_frustumVerticesWS);

                var bSphere = BoundingSphereD.CreateFromPoints(m_frustumVerticesWS);
                if (stabilize)
                {
                    bSphere.Center = bSphere.Center.Round();
                    bSphere.Radius = Math.Ceiling(bSphere.Radius);
                }

                var shadowCameraPosWS = bSphere.Center + m_shadowCascadeLightDirections[cascadeIndex] * (bSphere.Radius + cascadesNearClip);

                var lightView = VRageMath.MatrixD.CreateLookAt(shadowCameraPosWS, shadowCameraPosWS - m_shadowCascadeLightDirections[cascadeIndex], Math.Abs(Vector3.UnitY.Dot(m_shadowCascadeLightDirections[cascadeIndex])) < 0.99f ? Vector3.UnitY : Vector3.UnitX);
                var offset    = bSphere.Radius + cascadesNearClip + backOffset;

                Vector3D vMin = new Vector3D(-bSphere.Radius, -bSphere.Radius, cascadesNearClip);
                Vector3D vMax = new Vector3D(bSphere.Radius, bSphere.Radius, offset + bSphere.Radius);

                var cascadeProjection = MatrixD.CreateOrthographicOffCenter(vMin.X, vMax.X, vMin.Y, vMax.Y, vMax.Z, vMin.Z);
                cascadesMatrices[cascadeIndex] = lightView * cascadeProjection;

                var transformed = Vector3D.Transform(Vector3D.Zero, cascadesMatrices[cascadeIndex]) * shadowmapSize / 2;
                var smOffset    = (transformed.Round() - transformed) * 2 / shadowmapSize;

                // stabilize 1st cascade only
                if (stabilize)
                {
                    cascadeProjection.M41         += smOffset.X;
                    cascadeProjection.M42         += smOffset.Y;
                    cascadesMatrices[cascadeIndex] = lightView * cascadeProjection;
                }

                var inverseCascadeMatrix = MatrixD.Invert(cascadesMatrices[cascadeIndex]);
                var corner0 = Vector3D.Transform(Vector3D.Transform(new Vector3D(-1, -1, 0), inverseCascadeMatrix), globalMatrix);
                var corner1 = Vector3D.Transform(Vector3D.Transform(new Vector3D(1, 1, 1), inverseCascadeMatrix), globalMatrix);

                var diameter = corner1 - corner0;

                var cascadeScale = 1f / diameter;
                ShadowCascadeScales[cascadeIndex] = new Vector4D(cascadeScale, 0);

                var query = new MyShadowmapQuery();
                query.DepthBuffer = m_cascadeShadowmapArray.SubresourceDsv(cascadeIndex);
                query.Viewport    = new MyViewport(shadowmapSize, shadowmapSize);

                m_cascadeInfo[cascadeIndex].WorldCameraOffsetPosition = MyRender11.Environment.CameraPosition;
                m_cascadeInfo[cascadeIndex].WorldToProjection         = cascadesMatrices[cascadeIndex];
                // todo: skip translation, recalculate matrix in local space, keep world space matrix only for bounding frustum
                m_cascadeInfo[cascadeIndex].LocalToProjection = Matrix.CreateTranslation(MyRender11.Environment.CameraPosition) * cascadesMatrices[cascadeIndex];

                query.ProjectionInfo   = m_cascadeInfo[cascadeIndex];
                query.ProjectionDir    = m_shadowCascadeLightDirections[cascadeIndex];
                query.ProjectionFactor = (float)(shadowmapSize * shadowmapSize / (bSphere.Radius * bSphere.Radius * 4));

                query.QueryType    = MyFrustumEnum.ShadowCascade;
                query.CascadeIndex = cascadeIndex;

                appendShadowmapQueries.Add(query);
            }

            DebugProcessFrustrums();

            FillConstantBuffer(m_csmConstants);

            MyImmediateRC.RC.EndProfilingBlock();
        }
Пример #10
0
        static void PrepareCascades()
        {
            MyImmediateRC.RC.BeginProfilingBlock("PrepareCascades");
            MyImmediateRC.RC.Context.CopyResource(m_cascadeShadowmapArray.Resource, m_cascadeShadowmapBackup.Resource);

            bool        stabilize = true;
            const float DirectionDifferenceThreshold = 0.02f;

            for (int cascadeIndex = 0; cascadeIndex < m_initializedShadowCascadesCount; ++cascadeIndex)
            {
                ++m_shadowCascadeFramesSinceUpdate[cascadeIndex];

                if (m_shadowCascadeFramesSinceUpdate[cascadeIndex] > cascadeIndex * 60 ||
                    MyEnvironment.DirectionalLightDir.Dot(m_shadowCascadeLightDirections[cascadeIndex]) < (1 - DirectionDifferenceThreshold))
                {
                    m_shadowCascadeLightDirections[cascadeIndex]   = MyEnvironment.DirectionalLightDir;
                    m_shadowCascadeFramesSinceUpdate[cascadeIndex] = 0;
                }
            }

            var globalMatrix = CreateGlobalMatrix();

            MatrixD[] cascadesMatrices = new MatrixD[8];

            var cascadeFrozen = MyRender11.Settings.ShadowCascadeFrozen.Any(x => x == true);

            if (!cascadeFrozen)
            {
                m_oldView = MyEnvironment.View;
            }

            float cascadesNearClip = 1f;

            float cascadesFarClip = MyRender11.RenderSettings.ShadowQuality.ShadowCascadeSplit(m_initializedShadowCascadesCount);
            float backOffset      = MyRender11.RenderSettings.ShadowQuality.BackOffset();
            float shadowmapSize   = MyRender11.RenderSettings.ShadowQuality.ShadowCascadeResolution();

            var  oldCascadeSplit = 0.0f;
            bool useFarShadows   = MyRenderProxy.Settings.FarShadowDistanceOverride > MyRender11.Settings.ShadowCascadeMaxDistance;

            if (useFarShadows)
            {
                oldCascadeSplit = MyRender11.Settings.ShadowCascadeMaxDistance;

                MyRender11.Settings.ShadowCascadeMaxDistance = MyRenderProxy.Settings.FarShadowDistanceOverride;
            }

            for (int cascadeIndex = 0; cascadeIndex < ShadowCascadeSplitDepths.Length; ++cascadeIndex)
            {
                ShadowCascadeSplitDepths[cascadeIndex] = MyRender11.RenderSettings.ShadowQuality.ShadowCascadeSplit(cascadeIndex);
            }

            if (useFarShadows)
            {
                MyRender11.Settings.ShadowCascadeMaxDistance = oldCascadeSplit;
            }

            double unitWidth  = 1.0 / MyEnvironment.Projection.M11;
            double unitHeight = 1.0 / MyEnvironment.Projection.M22;
            var    vertices   = new Vector3D[]
            {
                new Vector3D(-unitWidth, -unitHeight, -1),
                new Vector3D(-unitWidth, unitHeight, -1),
                new Vector3D(unitWidth, unitHeight, -1),
                new Vector3D(unitWidth, -unitHeight, -1),
            };
            var frustumVerticesWS = new Vector3D[8];

            for (int cascadeIndex = 0; cascadeIndex < m_initializedShadowCascadesCount; ++cascadeIndex)
            {
                for (int i = 0; i < 4; i++)
                {
                    frustumVerticesWS[i]     = vertices[i] * ShadowCascadeSplitDepths[cascadeIndex];
                    frustumVerticesWS[i + 4] = vertices[i] * ShadowCascadeSplitDepths[cascadeIndex + 1];
                }

                if (MyRender11.Settings.ShadowCascadeFrozen[cascadeIndex])
                {
                    // draw cascade bounding primtiive
                    if (VisualizeDebug)
                    {
                        var oldInvView = MatrixD.Invert(m_oldView);
                        Vector3D.Transform(frustumVerticesWS, ref oldInvView, frustumVerticesWS);

                        var verticesF = new Vector3[8];
                        for (int i = 0; i < 8; i++)
                        {
                            verticesF[i] = frustumVerticesWS[i];
                        }
                        var batch = MyLinesRenderer.CreateBatch();
                        batch.Add6FacedConvex(verticesF, Color.Blue);

                        var bs = BoundingSphere.CreateFromPoints(verticesF);
                        var bb = BoundingBox.CreateFromSphere(bs);
                        batch.AddBoundingBox(bb, Color.OrangeRed);

                        batch.Commit();
                    }

                    continue;
                }


                /*
                 * Cascades update scheme:
                 *    1 2 3 4 5 6 7
                 * 0: 1 1 1 1 1 1 1
                 * 1: 1 0 1 0 1 0 1
                 * 2: 0 1 0 0 1 0 0
                 * 3: 0 0 0 1 0 0 0
                 * 4: 0 0 0 0 0 1 0
                 * 5: 0 0 0 0 0 0 1
                 */

                bool skipCascade  = false; // TODO: properly
                bool skipCascade1 = cascadeIndex == 1 && (MyCommon.FrameCounter % 2) != 0;
                bool skipCascade2 = cascadeIndex == 2 && (MyCommon.FrameCounter % 4) != 1;
                bool skipCascade3 = cascadeIndex == 3 && (MyCommon.FrameCounter % 4) != 3;
                bool skipCascade4 = cascadeIndex == 4 && (MyCommon.FrameCounter % 8) != 5;
                bool skipCascade5 = cascadeIndex == 5 && (MyCommon.FrameCounter % 8) != 7;
                skipCascade = skipCascade1 || skipCascade2 || skipCascade3 || skipCascade4 || skipCascade5;
                //
                if (skipCascade && !MyRender11.Settings.UpdateCascadesEveryFrame)
                {
                    continue;
                }

                MatrixD invView = MyEnvironment.InvView;
                Vector3D.Transform(frustumVerticesWS, ref invView, frustumVerticesWS);

                var bSphere = BoundingSphereD.CreateFromPoints((IEnumerable <Vector3D>)frustumVerticesWS);
                if (stabilize)
                {
                    bSphere.Center = bSphere.Center.Round();
                    bSphere.Radius = Math.Ceiling(bSphere.Radius);
                }

                var shadowCameraPosWS = bSphere.Center + m_shadowCascadeLightDirections[cascadeIndex] * (bSphere.Radius + cascadesNearClip);

                var lightView     = VRageMath.MatrixD.CreateLookAt(shadowCameraPosWS, shadowCameraPosWS - m_shadowCascadeLightDirections[cascadeIndex], Math.Abs(Vector3.UnitY.Dot(m_shadowCascadeLightDirections[cascadeIndex])) < 0.99f ? Vector3.UnitY : Vector3.UnitX);
                var longestShadow = MyRenderProxy.Settings.LongShadowFactor;
                var offset        = bSphere.Radius + cascadesNearClip + backOffset + (longestShadow < 0 ? 0.0 : longestShadow);

                Vector3D vMin = new Vector3D(-bSphere.Radius, -bSphere.Radius, cascadesNearClip);
                Vector3D vMax = new Vector3D(bSphere.Radius, bSphere.Radius, offset + bSphere.Radius);

                var cascadeProjection = MatrixD.CreateOrthographicOffCenter(vMin.X, vMax.X, vMin.Y, vMax.Y, vMax.Z, vMin.Z);
                cascadesMatrices[cascadeIndex] = lightView * cascadeProjection;

                var transformed = Vector3D.Transform(Vector3D.Zero, cascadesMatrices[cascadeIndex]) * shadowmapSize / 2;
                var smOffset    = (transformed.Round() - transformed) * 2 / shadowmapSize;

                // stabilize 1st cascade only
                if (stabilize)
                {
                    cascadeProjection.M41         += smOffset.X;
                    cascadeProjection.M42         += smOffset.Y;
                    cascadesMatrices[cascadeIndex] = lightView * cascadeProjection;
                }

                var inverseCascadeMatrix = MatrixD.Invert(cascadesMatrices[cascadeIndex]);
                var corner0 = Vector3D.Transform(Vector3D.Transform(new Vector3D(-1, -1, 0), inverseCascadeMatrix), globalMatrix);
                var corner1 = Vector3D.Transform(Vector3D.Transform(new Vector3D(1, 1, 1), inverseCascadeMatrix), globalMatrix);

                var d = corner1 - corner0;

                var cascadeScale = 1f / (corner1 - corner0);
                ShadowCascadeScales[cascadeIndex] = new Vector4D(cascadeScale, 0);

                var query = new MyShadowmapQuery();
                query.DepthBuffer = m_cascadeShadowmapArray.SubresourceDsv(cascadeIndex);
                query.Viewport    = new MyViewport(shadowmapSize, shadowmapSize);

                m_cascadeInfo[cascadeIndex].WorldCameraOffsetPosition = MyEnvironment.CameraPosition;
                m_cascadeInfo[cascadeIndex].WorldToProjection         = cascadesMatrices[cascadeIndex];
                // todo: skip translation, recalculate matrix in local space, keep world space matrix only for bounding frustum
                m_cascadeInfo[cascadeIndex].LocalToProjection = Matrix.CreateTranslation(MyEnvironment.CameraPosition) * cascadesMatrices[cascadeIndex];

                query.ProjectionInfo   = m_cascadeInfo[cascadeIndex];
                query.ProjectionDir    = m_shadowCascadeLightDirections[cascadeIndex];
                query.ProjectionFactor = (float)(shadowmapSize * shadowmapSize / (bSphere.Radius * bSphere.Radius * 4));

                query.QueryType    = MyFrustumEnum.ShadowCascade;
                query.CascadeIndex = cascadeIndex;

                m_shadowmapQueries.Add(query);
            }

            if (true)
            {
                var verticesWS = new Vector3D[8];

                var batch = MyLinesRenderer.CreateBatch();

                var cascadeColor = new[]
                {
                    Color.Red,
                    Color.Green,
                    Color.Blue,
                    Color.Yellow
                };

                for (int c = 0; c < m_initializedShadowCascadesCount; c++)
                {
                    if (MyRender11.Settings.ShadowCascadeFrozen[c])
                    {
                        if (VisualizeDebug)
                        {
                            var inverseViewProj = MatrixD.Invert(cascadesMatrices[c]);
                            Vector3D.Transform(m_cornersCS, ref inverseViewProj, verticesWS);

                            for (int i = 0; i < verticesWS.Length; i++)
                            {
                                verticesWS[i] += MyEnvironment.CameraPosition;
                            }

                            var verticesF = new Vector3[8];
                            for (int i = 0; i < 8; i++)
                            {
                                verticesF[i] = verticesWS[i];
                            }

                            MyPrimitivesRenderer.Draw6FacedConvex(verticesF, cascadeColor[c], 0.2f);
                            batch.Add6FacedConvex(verticesF, Color.Pink);
                        }
                    }
                }

                batch.Commit();
            }

            var mapping = MyMapping.MapDiscard(m_csmConstants);

            for (int c = 0; c < m_initializedShadowCascadesCount; c++)
            {
                mapping.stream.Write(Matrix.Transpose(m_cascadeInfo[c].CurrentLocalToProjection * MyMatrixHelpers.ClipspaceToTexture));
            }
            for (int i = m_initializedShadowCascadesCount; i < 8; i++)
            {
                mapping.stream.Write(Matrix.Zero);
            }

            for (int i = 0; i < ShadowCascadeSplitDepths.Length; i++)
            {
                mapping.stream.Write(ShadowCascadeSplitDepths[i]);
            }
            for (int i = ShadowCascadeSplitDepths.Length; i < 8; i++)
            {
                mapping.stream.Write(0.0f);
            }

            for (int i = 0; i < m_initializedShadowCascadesCount; i++)
            {
                mapping.stream.Write(ShadowCascadeScales[i] / ShadowCascadeScales[0]);
            }

            mapping.Unmap();

            MyImmediateRC.RC.EndProfilingBlock();
        }