/// <summary> /// The rotate trackball. /// </summary> /// <param name="p1"> /// The previous mouse position. /// </param> /// <param name="p2"> /// The current mouse position. /// </param> /// <param name="rotateAround"> /// The point to rotate around. /// </param> private void RotateTrackball(Point p1, Point p2, Point3D rotateAround) { // http://viewport3d.com/trackball.htm // http://www.codeplex.com/3DTools/Thread/View.aspx?ThreadId=22310 var v1 = ProjectToTrackball(p1, this.Viewport.ActualWidth, this.Viewport.ActualHeight); var v2 = ProjectToTrackball(p2, this.Viewport.ActualWidth, this.Viewport.ActualHeight); // transform the trackball coordinates to view space var viewZ = this.Camera.LookDirection; var viewX = Vector3D.Cross(this.Camera.UpDirection, viewZ); var viewY = Vector3D.Cross(viewX, viewZ); viewX.Normalize(); viewY.Normalize(); viewZ.Normalize(); 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 = Vector3D.Cross(u1, u2); if (axis.LengthSquared() < 1e-8) { return; } var angle = u1.AngleBetween(u2); // Create the transform var delta = Quaternion.RotationAxis(axis, -(float)(angle * this.RotationSensitivity * 5)); var rotate = Matrix.RotationQuaternion(delta); // Find vectors relative to the rotate-around point var relativeTarget = rotateAround - this.Camera.Target; var relativePosition = rotateAround - this.Camera.Position; // Rotate the relative vectors var newRelativeTarget = Vector3D.Transform(relativeTarget, rotate).ToVector3(); var newRelativePosition = Vector3D.Transform(relativePosition, rotate).ToVector3(); var newUpDirection = Vector3D.Transform(this.Camera.UpDirection, rotate).ToVector3(); // Find new camera position var newTarget = rotateAround - newRelativeTarget; var newPosition = rotateAround - newRelativePosition; this.Camera.LookDirection = newTarget - newPosition; if (this.CameraMode == CameraMode.Inspect) { this.Camera.Position = newPosition; } this.Camera.UpDirection = newUpDirection; }
/// <summary> /// Rotate around three axes. /// </summary> /// <param name="p1"> /// The previous mouse position. /// </param> /// <param name="p2"> /// The current mouse position. /// </param> /// <param name="rotateAround"> /// The point to rotate around. /// </param> public void RotateTurnball(Point p1, Point p2, Point3D rotateAround) { this.InitTurnballRotationAxes(p1); Vector2 delta = p2.ToVector2() - p1.ToVector2(); var relativeTarget = rotateAround - this.Camera.Target; var relativePosition = rotateAround - this.Camera.Position; float d = -1f; if (this.CameraMode != CameraMode.Inspect) { d = 0.2f; } d *= (float)this.RotationSensitivity; var q1 = Quaternion.RotationAxis(this.rotationAxisX, (float)(d * delta.X / 180 * Math.PI)); var q2 = Quaternion.RotationAxis(this.rotationAxisY, (float)(d * delta.Y / 180 * Math.PI)); Quaternion q = q1 * q2; var m = Matrix.RotationQuaternion(q); var newLookDir = Vector3D.Transform(this.Camera.LookDirection, m).ToVector3(); var newUpDirection = Vector3D.Transform(this.Camera.UpDirection, m).ToVector3(); var newRelativeTarget = Vector3D.Transform(relativeTarget, m).ToVector3(); var newRelativePosition = Vector3D.Transform(relativePosition, m).ToVector3(); var newRightVector = Vector3D.Cross(newLookDir, newUpDirection); newRightVector.Normalize(); var modUpDir = Vector3D.Cross(newRightVector, newLookDir); modUpDir.Normalize(); if ((newUpDirection - modUpDir).Length() > 1e-8) { newUpDirection = modUpDir; } var newTarget = rotateAround - newRelativeTarget; var newPosition = rotateAround - newRelativePosition; var newLookDirection = newTarget - newPosition; this.Camera.LookDirection = newLookDirection; if (this.CameraMode == CameraMode.Inspect) { this.Camera.Position = newPosition; } this.Camera.UpDirection = newUpDirection; }
/// <summary> /// Rotate camera using 'Turntable' rotation. /// </summary> /// <param name="delta"> /// The relative change in position. /// </param> /// <param name="rotateAround"> /// The point to rotate around. /// </param> public void RotateTurntable(Vector2 delta, Point3D rotateAround) { var relativeTarget = rotateAround - this.Camera.Target; var relativePosition = rotateAround - this.Camera.Position; var up = this.ModelUpDirection; var dir = this.Camera.LookDirection; dir.Normalize(); var right = Vector3D.Cross(dir, this.Camera.UpDirection); right.Normalize(); var d = -0.5f; if (this.CameraMode != CameraMode.Inspect) { d *= -0.2f; } d *= (float)this.RotationSensitivity; var q1 = Quaternion.RotationAxis(up, (float)(d * delta.X / 180 * Math.PI)); var q2 = Quaternion.RotationAxis(right, (float)(d * delta.Y / 180 * Math.PI)); Quaternion q = q1 * q2; var m = Matrix.RotationQuaternion(q); var newUpDirection = Vector3D.Transform(this.Camera.UpDirection, m).ToVector3(); var newRelativeTarget = Vector3D.Transform(relativeTarget, m).ToVector3(); var newRelativePosition = Vector3D.Transform(relativePosition, m).ToVector3(); var newTarget = rotateAround - newRelativeTarget; var newPosition = rotateAround - newRelativePosition; this.Camera.LookDirection = newTarget - newPosition; if (this.CameraMode == CameraMode.Inspect) { this.Camera.Position = newPosition; } this.Camera.UpDirection = newUpDirection; }
private void ProcessLeftMouse(EButtonEvent buttonEvent) { if (buttonEvent == EButtonEvent.Pressed && m_controlledTransform != null) { if (IsHovered) { Plane axisPlane; if (m_activeAxisList.Count > 1) { Vector3 planeNormal = Vector3.Cross(m_activeAxisList[0], m_activeAxisList[1]); axisPlane = new Plane(m_gizmoLocation, planeNormal); } else { Vector3 planeNormal; if (Mode == EGizmoMode.Rotation) { // Rotation planeNormal = m_activeAxisList[0]; } else { //Translation / Scale Vector3 toCamera = m_frameViewInfo.ViewLocation - m_gizmoLocation; Vector3 planeTangent = Vector3.Cross(m_activeAxisList[0], toCamera); planeNormal = Vector3.Cross(m_activeAxisList[0], planeTangent); } axisPlane = new Plane(m_gizmoLocation, planeNormal); } World.ViewManager.GetViewInfo(out SSceneViewInfo viewInfo); Ray ray = CreateMouseRay(viewInfo); if (ray.Intersects(ref axisPlane, out Vector3 intersectionPoint)) { m_startLocation = intersectionPoint; switch (Mode) { case EGizmoMode.Translation: m_clickOffset = intersectionPoint - m_gizmoLocation; m_originalPosition = m_controlledTransform.WorldPosition; break; case EGizmoMode.Rotation: Vector3 toStart = m_startLocation - m_gizmoLocation; m_rotationDragAxis = Vector3.Cross(toStart, m_activeAxisList[0]); m_rotationDragAxis.Normalize(); m_originalRotation = m_controlledTransform.WorldRotation; break; case EGizmoMode.Scale: m_originalScale = m_controlledTransform.WorldScale; m_scaleAxis = Vector3.Zero; foreach (Vector3 axis in m_activeAxisList) { m_scaleAxis += Vector3.Transform(axis, Quaternion.Invert(m_controlledTransform.WorldRotation)); } m_scaleAxis.Normalize(); m_scaleSizeFactor = m_originalScale.Length(); break; default: throw new ArgumentOutOfRangeException(); } IsClicked = true; } } } else if (m_controlledTransform != null) { if (IsClicked) { switch (Mode) { case EGizmoMode.Translation: Vector3 newPosition = m_controlledTransform.WorldPosition; if (newPosition != m_originalPosition) { OnTranslationChanged?.Invoke(m_controlledTransform, m_originalPosition, newPosition); } break; case EGizmoMode.Rotation: Quaternion newRotation = m_controlledTransform.WorldRotation; if (newRotation != m_originalRotation) { OnRotationChanged?.Invoke(m_controlledTransform, m_originalRotation, newRotation); } break; case EGizmoMode.Scale: Vector3 newScale = m_controlledTransform.WorldScale; if (newScale != m_originalScale) { OnScaleChanged?.Invoke(m_controlledTransform, m_originalScale, newScale); } break; } } IsClicked = false; m_totalAngleDelta = 0.0f; m_totalScaleDelta = 0.0f; } }