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; }
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(); }