/// <summary> /// Renders the shadow map using the orthographic camera created in /// CalculateFrustum. /// </summary> protected void renderShadowMap(RenderPrimitives renderDelegate, int splitIndex) { // Set the viewport for the current split Viewport splitViewport = new Viewport(); splitViewport.MinZ = 0; splitViewport.MaxZ = 1; splitViewport.Width = ShadowMapSize; splitViewport.Height = ShadowMapSize; splitViewport.X = splitIndex * ShadowMapSize; splitViewport.Y = 0; context.Rasterizer.SetViewports(splitViewport); renderDelegate(lightCameras[splitIndex]); }
/// <summary> /// Renders a list of models to the shadow map, and returns a surface /// containing the shadow occlusion factor /// </summary> /// <param name="modelList">The list of models to render</param> /// <param name="depthTexture">Texture containing depth for the scene</param> /// <param name="light">The light for which the shadow is being calculated</param> /// <param name="mainCamera">The camera viewing the scene containing the light</param> /// <returns>The shadow occlusion texture</returns> public void UpdateShadowMap(RenderPrimitives renderDelegate, DirectionalLight light, ICamera mainCamera) { context.ClearDepthStencilView(shadowMapDsv, DepthStencilClearFlags.Depth, 1, 0); context.ClearState(); context.OutputMerger.SetTargets(shadowMapDsv); // Get corners of the main camera's bounding frustum Matrix cameraTransform, viewMatrix; viewMatrix = mainCamera.View; cameraTransform = Matrix.Invert(viewMatrix); BoundingFrustum frustum = new BoundingFrustum(mainCamera.ViewProjection); frustum.GetCorners(frustumCornersWS); Vector3.TransformCoordinate(frustumCornersWS, ref viewMatrix, frustumCornersVS); for (int i = 0; i < 4; i++) { farFrustumCornersVS[i] = frustumCornersVS[i + 4]; } // Calculate the cascade splits. We calculate these so that each successive // split is larger than the previous, giving the closest split the most amount // of shadow detail. float N = NumSplits; float near = mainCamera.NearClip, far = mainCamera.FarClip; splitDepths[0] = near; splitDepths[NumSplits] = far; const float splitConstant = 0.95f; for (int i = 1; i < splitDepths.Length - 1; i++) { splitDepths[i] = splitConstant * near * (float)Math.Pow(far / near, i / N) + (1.0f - splitConstant) * ((near + (i / N)) * (far - near)); } // Render our scene geometry to each split of the cascade for (int i = 0; i < NumSplits; i++) { float minZ = splitDepths[i]; float maxZ = splitDepths[i + 1]; lightCameras[i] = CalculateFrustum(light, mainCamera, minZ, maxZ); renderShadowMap(renderDelegate, i); } // We'll use these clip planes to determine which split a pixel belongs to for (int i = 0; i < NumSplits; i++) { lightClipPlanes[i].X = -splitDepths[i]; lightClipPlanes[i].Y = -splitDepths[i + 1]; lightViewProjectionMatrices[i] = lightCameras[i].ViewProjection; //lightProjectionMatrices[i] = lightCameras[i].Projection; //lightCameras[ i ].GetViewProjMatrix( out ); } }