//------------------------------------------------------------------ // // The following article discusses the mechanics behind this // trackball implementation: http://viewport3d.com/trackball.htm // // Reading the article is not required to use this sample code, // but skimming it might be useful. // // For licensing information and to get the latest version go to: // http://workspaces.gotdotnet.com/3dtools // //------------------------------------------------------------------ using System; using System.Windows; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Media3D; using System.Windows.Controls; using Petzold.Media3D; namespace Xenki.DefaultRenderer { public class CameraControl { private FrameworkElement _eventSource; private Point _previousPosition2D; private Vector3D _previousPosition3D = new Vector3D(0, 0, 1); private Transform3DGroup _transform; private ScaleTransform3D _scale = new ScaleTransform3D(); private AxisAngleRotation3D _rotation = new AxisAngleRotation3D(); private TranslateTransform3D _translate = new TranslateTransform3D(); private Vector3D _cameraLookDirection = new Vector3D(128, 128, 10); private PerspectiveCamera _camera; private Point3D _cameraLookPoint; private RotateTransform3D _rotationTransform = new RotateTransform3D(); ModelVisual3D clickedVisual; private TranslateTransform3D _clickedTranslate = new TranslateTransform3D(); bool isTracking = false; public CameraControl(PerspectiveCamera camera) { _camera = camera; _rotationTransform.Rotation = _rotation; _transform = new Transform3DGroup(); //_transform.Children.Add(_translate); _transform.Children.Add(_rotationTransform); // _transform.Children.Add(_scale); } /// /// A transform to move the camera or scene to the trackball's /// current orientation and scale. /// public Transform3DGroup Transform { get { return _transform; } } #region Event Handling /// /// The FrameworkElement we listen to for mouse events. /// public FrameworkElement EventSource { get { return _eventSource; } set { if (_eventSource != null) { _eventSource.MouseWheel -= _eventSource_MouseWheel; _eventSource.MouseUp -= this.OnMouseUp; _eventSource.MouseMove -= this.OnMouseMove; _eventSource.MouseLeftButtonDown -= _eventSource_MouseLeftButtonDown; } _eventSource = value; _eventSource.MouseWheel += _eventSource_MouseWheel; _eventSource.MouseLeftButtonDown += new MouseButtonEventHandler(_eventSource_MouseLeftButtonDown); _eventSource.MouseUp += this.OnMouseUp; _eventSource.MouseMove += this.OnMouseMove; } } void _eventSource_MouseWheel(object sender, MouseWheelEventArgs e) { double scale = e.Delta / 1200.00; double distance = Point3D.Subtract(_cameraLookPoint, _camera.Position).Length; if (distance > 1024 || distance <= 0.5) { if (touch == false) { touch = true; } } else { touch = false; } if (touch == true) scale = -scale; _camera.Position = new Point3D(_camera.Position.X - scale * _cameraLookDirection.X, _camera.Position.Y - scale * _cameraLookDirection.Y, _camera.Position.Z - scale * _cameraLookDirection.Z); _camera.LookDirection = Point3D.Subtract(_cameraLookPoint, _camera.Position); } void _eventSource_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Mouse.Capture(EventSource, CaptureMode.Element); Point pclick = e.GetPosition(EventSource); HitTestResult hitresult = VisualTreeHelper.HitTest(EventSource, pclick); RayMeshGeometry3DHitTestResult result3d = hitresult as RayMeshGeometry3DHitTestResult; if (result3d == null) return; ModelVisual3D visul3d = result3d.VisualHit as ModelVisual3D; if (visul3d == null) return; _clickedTranslate = visul3d.Transform as TranslateTransform3D; if (_clickedTranslate == null) return; clickedVisual = visul3d; clickedVisual.Transform = _clickedTranslate; Petzold.Media3D.LineRange line; Petzold.Media3D.ViewportInfo.Point2DtoPoint3D(_eventSource as Viewport3D, pclick, out line); _cameraLookPoint = line.PointFromY(visul3d.Content.Bounds.Y); _rotationTransform.CenterX = _cameraLookPoint.X; _rotationTransform.CenterY = _cameraLookPoint.Y; _rotationTransform.CenterZ = _cameraLookPoint.Z; _cameraLookDirection = Point3D.Subtract(_cameraLookPoint, _camera.Position); _camera.LookDirection = _cameraLookDirection; isTracking = true; _eventSource.CaptureMouse(); _eventSource.Focus(); e.Handled = true; } private void OnMouseUp(object sender, MouseEventArgs e) { Mouse.Capture(EventSource, CaptureMode.None); isTracking = false; _eventSource.ReleaseMouseCapture(); _eventSource.Cursor = Cursors.Arrow; string mmm = mm; } private void OnMouseMove(object sender, MouseEventArgs e) { Point currentPosition = e.GetPosition(EventSource); if (e.RightButton == MouseButtonState.Pressed && (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))) { LookUpDown(currentPosition); } else if (e.LeftButton == MouseButtonState.Pressed && (Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt))) { if (isTracking) { _eventSource.Cursor = Cursors.None; Focus(currentPosition); } } else if (e.RightButton == MouseButtonState.Pressed && Keyboard.IsKeyDown(Key.Q)) { CameraPanUP(currentPosition); } else if (e.LeftButton == MouseButtonState.Pressed && (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))) { PanObject(currentPosition); } _previousPosition2D = currentPosition; } private void PanObject(Point currentPosition) { double scale = currentPosition.Y - _previousPosition2D.Y; scale = scale / 5; LineRange range; ViewportInfo.Point2DtoPoint3D(_eventSource as Viewport3D, currentPosition, out range); Point3D pointNew = range.PointFromZ(clickedVisual.Content.Bounds.X); //Vector3D v = pointNew- new Point3D(clickedVisual.Content.Bounds.X,clickedVisual.Content.Bounds.Y,clickedVisual.Content.Bounds.Z); Vector3D vectMouse = pointNew - _cameraLookPoint; _clickedTranslate.OffsetX = _clickedTranslate.OffsetX + vectMouse.X; _clickedTranslate.OffsetY = _clickedTranslate.OffsetY + vectMouse.Y; _clickedTranslate.OffsetZ = _clickedTranslate.OffsetZ + vectMouse.Z; //_camera.LookDirection = new Vector3D(_camera.LookDirection.X, _camera.LookDirection.Y, _camera.LookDirection.Z + scale); } #endregion Event Handling private void LookUpDown(Point currentPosition) { double scale = currentPosition.Y- _previousPosition2D.Y; scale = scale/5; _camera.LookDirection = new Vector3D(_camera.LookDirection.X, _camera.LookDirection.Y, _camera.LookDirection.Z + scale); } string mm = ""; bool touch = false; private void Focus(Point currentPosition) { double yDelta = currentPosition.Y - _previousPosition2D.Y; double scale = yDelta / 100; //Maybe this part need replaced by collision detection method double distance = Point3D.Subtract(_cameraLookPoint, _camera.Position).Length; if (distance > 1024 || distance <= 0.5) { if (touch == false) touch = true; } else { touch = false; } if (touch == true) scale = -scale; _camera.Position = new Point3D(_camera.Position.X - scale * _cameraLookDirection.X, _camera.Position.Y - scale * _cameraLookDirection.Y, _camera.Position.Z - scale * _cameraLookDirection.Z); //_translate.OffsetX -= scale * _cameraLookDirection.X;// _camera.LookDirection.X; //_translate.OffsetY -= scale * _cameraLookDirection.Y;//_camera.LookDirection.Y; //_translate.OffsetZ -= scale * _cameraLookDirection.Z;//_camera.LookDirection.Z; _camera.LookDirection = Point3D.Subtract(_cameraLookPoint, _camera.Position); double axisAngle = currentPosition.X - _previousPosition2D.X; double angletimes = axisAngle; if (angletimes > 360 || angletimes < -360) angletimes = 0; if (angletimes + _rotation.Angle >= 360) _rotation.Angle = 0; _rotation.Axis = new Vector3D(0, 0, 1); _rotation.Angle += axisAngle; } public HitTestResultBehavior HitTestCallback(HitTestResult result) { if (result.VisualHit != null) { return HitTestResultBehavior.Stop; } return HitTestResultBehavior.Continue; } private void CameraPanUP(Point currentPosition) { double yDelta = currentPosition.Y - _previousPosition2D.Y; double xDelta = currentPosition.X - _previousPosition2D.X; double scale = yDelta / 10; _camera.Position = new Point3D(_camera.Position.X, _camera.Position.Y, _camera.Position.Z + scale); } } }