void SubscribeToEvents()
		{
			Engine.SubscribeToPostUpdate(args =>
				{
					if (vehicle == null)
						return;

					Node vehicleNode = vehicle.Node;

					// Physics update has completed. Position camera behind vehicle
					Quaternion dir = Quaternion.FromAxisAngle(Vector3.UnitY, vehicleNode.Rotation.YawAngle);
					dir = dir * Quaternion.FromAxisAngle(Vector3.UnitY, vehicle.Controls.Yaw);
					dir = dir * Quaternion.FromAxisAngle(Vector3.UnitX, vehicle.Controls.Pitch);

					Vector3 cameraTargetPos = vehicleNode.Position - (dir * new Vector3(0.0f, 0.0f, CameraDistance));
					Vector3 cameraStartPos = vehicleNode.Position;

					// Raycast camera against static objects (physics collision mask 2)
					// and move it closer to the vehicle if something in between
					Ray cameraRay = new Ray(cameraStartPos, cameraTargetPos - cameraStartPos);
					float cameraRayLength = (cameraTargetPos - cameraStartPos).Length;
					PhysicsRaycastResult result = new PhysicsRaycastResult();
					scene.GetComponent<PhysicsWorld>().RaycastSingle(ref result, cameraRay, cameraRayLength, 2);
					if (result.Body != null)
					{
						cameraTargetPos = cameraStartPos + cameraRay.Direction * (result.Distance - 0.5f);
					}

					CameraNode.Position = cameraTargetPos;
					CameraNode.Rotation = dir;
				});

			scene.GetComponent<PhysicsWorld>().SubscribeToPhysicsPreStep(args => vehicle?.FixedUpdate(args.TimeStep));
		}
        void HandlePostUpdate(PostUpdateEventArgs args)
        {
            if (character == null)
            {
                return;
            }

            Node characterNode = character.Node;

            // Get camera lookat dir from character yaw + pitch
            Quaternion rot = characterNode.Rotation;
            Quaternion dir = rot * Quaternion.FromAxisAngle(Vector3.UnitX, character.Controls.Pitch);

            // Turn head to camera pitch, but limit to avoid unnatural animation
            Node headNode = characterNode.GetChild("Bip01_Head", true);

            if (headNode != null)
            {
                float      limitPitch = MathHelper.Clamp(character.Controls.Pitch, -45.0f, 45.0f);
                Quaternion headDir    = rot * Quaternion.FromAxisAngle(new Vector3(1.0f, 0.0f, 0.0f), limitPitch);
                // This could be expanded to look at an arbitrary target, now just look at a point in front
                Vector3 headWorldTarget = headNode.WorldPosition + headDir * new Vector3(0.0f, 0.0f, 1.0f);
                headNode.LookAt(headWorldTarget, new Vector3(0.0f, 1.0f, 0.0f), TransformSpace.World);
                // Correct head orientation because LookAt assumes Z = forward, but the bone has been authored differently (Y = forward)
                headNode.Rotate(new Quaternion(0.0f, 90.0f, 90.0f), TransformSpace.Local);
            }
            if (firstPerson)
            {
                if (headNode != null)
                {
                    CameraNode.Position = headNode.WorldPosition + rot * new Vector3(0.0f, 0.15f, 0.2f);
                    CameraNode.Rotation = dir;
                }
            }
            else
            {
                // Third person camera: position behind the character
                Vector3 aimPoint = characterNode.Position + rot * new Vector3(0.0f, 1.7f, 0.0f);

                // Collide camera ray with static physics objects (layer bitmask 2) to ensure we see the character properly
                Vector3 rayDir      = dir * new Vector3(0f, 0f, -1f);
                float   rayDistance = touch != null ? touch.CameraDistance : CameraInitialDist;

                PhysicsRaycastResult result = new PhysicsRaycastResult();
                scene.GetComponent <PhysicsWorld>().RaycastSingle(ref result, new Ray(aimPoint, rayDir), rayDistance, 2);
                if (result.Body != null)
                {
                    rayDistance = Math.Min(rayDistance, result.Distance);
                }
                rayDistance = MathHelper.Clamp(rayDistance, CameraMinDist, CameraMaxDist);

                CameraNode.Position = aimPoint + rayDir * rayDistance;
                CameraNode.Rotation = dir;
            }
        }
        void SubscribeToEvents()
        {
            SubscribeToEvent <PostUpdateEvent>(e =>
            {
                if (vehicle == null)
                {
                    return;
                }

                Node vehicleNode = vehicle.Node;

                // Physics update has completed. Position camera behind vehicle
                Quaternion dir = Quaternion.FromAxisAngle(Vector3.UnitY, vehicleNode.Rotation.YawAngle);

                dir = dir * Quaternion.FromAxisAngle(Vector3.UnitY, vehicle.Controls.Yaw);
                dir = dir * Quaternion.FromAxisAngle(Vector3.UnitX, vehicle.Controls.Pitch);

                Vector3 cameraTargetPos = vehicleNode.Position - (dir * new Vector3(0.0f, 0.0f, CameraDistance));
                Vector3 cameraStartPos  = vehicleNode.Position;


                // and move it closer to the vehicle if something in between
                Ray cameraRay         = new Ray(cameraStartPos, cameraTargetPos - cameraStartPos);
                float cameraRayLength = (cameraTargetPos - cameraStartPos).Length;

                // Raycast camera against static objects (physics collision mask 2)
                var query = new RayOctreeQuery(cameraRay, RayQueryLevel.RAY_TRIANGLE, cameraRayLength, Constants.DRAWABLE_ANY, 2);

                PhysicsRaycastResult result = new PhysicsRaycastResult();

                scene.GetComponent <PhysicsWorld>().RaycastSingle(ref result, cameraRay, cameraRayLength, 2);
                if (result.Body != null)
                {
                    cameraTargetPos = cameraStartPos + cameraRay.Direction * (result.Distance - 0.5f);
                }

                CameraNode.Position = cameraTargetPos;
                CameraNode.Rotation = dir;
            });
        }
        void SubscribeToEvents()
        {
            Engine.PostUpdate += args =>
            {
                if (vehicle == null)
                {
                    return;
                }

                Node vehicleNode = vehicle.Node;

                // Physics update has completed. Position camera behind vehicle
                Quaternion dir = Quaternion.FromAxisAngle(Vector3.UnitY, vehicleNode.Rotation.YawAngle);
                dir *= Quaternion.FromAxisAngle(Vector3.UnitY, vehicle.Controls.Yaw);
                dir *= Quaternion.FromAxisAngle(Vector3.UnitX, vehicle.Controls.Pitch);

                Vector3 cameraTargetPos = vehicleNode.Position - (dir * new Vector3(0.0f, 0.0f, CameraDistance));
                Vector3 cameraStartPos  = vehicleNode.Position;

                // Raycast camera against static objects (physics collision mask 2)
                // and move it closer to the vehicle if something in between
                Ray   cameraRay             = new Ray(cameraStartPos, cameraTargetPos - cameraStartPos);
                float cameraRayLength       = (cameraTargetPos - cameraStartPos).Length;
                PhysicsRaycastResult result = new PhysicsRaycastResult();
                scene.GetComponent <PhysicsWorld>().RaycastSingle(ref result, cameraRay, cameraRayLength, 2);
                if (result.Body != null)
                {
                    cameraTargetPos = cameraStartPos + cameraRay.Direction * (result.Distance - 0.5f);
                }

                CameraNode.Position = cameraTargetPos;
                CameraNode.Rotation = dir;
            };

            scene.GetComponent <PhysicsWorld>().PhysicsPreStep += args => vehicle?.FixedUpdate(args.TimeStep);
        }
		void HandlePostUpdate(PostUpdateEventArgs args)
		{
			if (character == null)
				return;

			Node characterNode = character.Node;

			// Get camera lookat dir from character yaw + pitch
			Quaternion rot = characterNode.Rotation;
			Quaternion dir = rot * Quaternion.FromAxisAngle(Vector3.UnitX, character.Controls.Pitch);

			// Turn head to camera pitch, but limit to avoid unnatural animation
			Node headNode = characterNode.GetChild("Bip01_Head", true);
			float limitPitch = MathHelper.Clamp(character.Controls.Pitch, -45.0f, 45.0f);
			Quaternion headDir = rot * Quaternion.FromAxisAngle(new Vector3(1.0f, 0.0f, 0.0f), limitPitch);
			// This could be expanded to look at an arbitrary target, now just look at a point in front
			Vector3 headWorldTarget = headNode.WorldPosition + headDir * new Vector3(0.0f, 0.0f, 1.0f);
			headNode.LookAt(headWorldTarget, new Vector3(0.0f, 1.0f, 0.0f), TransformSpace.World);
			// Correct head orientation because LookAt assumes Z = forward, but the bone has been authored differently (Y = forward)
			headNode.Rotate(new Quaternion(0.0f, 90.0f, 90.0f), TransformSpace.Local);

			if (firstPerson)
			{
				CameraNode.Position = headNode.WorldPosition + rot * new Vector3(0.0f, 0.15f, 0.2f);
				CameraNode.Rotation = dir;
			}
			else
			{
				// Third person camera: position behind the character
				Vector3 aimPoint = characterNode.Position + rot * new Vector3(0.0f, 1.7f, 0.0f);

				// Collide camera ray with static physics objects (layer bitmask 2) to ensure we see the character properly
				Vector3 rayDir = dir * new Vector3(0f, 0f, -1f);
				float rayDistance = touch != null ? touch.CameraDistance : CameraInitialDist;

				PhysicsRaycastResult result = new PhysicsRaycastResult();
				scene.GetComponent<PhysicsWorld>().RaycastSingle(ref result, new Ray(aimPoint, rayDir), rayDistance, 2);
				if (result.Body != null)
					rayDistance = Math.Min(rayDistance, result.Distance);
				rayDistance = MathHelper.Clamp(rayDistance, CameraMinDist, CameraMaxDist);

				CameraNode.Position = aimPoint + rayDir * rayDistance;
				CameraNode.Rotation = dir;
			}
		}