public MyShadowmapQuery GetShadowmapQueryForSingleShadow(int index, IDsvBindable dsvBindable)
        {
            MyProjectionInfo projInfo = new MyProjectionInfo();
            projInfo.WorldCameraOffsetPosition = MyRender11.Environment.Matrices.CameraPosition;
            projInfo.WorldToProjection = MatrixWorldAt0ToShadowSpace;
            projInfo.LocalToProjection = Matrix.CreateTranslation(MyRender11.Environment.Matrices.CameraPosition) * MatrixWorldAt0ToShadowSpace;

            MyShadowmapQuery query = new MyShadowmapQuery();
            query.DepthBuffer = dsvBindable;
            query.Viewport = new MyViewport(dsvBindable.Size.X, dsvBindable.Size.Y);
            query.ProjectionInfo = projInfo;
            query.ProjectionFactor = (float)Math.Sqrt(dsvBindable.Size.X * dsvBindable.Size.Y / (m_matrixShadowToWorldAt0Space.Left.Length() * m_matrixShadowToWorldAt0Space.Up.Length()));

            query.QueryType = MyFrustumEnum.ShadowProjection;
            query.Index = index;
            return query;
        }
Beispiel #2
0
        public MyShadowmapQuery GetShadowmapQueryForSingleShadow(int index, IDsvBindable dsvBindable)
        {
            MyProjectionInfo projInfo = new MyProjectionInfo();

            projInfo.WorldCameraOffsetPosition = MyRender11.Environment.Matrices.CameraPosition;
            projInfo.WorldToProjection         = MatrixWorldAt0ToShadowSpace;
            projInfo.LocalToProjection         = Matrix.CreateTranslation(MyRender11.Environment.Matrices.CameraPosition) * MatrixWorldAt0ToShadowSpace;

            MyShadowmapQuery query = new MyShadowmapQuery();

            query.DepthBuffer      = dsvBindable;
            query.Viewport         = new MyViewport(dsvBindable.Size.X, dsvBindable.Size.Y);
            query.ProjectionInfo   = projInfo;
            query.ProjectionFactor = (float)Math.Sqrt(dsvBindable.Size.X * dsvBindable.Size.Y / (m_matrixShadowToWorldAt0Space.Left.Length() * m_matrixShadowToWorldAt0Space.Up.Length()));

            query.QueryType = MyFrustumEnum.ShadowProjection;
            query.Index     = index;
            return(query);
        }
        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;
        }
        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;
        }
        /// <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 (!MyRender11.Settings.EnableShadows || !MyRender11.DebugOverrides.Shadows || MyRender11.RenderSettings.ShadowQuality.GetShadowsQuality() == MyShadowsQuality.DISABLED)
                return;

            MyGpuProfiler.IC_BeginBlock("PrepareCascades");
            MyImmediateRC.RC.CopyResource(m_cascadeShadowmapArray, m_cascadeShadowmapBackup);

            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.Data.EnvironmentLight.SunLightDirection.Dot(m_shadowCascadeLightDirections[cascadeIndex]) < (1 - DirectionDifferenceThreshold))
                {
                    m_shadowCascadeLightDirections[cascadeIndex] = MyRender11.Environment.Data.EnvironmentLight.SunLightDirection;
                    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.Matrices.Projection.M11;
            double unitHeight = 1.0 / MyRender11.Environment.Matrices.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.Matrices.CameraPosition) > Math.Pow(1000, 2);
                // 
                if (!forceUpdate && skipCascade && !Settings.Data.UpdateCascadesEveryFrame)
                    continue;
                if (Settings.ShadowCascadeFrozen[cascadeIndex])
                    continue;

                m_shadowCascadeUpdatePositions[cascadeIndex] = MyRender11.Environment.Matrices.CameraPosition;

                MatrixD invView = MyRender11.Environment.Matrices.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.Matrices.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.Matrices.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.Index = cascadeIndex;

                appendShadowmapQueries.Add(query);
            }

            DebugProcessFrustrums();

            FillConstantBuffer(m_csmConstants);

            MyGpuProfiler.IC_EndBlock();
        }