/// <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; if (MyRenderConstants.RenderQualityProfile.ForwardRender) { MultiThreaded = false; } }
/// <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) { // Shorten the view frustum according to the shadow view distance Matrix cameraMatrix; mainCamera.GetWorldMatrix(out cameraMatrix); Matrix.CreatePerspectiveFieldOfView(mainCamera.FieldOfView, mainCamera.AspectRatio, minZ, maxZ, out lightCamera.CameraSubfrustum); Matrix wma; mainCamera.GetViewMatrix(out wma); lightCamera.CameraSubfrustum = MyCamera.ViewMatrix * lightCamera.CameraSubfrustum; 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); } Vector3.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 //Toto se nemeni per frame! Matrix viewMatrix = Matrix.CreateLookAt(Vector3.Zero - (m_sunLightDirection * mainCamera.FarClip), Vector3.Zero, new Vector3(0, 1, 0)); // Determine the position of the frustum corners in light space Vector3.Transform(m_frustumCornersWS, ref viewMatrix, m_frustumCornersLS); // Calculate an orthographic projection by sizing a bounding box // to the frustum coordinates in light space Vector3 mins = m_frustumCornersLS[0]; Vector3 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 float diagonalLength = (m_frustumCornersWS[0] - m_frustumCornersWS[6]).Length(); //Make bigger box - ensure rotation and movement stabilization diagonalLength = MyMath.GetNearestBiggerPowerOfTwo(diagonalLength); float worldsUnitsPerTexel = diagonalLength / (float)ShadowMapCascadeSize; Vector3 vBorderOffset = (new Vector3(diagonalLength, diagonalLength, diagonalLength) - (maxes - mins)) * 0.5f; maxes += vBorderOffset; mins -= vBorderOffset; mins /= worldsUnitsPerTexel; mins.X = (float)Math.Floor(mins.X); mins.Y = (float)Math.Floor(mins.Y); mins.Z = (float)Math.Floor(mins.Z); mins *= worldsUnitsPerTexel; maxes /= worldsUnitsPerTexel; maxes.X = (float)Math.Floor(maxes.X); maxes.Y = (float)Math.Floor(maxes.Y); maxes.Z = (float)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); }