/// <inheritdoc />
        public CameraInfoCache(ICameraInfo cameraInfo)
        {
            // raw

            // world space -> camera space
            MatrixView        = MatrixEx.LookAtRH(cameraInfo.Position.ToVector3D(), cameraInfo.Target.ToVector3D(), cameraInfo.UpVector);
            MatrixViewInverse = MatrixView.Inverse();

            // camera space -> clip space
            MatrixProjection        = cameraInfo.Projection.GetMatrixProjection();
            MatrixProjectionInverse = MatrixProjection.Inverse();

            // clip space -> screen space
            MatrixViewport        = MatrixEx.Viewport(cameraInfo.Viewport);
            MatrixViewportInverse = MatrixViewport.Inverse();

            // multiplicatives

            // world space -> camera space -> clip space
            MatrixViewProjection        = MatrixView * MatrixProjection;
            MatrixViewProjectionInverse = MatrixViewProjection.Inverse();

            // world space -> camera space -> clip space -> screen space
            MatrixViewProjectionViewport        = MatrixViewProjection * MatrixViewport;
            MatrixViewProjectionViewportInverse = MatrixViewProjectionViewport.Inverse();
        }
        private void DrawPolyline(IEnumerable <Point3D> points, Space space, Pen pen)
        {
            switch (space)
            {
            case Space.World:
                var t      = GetDeltaTime(new TimeSpan(0, 0, 0, 10));
                var angle  = t * Math.PI * 2;
                var radius = 2;

                // view matrix
                var cameraPosition = new Vector3D(Math.Sin(angle) * radius, Math.Cos(angle) * radius, 1);
                var cameraTarget   = new Vector3D(0, 0, 0);
                var cameraUpVector = new UnitVector3D(0, 0, 1);
                var matrixView     = MatrixEx.LookAtRH(cameraPosition, cameraTarget, cameraUpVector);

                // projection matrix
                var fovY        = Math.PI * 0.5;
                var aspectRatio = (double)BufferSize.Width / BufferSize.Height;
                var nearPlane   = 0.001;
                var farPlane    = 1000;
                // ReSharper disable once UnusedVariable
                var matrixPerspective = MatrixEx.PerspectiveFovRH(fovY, aspectRatio, nearPlane, farPlane);

                var fieldHeight = 3;
                var fieldWidth  = fieldHeight * aspectRatio;
                // ReSharper disable once UnusedVariable
                var matrixOrthographic = MatrixEx.OrthoRH(fieldWidth, fieldHeight, nearPlane, farPlane);

                var matrixProjection = matrixPerspective;

                // view space (NDC) to screen space matrix
                var matrixViewport = MatrixEx.Viewport(Viewport);

                DrawPolylineScreenSpace((matrixView * matrixProjection * matrixViewport).Transform(points), pen);
                break;

            case Space.View:
                DrawPolylineScreenSpace(MatrixEx.Viewport(Viewport).Transform(points), pen);
                break;

            case Space.Screen:
                DrawPolylineScreenSpace(points, pen);
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(space), space, null);
            }
        }