public void GetShadowCamera(SceneManager sceneManager, Camera camera, Viewport viewport, Light light,
                                    Camera textureCamera, int iteration)
        {
            Vector3    pos, dir;
            Quaternion q;

            // reset custom view / projection matrix in case already set
            textureCamera.SetCustomViewMatrix(false);
            textureCamera.SetCustomProjectionMatrix(false);
            textureCamera.Near = light.DeriveShadowNearClipDistance(camera);
            textureCamera.Far  = light.DeriveShadowFarClipDistance(camera);


            // get the shadow frustum's far distance
            var shadowDist = light.ShadowFarDistance;

            if (shadowDist == 0.0f)
            {
                // need a shadow distance, make one up
                shadowDist = camera.Near * 300;
            }
            var shadowOffset = shadowDist * sceneManager.ShadowDirectionalLightTextureOffset;

            // Directional lights
            if (light.Type == LightType.Directional)
            {
                // set up the shadow texture
                // Set ortho projection
                textureCamera.ProjectionType = Projection.Orthographic;
                // set ortho window so that texture covers far dist
                textureCamera.SetOrthoWindow(shadowDist * 2, shadowDist * 2);

                // Calculate look at position
                // We want to look at a spot shadowOffset away from near plane
                // 0.5 is a litle too close for angles
                var target = camera.DerivedPosition + (camera.DerivedDirection * shadowOffset);

                // Calculate direction, which same as directional light direction
                dir = -light.DerivedDirection; // backwards since point down -z
                dir.Normalize();

                // Calculate position
                // We want to be in the -ve direction of the light direction
                // far enough to project for the dir light extrusion distance
                pos = target + dir * sceneManager.ShadowDirectionalLightExtrusionDistance;

                // Round local x/y position based on a world-space texel; this helps to reduce
                // jittering caused by the projection moving with the camera
                // Viewport is 2 * near clip distance across (90 degree fov)
                //~ Real worldTexelSize = (texCam->getNearClipDistance() * 20) / vp->getActualWidth();
                //~ pos.x -= fmod(pos.x, worldTexelSize);
                //~ pos.y -= fmod(pos.y, worldTexelSize);
                //~ pos.z -= fmod(pos.z, worldTexelSize);
                var worldTexelSize = (shadowDist * 2) / textureCamera.Viewport.ActualWidth;

                //get texCam orientation

                var up = Vector3.UnitY;
                // Check it's not coincident with dir
                if (Utility.Abs(up.Dot(dir)) >= 1.0f)
                {
                    // Use camera up
                    up = Vector3.UnitZ;
                }
                // cross twice to rederive, only direction is unaltered
                var left = dir.Cross(up);
                left.Normalize();
                up = dir.Cross(left);
                up.Normalize();
                // Derive quaternion from axes
                q = Quaternion.FromAxes(left, up, dir);

                //convert world space camera position into light space
                var lightSpacePos = q.Inverse() * pos;

                //snap to nearest texel
                lightSpacePos.x -= lightSpacePos.x % worldTexelSize; //fmod(lightSpacePos.x, worldTexelSize);
                lightSpacePos.y -= lightSpacePos.y % worldTexelSize; //fmod(lightSpacePos.y, worldTexelSize);

                //convert back to world space
                pos = q * lightSpacePos;
            }
            // Spotlight
            else if (light.Type == LightType.Spotlight)
            {
                // Set perspective projection
                textureCamera.ProjectionType = Projection.Perspective;
                // set FOV slightly larger than the spotlight range to ensure coverage
                var fovy = light.SpotlightOuterAngle * 1.2;

                // limit angle
                if (fovy.InDegrees > 175)
                {
                    fovy = (Degree)(175);
                }
                textureCamera.FieldOfView = fovy;

                // Calculate position, which same as spotlight position
                pos = light.GetDerivedPosition();

                // Calculate direction, which same as spotlight direction
                dir = -light.DerivedDirection; // backwards since point down -z
                dir.Normalize();
            }
            // Point light
            else
            {
                // Set perspective projection
                textureCamera.ProjectionType = Projection.Perspective;
                // Use 120 degree FOV for point light to ensure coverage more area
                textureCamera.FieldOfView = 120.0f;

                // Calculate look at position
                // We want to look at a spot shadowOffset away from near plane
                // 0.5 is a litle too close for angles
                var target = camera.DerivedPosition + (camera.DerivedDirection * shadowOffset);

                // Calculate position, which same as point light position
                pos = light.GetDerivedPosition();

                dir = (pos - target); // backwards since point down -z
                dir.Normalize();
            }

            // Finally set position
            textureCamera.Position = pos;

            // Calculate orientation based on direction calculated above

            /*
             * // Next section (camera oriented shadow map) abandoned
             * // Always point in the same direction, if we don't do this then
             * // we get 'shadow swimming' as camera rotates
             * // As it is, we get swimming on moving but this is less noticeable
             *
             * // calculate up vector, we want it aligned with cam direction
             * Vector3 up = cam->getDerivedDirection();
             * // Check it's not coincident with dir
             * if (up.dotProduct(dir) >= 1.0f)
             * {
             * // Use camera up
             * up = cam->getUp();
             * }
             */
            var up2 = Vector3.UnitY;

            // Check it's not coincident with dir
            if (Utility.Abs(up2.Dot(dir)) >= 1.0f)
            {
                // Use camera up
                up2 = Vector3.UnitZ;
            }

            // cross twice to rederive, only direction is unaltered
            var left2 = dir.Cross(up2);

            left2.Normalize();
            up2 = dir.Cross(left2);
            up2.Normalize();

            // Derive quaternion from axes
            q = Quaternion.FromAxes(left2, up2, dir);
            textureCamera.Orientation = q;
        }
		public void GetShadowCamera( SceneManager sceneManager, Camera camera, Viewport viewport, Light light,
		                             Camera textureCamera, int iteration )
		{
			Vector3 pos, dir;
			Quaternion q;

			// reset custom view / projection matrix in case already set
			textureCamera.SetCustomViewMatrix( false );
			textureCamera.SetCustomProjectionMatrix( false );
			textureCamera.Near = light.DeriveShadowNearClipDistance( camera );
			textureCamera.Far = light.DeriveShadowFarClipDistance( camera );


			// get the shadow frustum's far distance
			var shadowDist = light.ShadowFarDistance;
			if ( shadowDist == 0.0f )
			{
				// need a shadow distance, make one up
				shadowDist = camera.Near*300;
			}
			var shadowOffset = shadowDist*sceneManager.ShadowDirectionalLightTextureOffset;

			// Directional lights
			if ( light.Type == LightType.Directional )
			{
				// set up the shadow texture
				// Set ortho projection
				textureCamera.ProjectionType = Projection.Orthographic;
				// set ortho window so that texture covers far dist
				textureCamera.SetOrthoWindow( shadowDist*2, shadowDist*2 );

				// Calculate look at position
				// We want to look at a spot shadowOffset away from near plane
				// 0.5 is a litle too close for angles
				var target = camera.DerivedPosition + ( camera.DerivedDirection*shadowOffset );

				// Calculate direction, which same as directional light direction
				dir = -light.DerivedDirection; // backwards since point down -z
				dir.Normalize();

				// Calculate position
				// We want to be in the -ve direction of the light direction
				// far enough to project for the dir light extrusion distance
				pos = target + dir*sceneManager.ShadowDirectionalLightExtrusionDistance;

				// Round local x/y position based on a world-space texel; this helps to reduce
				// jittering caused by the projection moving with the camera
				// Viewport is 2 * near clip distance across (90 degree fov)
				//~ Real worldTexelSize = (texCam->getNearClipDistance() * 20) / vp->getActualWidth();
				//~ pos.x -= fmod(pos.x, worldTexelSize);
				//~ pos.y -= fmod(pos.y, worldTexelSize);
				//~ pos.z -= fmod(pos.z, worldTexelSize);
				var worldTexelSize = ( shadowDist*2 )/textureCamera.Viewport.ActualWidth;

				//get texCam orientation

				var up = Vector3.UnitY;
				// Check it's not coincident with dir
				if ( Utility.Abs( up.Dot( dir ) ) >= 1.0f )
				{
					// Use camera up
					up = Vector3.UnitZ;
				}
				// cross twice to rederive, only direction is unaltered
				var left = dir.Cross( up );
				left.Normalize();
				up = dir.Cross( left );
				up.Normalize();
				// Derive quaternion from axes
				q = Quaternion.FromAxes( left, up, dir );

				//convert world space camera position into light space
				var lightSpacePos = q.Inverse()*pos;

				//snap to nearest texel
				lightSpacePos.x -= lightSpacePos.x%worldTexelSize; //fmod(lightSpacePos.x, worldTexelSize);
				lightSpacePos.y -= lightSpacePos.y%worldTexelSize; //fmod(lightSpacePos.y, worldTexelSize);

				//convert back to world space
				pos = q*lightSpacePos;
			}
				// Spotlight
			else if ( light.Type == LightType.Spotlight )
			{
				// Set perspective projection
				textureCamera.ProjectionType = Projection.Perspective;
				// set FOV slightly larger than the spotlight range to ensure coverage
				var fovy = light.SpotlightOuterAngle*1.2;

				// limit angle
				if ( fovy.InDegrees > 175 )
				{
					fovy = (Degree)( 175 );
				}
				textureCamera.FieldOfView = fovy;

				// Calculate position, which same as spotlight position
				pos = light.GetDerivedPosition();

				// Calculate direction, which same as spotlight direction
				dir = -light.DerivedDirection; // backwards since point down -z
				dir.Normalize();
			}
				// Point light
			else
			{
				// Set perspective projection
				textureCamera.ProjectionType = Projection.Perspective;
				// Use 120 degree FOV for point light to ensure coverage more area
				textureCamera.FieldOfView = 120.0f;

				// Calculate look at position
				// We want to look at a spot shadowOffset away from near plane
				// 0.5 is a litle too close for angles
				var target = camera.DerivedPosition + ( camera.DerivedDirection*shadowOffset );

				// Calculate position, which same as point light position
				pos = light.GetDerivedPosition();

				dir = ( pos - target ); // backwards since point down -z
				dir.Normalize();
			}

			// Finally set position
			textureCamera.Position = pos;

			// Calculate orientation based on direction calculated above
			/*
            // Next section (camera oriented shadow map) abandoned
            // Always point in the same direction, if we don't do this then
            // we get 'shadow swimming' as camera rotates
            // As it is, we get swimming on moving but this is less noticeable

            // calculate up vector, we want it aligned with cam direction
            Vector3 up = cam->getDerivedDirection();
            // Check it's not coincident with dir
            if (up.dotProduct(dir) >= 1.0f)
            {
            // Use camera up
            up = cam->getUp();
            }
            */
			var up2 = Vector3.UnitY;

			// Check it's not coincident with dir
			if ( Utility.Abs( up2.Dot( dir ) ) >= 1.0f )
			{
				// Use camera up
				up2 = Vector3.UnitZ;
			}

			// cross twice to rederive, only direction is unaltered
			var left2 = dir.Cross( up2 );
			left2.Normalize();
			up2 = dir.Cross( left2 );
			up2.Normalize();

			// Derive quaternion from axes
			q = Quaternion.FromAxes( left2, up2, dir );
			textureCamera.Orientation = q;
		}