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]); } }
public void Update(MyShadowVolume[] volumes, ref MyShadowsSettings settings, float shadowmapResolution) { // Update sun position: if (!settings.NewData.FreezeSunDirection) { Vector3D currentSunLightDir = MyRender11.Environment.Data.EnvironmentLight.SunLightDirection; Vector3D prevSunLightDir = m_sunDirection; currentSunLightDir.Normalize(); prevSunLightDir.Normalize(); double diffAngle = 360.0 / Math.PI * Math.Acos(Vector3D.Dot(prevSunLightDir, currentSunLightDir)); if (diffAngle >= settings.NewData.SunAngleThreshold) m_sunDirection = MyRender11.Environment.Data.EnvironmentLight.SunLightDirection; } double unitWidth = 1.0/MyRender11.Environment.Matrices.Projection.M11; double unitHeight = 1.0/MyRender11.Environment.Matrices.Projection.M22; for (int cascadeIndex = 0; cascadeIndex < volumes.Length; ++cascadeIndex) { // Update primitive vertices that are inside of frustrum matrix: float baseDist = settings.Cascades[cascadeIndex].FullCoverageDepth; float baseCut = (cascadeIndex == 0) ? 0 : settings.Cascades[cascadeIndex - 1].FullCoverageDepth; Vector3D[] verts; float extDepth = settings.Cascades[cascadeIndex].ExtendedCoverageDepth; if (!settings.NewData.StabilizeRotation) verts = MyCsmPlacementStrategyUtil.CreateCutPyramidExt(unitWidth, unitHeight, baseDist, baseCut, extDepth); else { double coneRadius = Math.Sqrt((unitWidth * unitWidth) + (unitHeight * unitHeight)); verts = MyCsmPlacementStrategyUtil.CreateCutConeExt(coneRadius, baseDist, baseCut, extDepth); } double shadowVolumeSize = GetStableShadowVolumeSize(verts, shadowmapResolution); MatrixD invView = MyRender11.Environment.Matrices.InvView; Vector3D.Transform(verts, ref invView, verts); float zOffset = settings.NewData.ZOffset; MatrixD shadowMatrixWorld; if (!settings.NewData.StabilizeMovement) shadowMatrixWorld = CreateRigidLightMatrix(verts, m_sunDirection, zOffset); else shadowMatrixWorld = CreateStableLightMatrix(verts, m_sunDirection, zOffset, shadowVolumeSize, shadowmapResolution); Matrix matrixTranslation = Matrix.CreateTranslation(MyRender11.Environment.Matrices.CameraPosition); Matrix shadowMatrixWorldAt0 = matrixTranslation*shadowMatrixWorld; volumes[cascadeIndex].SetMatrixWorldAt0ToShadow(shadowMatrixWorldAt0); } }