/// <summary> /// Add the spheres that prevent autopilot from getting stuck between objects. /// </summary> /// <remarks> /// For every cluster, adds a sphere that includes the centre of every sphere in the cluster. /// </remarks> public void AddMiddleSpheres() { for (int indexO = Clusters.Count - 1; indexO >= 0; indexO--) { List <RepulseSphere> cluster = Clusters[indexO]; if (cluster.Count < 2) { continue; } Vector3D[] points = new Vector3D[cluster.Count]; for (int indexI = cluster.Count - 1; indexI >= 0; indexI--) { points[indexI] = cluster[indexI].Centre; } BoundingSphereD sphere = BoundingSphereD.CreateFromPoints(points); RepulseSphere repulse = new RepulseSphere() { Centre = sphere.Center, FixedRadius = sphere.Radius }; #if DEBUG List <IMyEntity> entities; ResourcePool.Get(out entities); foreach (RepulseSphere rs in cluster) { entities.AddArray(rs.Entities); } repulse.Entities = entities.ToArray(); entities.Clear(); ResourcePool.Return(entities); #endif cluster.Add(repulse); } }
public static BoundingSphereD NewObbClosestTriCorners(MyEntity ent, Vector3D pos) { var entCorners = new Vector3D[8]; var quaternion = Quaternion.CreateFromRotationMatrix(ent.PositionComp.GetOrientation()); var halfExtents = ent.PositionComp.LocalAABB.HalfExtents; var gridCenter = ent.PositionComp.WorldAABB.Center; var obb = new MyOrientedBoundingBoxD(gridCenter, halfExtents, quaternion); var minValue = double.MaxValue; var minValue0 = double.MaxValue; var minValue1 = double.MaxValue; var minValue2 = double.MaxValue; var minValue3 = double.MaxValue; var minNum = -2; var minNum0 = -2; var minNum1 = -2; var minNum2 = -2; var minNum3 = -2; obb.GetCorners(entCorners, 0); for (int i = 0; i < entCorners.Length; i++) { var gridCorner = entCorners[i]; var range = gridCorner - pos; var test = (range.X * range.X) + (range.Y * range.Y) + (range.Z * range.Z); if (test < minValue3) { if (test < minValue) { minValue3 = minValue2; minNum3 = minNum2; minValue2 = minValue1; minNum2 = minNum1; minValue1 = minValue0; minNum1 = minNum0; minValue0 = minValue; minNum0 = minNum; minValue = test; minNum = i; } else if (test < minValue0) { minValue3 = minValue2; minNum3 = minNum2; minValue2 = minValue1; minNum2 = minNum1; minValue1 = minValue0; minNum1 = minNum0; minValue0 = test; minNum0 = i; } else if (test < minValue1) { minValue3 = minValue2; minNum3 = minNum2; minValue2 = minValue1; minNum2 = minNum1; minValue1 = test; minNum1 = i; } else if (test < minValue2) { minValue3 = minValue2; minNum3 = minNum2; minValue2 = test; minNum2 = i; } else { minValue3 = test; minNum3 = i; } } } var corner = entCorners[minNum]; var corner0 = entCorners[minNum0]; var corner1 = entCorners[minNum1]; var corner2 = entCorners[minNum2]; var corner3 = gridCenter; Vector3D[] closestCorners = { corner, corner0, corner3 }; var sphere = BoundingSphereD.CreateFromPoints(closestCorners); //var subObb = MyOrientedBoundingBoxD.CreateFromBoundingBox(box); return(sphere); }
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(); }
/// <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(); }
public unsafe void Update(MyShadowVolume[] volumes, ref MyShadowsSettings settings, float shadowmapResolution) { bool stabilize = true; float cascadesNearClip = 1f; float shadowChangeDelayMultiplier = 180; const float directionDifferenceThreshold = 0.0175f; float backOffset = MyRender11.RenderSettings.ShadowQuality.BackOffset(); float shadowmapSize = MyRender11.RenderSettings.ShadowQuality.ShadowCascadeResolution(); Array.Resize(ref m_shadowCascadeSplitDepths, volumes.Length + 1); Array.Resize(ref m_shadowCascadeUpdatePositions, volumes.Length); Array.Resize(ref m_shadowCascadeFramesSinceLightUpdate, volumes.Length); Array.Resize(ref m_shadowCascadeLightDirections, volumes.Length); for (int cascadeIndex = 0; cascadeIndex < volumes.Length; ++cascadeIndex) { m_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[volumes.Length]; for (int cascadeIndex = 0; cascadeIndex < volumes.Length; ++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; } } for (int cascadeIndex = 0; cascadeIndex < volumes.Length; ++cascadeIndex) { for (int vertexIndex = 0; vertexIndex < 4; ++vertexIndex) { m_frustumVerticesWS[vertexIndex] = untransformedVertices[vertexIndex] * m_shadowCascadeSplitDepths[cascadeIndex]; m_frustumVerticesWS[vertexIndex + 4] = untransformedVertices[vertexIndex] * m_shadowCascadeSplitDepths[cascadeIndex + 1]; } bool skipCascade = MyCommon.FrameCounter % (ulong)m_shadowCascadeUpdateIntervals[cascadeIndex].Item1 != (ulong)m_shadowCascadeUpdateIntervals[cascadeIndex].Item2; bool forceUpdate = m_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; } Matrix matrixTranslation = Matrix.CreateTranslation(MyRender11.Environment.Matrices.CameraPosition); cascadesMatrices[cascadeIndex] = matrixTranslation * cascadesMatrices[cascadeIndex]; volumes[cascadeIndex].SetMatrixWorldAt0ToShadow(cascadesMatrices[cascadeIndex]); } }