/// <summary> /// Rotates the trackball. /// </summary> /// <param name="cameraMode">The camera mode.</param> /// <param name="p1">The p1.</param> /// <param name="p2">The p2.</param> /// <param name="rotateAround">The rotate around.</param> /// <param name="sensitivity">The sensitivity.</param> /// <param name="viewportWidth">Width of the viewport.</param> /// <param name="viewportHeight">Height of the viewport.</param> /// <param name="camera">The camera.</param> /// <param name="invertFactor">The invert factor. Right Handed System = 1; LeftHandedSystem = -1;</param> /// <param name="newPosition">The new position.</param> /// <param name="newLookDirection">The new look direction.</param> /// <param name="newUpDirection">The new up direction.</param> public static void RotateTrackball(CameraMode cameraMode, ref Vector2 p1, ref Vector2 p2, ref Vector3 rotateAround, float sensitivity, int viewportWidth, int viewportHeight, CameraCore camera, int invertFactor, out Vector3 newPosition, out Vector3 newLookDirection, out Vector3 newUpDirection) { // http://viewport3d.com/trackball.htm // http://www.codeplex.com/3DTools/Thread/View.aspx?ThreadId=22310 var v1 = ProjectToTrackball(p1, viewportWidth, viewportHeight); var v2 = ProjectToTrackball(p2, viewportWidth, viewportHeight); var cUP = Vector3.Normalize(camera.UpDirection); // transform the trackball coordinates to view space var viewZ = Vector3.Normalize(camera.LookDirection * invertFactor); var viewX = Vector3.Normalize(Vector3.Cross(cUP, viewZ)) * invertFactor; var viewY = Vector3.Cross(viewX, viewZ); var u1 = (viewZ * v1.Z) + (viewX * v1.X) + (viewY * v1.Y); var u2 = (viewZ * v2.Z) + (viewX * v2.X) + (viewY * v2.Y); // Could also use the Camera ViewMatrix // var vm = Viewport3DHelper.GetViewMatrix(this.ActualCamera); // vm.Invert(); // var ct = new MatrixTransform3D(vm); // var u1 = ct.Transform(v1); // var u2 = ct.Transform(v2); // Find the rotation axis and angle var axis = Vector3.Cross(u1, u2); if (axis.LengthSquared() < 1e-8) { newPosition = camera.Position; newLookDirection = camera.LookDirection; newUpDirection = camera.UpDirection; return; } var angle = VectorExtensions.AngleBetween(u1, u2); // Create the transform var rotate = Matrix.RotationAxis(Vector3.Normalize(axis), -angle * sensitivity * 5); // Find vectors relative to the rotate-around point var relativeTarget = rotateAround - camera.Target; var relativePosition = rotateAround - camera.Position; // Rotate the relative vectors var newRelativeTarget = Vector3.TransformCoordinate(relativeTarget, rotate); var newRelativePosition = Vector3.TransformCoordinate(relativePosition, rotate); newUpDirection = Vector3.TransformNormal(cUP, rotate); // Find new camera position var newTarget = rotateAround - newRelativeTarget; newPosition = rotateAround - newRelativePosition; newLookDirection = newTarget - newPosition; if (cameraMode != CameraMode.Inspect) { newPosition = camera.Position; } }