public MyShadowRenderer(int shadowMapSize, MyRenderTargets renderTarget, MyRenderTargets depthTarget, bool multiThreaded) { ShadowMapCascadeSize = shadowMapSize; m_shadowRenderTarget = renderTarget; m_shadowDepthTarget = depthTarget; for (int i = 0; i < NumSplits; i++) { m_lightCameras[i] = new MyOrthographicCamera(1, 1, 1, 10); // Occ queries for shadows are disabled, so save memory by commenting this //m_occlusionQueriesLists[i] = new List<MyOcclusionQueryIssue>(1024); m_cascadeQueries[i] = new MyOcclusionQueryIssue(null); m_visibility[i] = true; } MultiThreaded = multiThreaded; }
/// <summary> /// Creates the renderer /// </summary> /// <param name="graphicsDevice">The GraphicsDevice to use for rendering</param> /// <param name="contentManager">The MyCustomContentManager to use for loading content</param> public MyShadowRenderer(int shadowMapSize, MyRenderTargets renderTarget, MyRenderTargets depthTarget, bool multiThreaded) { ShadowMapCascadeSize = shadowMapSize; m_shadowRenderTarget = renderTarget; m_shadowDepthTarget = depthTarget; for (int i = 0; i < NumSplits; i++) { m_lightCameras[i] = new MyOrthographicCamera(1, 1, 1, 10); // Occ queries for shadows are disabled, so save memory by commenting this //m_occlusionQueriesLists[i] = new List<MyOcclusionQueryIssue>(1024); m_cascadeQueries[i] = new MyOcclusionQueryIssue(null); m_visibility[i] = true; } MultiThreaded = multiThreaded; }
/// <summary> /// Determines the size of the frustum needed to cover the viewable area, /// then creates an appropriate orthographic projection. /// </summary> /// <param name="light">The directional light to use</param> /// <param name="mainCamera">The camera viewing the scene</param> protected MyOrthographicCamera CalculateFrustum(MyOrthographicCamera lightCamera, MyPerspectiveCamera mainCamera, float minZ, float maxZ) { MatrixD cameraMatrix; mainCamera.GetWorldMatrix(out cameraMatrix); MatrixD cameraMatrixAtZero = cameraMatrix; cameraMatrixAtZero.Translation = Vector3D.Zero; for (int i = 0; i < 4; i++) m_splitFrustumCornersVS[i] = m_frustumCornersVS[i + 4] * (minZ / mainCamera.FarClip); for (int i = 4; i < 8; i++) m_splitFrustumCornersVS[i] = m_frustumCornersVS[i] * (maxZ / mainCamera.FarClip); Vector3D.Transform(m_splitFrustumCornersVS, ref cameraMatrix, m_frustumCornersWS); // Position the shadow-caster camera so that it's looking at the centroid, // and backed up in the direction of the sunlight MatrixD viewMatrix = MatrixD.CreateLookAt(MyRenderCamera.Position - (MyRender.Sun.Direction * (float)mainCamera.FarClip), MyRenderCamera.Position, Vector3D.Up); // Determine the position of the frustum corners in light space Vector3D.Transform(m_frustumCornersWS, ref viewMatrix, m_frustumCornersLS); // Calculate an orthographic projection by sizing a bounding box // to the frustum coordinates in light space Vector3D mins = m_frustumCornersLS[0]; Vector3D maxes = m_frustumCornersLS[0]; for (int i = 0; i < 8; i++) { if (m_frustumCornersLS[i].X > maxes.X) maxes.X = m_frustumCornersLS[i].X; else if (m_frustumCornersLS[i].X < mins.X) mins.X = m_frustumCornersLS[i].X; if (m_frustumCornersLS[i].Y > maxes.Y) maxes.Y = m_frustumCornersLS[i].Y; else if (m_frustumCornersLS[i].Y < mins.Y) mins.Y = m_frustumCornersLS[i].Y; if (m_frustumCornersLS[i].Z > maxes.Z) maxes.Z = m_frustumCornersLS[i].Z; else if (m_frustumCornersLS[i].Z < mins.Z) mins.Z = m_frustumCornersLS[i].Z; } // Update an orthographic camera for collision detection lightCamera.UpdateUnscaled(mins.X, maxes.X, mins.Y, maxes.Y, -maxes.Z - SHADOW_MAX_OFFSET, -mins.Z); lightCamera.SetViewMatrixUnscaled(ref viewMatrix); // We snap the camera to 1 pixel increments so that moving the camera does not cause the shadows to jitter. // This is a matter of integer dividing by the world space size of a texel var diagonalLength = (m_frustumCornersWS[0] - m_frustumCornersWS[6]).Length(); //Make bigger box - ensure rotation and movement stabilization diagonalLength = MathHelper.GetNearestBiggerPowerOfTwo(diagonalLength); var worldsUnitsPerTexel = diagonalLength / (float)ShadowMapCascadeSize; Vector3D vBorderOffset = (new Vector3D(diagonalLength, diagonalLength, diagonalLength) - (maxes - mins)) * 0.5f; maxes += vBorderOffset; mins -= vBorderOffset; mins /= worldsUnitsPerTexel; mins.X = Math.Floor(mins.X); mins.Y = Math.Floor(mins.Y); mins.Z = Math.Floor(mins.Z); mins *= worldsUnitsPerTexel; maxes /= worldsUnitsPerTexel; maxes.X = Math.Floor(maxes.X); maxes.Y = Math.Floor(maxes.Y); maxes.Z = Math.Floor(maxes.Z); maxes *= worldsUnitsPerTexel; /* Matrix proj; Matrix.CreateOrthographicOffCenter(mins.X, maxes.X, mins.Y, maxes.Y, -maxes.Z - SHADOW_MAX_OFFSET, -mins.Z, out proj); if (MyUtils.IsEqual(lightCamera.ProjectionMatrix, proj)) { //cache return null; } */ // Update an orthographic camera for use as a shadow caster lightCamera.Update(mins.X, maxes.X, mins.Y, maxes.Y, -maxes.Z - SHADOW_MAX_OFFSET, -mins.Z); lightCamera.SetViewMatrix(ref viewMatrix); return lightCamera; }
/// <summary> /// Determines the size of the frustum needed to cover the viewable area, /// then creates an appropriate orthographic projection. /// </summary> /// <param name="light">The directional light to use</param> /// <param name="mainCamera">The camera viewing the scene</param> protected MyOrthographicCamera CalculateFrustum(MyOrthographicCamera lightCamera, MyPerspectiveCamera mainCamera, float minZ, float maxZ) { MatrixD cameraMatrix; mainCamera.GetWorldMatrix(out cameraMatrix); MatrixD cameraMatrixAtZero = cameraMatrix; cameraMatrixAtZero.Translation = Vector3D.Zero; for (int i = 0; i < 4; i++) { m_splitFrustumCornersVS[i] = m_frustumCornersVS[i + 4] * (minZ / mainCamera.FarClip); } for (int i = 4; i < 8; i++) { m_splitFrustumCornersVS[i] = m_frustumCornersVS[i] * (maxZ / mainCamera.FarClip); } Vector3D.Transform(m_splitFrustumCornersVS, ref cameraMatrix, m_frustumCornersWS); // Position the shadow-caster camera so that it's looking at the centroid, // and backed up in the direction of the sunlight Vector3 viewUp = Math.Abs(Vector3.UnitY.Dot(MyRender.Sun.Direction)) < 0.99f ? Vector3.UnitY : Vector3.UnitX; MatrixD viewMatrix = MatrixD.CreateLookAt(MyRenderCamera.Position - (MyRender.Sun.Direction * (float)mainCamera.FarClip), MyRenderCamera.Position, viewUp); // Determine the position of the frustum corners in light space Vector3D.Transform(m_frustumCornersWS, ref viewMatrix, m_frustumCornersLS); // Calculate an orthographic projection by sizing a bounding box // to the frustum coordinates in light space Vector3D mins = m_frustumCornersLS[0]; Vector3D maxes = m_frustumCornersLS[0]; for (int i = 0; i < 8; i++) { if (m_frustumCornersLS[i].X > maxes.X) { maxes.X = m_frustumCornersLS[i].X; } else if (m_frustumCornersLS[i].X < mins.X) { mins.X = m_frustumCornersLS[i].X; } if (m_frustumCornersLS[i].Y > maxes.Y) { maxes.Y = m_frustumCornersLS[i].Y; } else if (m_frustumCornersLS[i].Y < mins.Y) { mins.Y = m_frustumCornersLS[i].Y; } if (m_frustumCornersLS[i].Z > maxes.Z) { maxes.Z = m_frustumCornersLS[i].Z; } else if (m_frustumCornersLS[i].Z < mins.Z) { mins.Z = m_frustumCornersLS[i].Z; } } // Update an orthographic camera for collision detection lightCamera.UpdateUnscaled(mins.X, maxes.X, mins.Y, maxes.Y, -maxes.Z - SHADOW_MAX_OFFSET, -mins.Z); lightCamera.SetViewMatrixUnscaled(ref viewMatrix); // We snap the camera to 1 pixel increments so that moving the camera does not cause the shadows to jitter. // This is a matter of integer dividing by the world space size of a texel var diagonalLength = (m_frustumCornersWS[0] - m_frustumCornersWS[6]).Length(); //Make bigger box - ensure rotation and movement stabilization diagonalLength = MathHelper.GetNearestBiggerPowerOfTwo(diagonalLength); var worldsUnitsPerTexel = diagonalLength / (float)ShadowMapCascadeSize; Vector3D vBorderOffset = (new Vector3D(diagonalLength, diagonalLength, diagonalLength) - (maxes - mins)) * 0.5f; maxes += vBorderOffset; mins -= vBorderOffset; mins /= worldsUnitsPerTexel; mins.X = Math.Floor(mins.X); mins.Y = Math.Floor(mins.Y); mins.Z = Math.Floor(mins.Z); mins *= worldsUnitsPerTexel; maxes /= worldsUnitsPerTexel; maxes.X = Math.Floor(maxes.X); maxes.Y = Math.Floor(maxes.Y); maxes.Z = Math.Floor(maxes.Z); maxes *= worldsUnitsPerTexel; /* * Matrix proj; * Matrix.CreateOrthographicOffCenter(mins.X, maxes.X, mins.Y, maxes.Y, -maxes.Z - SHADOW_MAX_OFFSET, -mins.Z, out proj); * * if (MyUtils.IsEqual(lightCamera.ProjectionMatrix, proj)) * { //cache * return null; * } */ // Update an orthographic camera for use as a shadow caster lightCamera.Update(mins.X, maxes.X, mins.Y, maxes.Y, -maxes.Z - SHADOW_MAX_OFFSET, -mins.Z); lightCamera.SetViewMatrix(ref viewMatrix); return(lightCamera); }