Example #1
0
        internal void PreDraw(int swapchainIndex, Float3 sunDirection, float shadowDistance)
        {
            //Get the 'normal' scene projections for current camera and aspect
            CameraData sceneCameraData = CameraData.FromCamera(scene.Camera, swapchainAspect);

            //Rotation from world to 'sun' direction
            Float4x4 rotationMatrix = Float4x4.CreateRotationFromAxis(sunDirection, Float3.Forward);

            //Calculate a sphere in 'lightspace' that fits the frustum of the camera
            //using a sphere so that the size stays constant when the camera rotates, this avoids
            //the shimmering when the shadow map is resized all the time
            FloatSphere shadowSphere = GetShadowSphere(
                sceneCameraData.InverseViewProjectionMatrix,
                rotationMatrix.Invert(),
                shadowDistance);

            //Derive the projection values from the sphere
            Float3 shadowCenter   = shadowSphere.Center;
            float  radius         = shadowSphere.Radius.Round();
            float  shadowSize     = radius * 2f;
            float  shadowNearClip = -radius;
            float  shadowFarClip  = radius;

            //Calculate the matrices for the shadow projection
            Float4x4 cameraMatrix     = rotationMatrix * Float4x4.CreateTranslation(shadowCenter);
            Float4x4 viewMatrix       = cameraMatrix.Invert();
            Float4x4 projectionMatrix = Float4x4.CreateOrthographicProjection(
                shadowSize.XX(), shadowNearClip, shadowFarClip);
            Float4x4 viewProjectionMatrix = projectionMatrix * viewMatrix;

            //Calculate a rounding matrix to fix shadow 'shimmering' as objects constantly 'switch'
            //between pixels in the shadowmap
            float    targetHalfSize = targetSize / 2f;
            Float2   shadowOrigin   = viewProjectionMatrix.TransformPoint((0f, 0f, 0f)).XY *targetHalfSize;
            Float2   rounding       = (shadowOrigin.Round() - shadowOrigin) / targetHalfSize;
            Float4x4 roundingMat    = Float4x4.CreateTranslation(rounding.XY0);

            //Apply rounding
            projectionMatrix     = roundingMat * projectionMatrix;
            viewProjectionMatrix = roundingMat * viewProjectionMatrix;

            //Update shadow projection data in the buffer
            cameraBuffer.Write(new CameraData(
                                   cameraMatrix,
                                   viewMatrix,
                                   projectionMatrix,
                                   viewProjectionMatrix,
                                   viewProjectionMatrix.Invert(),
                                   shadowNearClip,
                                   shadowFarClip), offset: CameraData.SIZE * swapchainIndex);
        }