View of /trunk/DefaultRenderer/Trackball3D.cs
Parent Directory
|
Revision Log
Revision 12 -
(download)
(annotate)
Wed Aug 27 02:26:39 2008 UTC (4 years, 8 months ago) by albert
File size: 13353 byte(s)
Wed Aug 27 02:26:39 2008 UTC (4 years, 8 months ago) by albert
File size: 13353 byte(s)
//------------------------------------------------------------------ // // 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 { /// <summary> /// Trackball is a utility class which observes the mouse events /// on a specified FrameworkElement and produces a Transform3D /// with the resultant rotation and scale. /// /// Example Usage: /// /// Trackball trackball = new Trackball(); /// trackball.EventSource = myElement; /// myViewport3D.Camera.Transform = trackball.Transform; /// /// Because Viewport3Ds only raise events when the mouse is over the /// rendered 3D geometry (as opposed to not when the mouse is within /// the layout bounds) you usually want to use another element as /// your EventSource. For example, a transparent border placed on /// top of your Viewport3D works well: /// /// <Grid> /// <ColumnDefinition /> /// <RowDefinition /> /// <Viewport3D Name="myViewport" ClipToBounds="True" Grid.Row="0" Grid.Column="0" /> /// <Border Name="myElement" Background="Transparent" Grid.Row="0" Grid.Column="0" /> /// </Grid> /// /// NOTE: The Transform property may be shared by multiple Cameras /// if you want to have auxilary views following the trackball. /// /// It can also be useful to share the Transform property with /// models in the scene that you want to move with the camera. /// (For example, the Trackport3D's headlight is implemented /// this way.) /// /// You may also use a Transform3DGroup to combine the /// Transform property with additional Transforms. /// </summary> public class Trackball { 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(); bool isTracking=false; public Trackball(PerspectiveCamera camera) { _camera = camera; _rotationTransform.Rotation = _rotation; _transform = new Transform3DGroup(); _transform.Children.Add(_scale); _transform.Children.Add(_rotationTransform); _transform.Children.Add(_translate); } /// <summary> /// A transform to move the camera or scene to the trackball's /// current orientation and scale. /// </summary> public Transform3D Transform { get { return _transform; } } #region Event Handling /// <summary> /// The FrameworkElement we listen to for mouse events. /// </summary> public FrameworkElement EventSource { get { return _eventSource; } set { if (_eventSource != null) { _eventSource.MouseDown -= this.OnMouseDown; _eventSource.MouseUp -= this.OnMouseUp; _eventSource.MouseMove -= this.OnMouseMove; _eventSource.KeyDown -= this.OnKeyDown; } _eventSource = value; _eventSource.MouseDown += this.OnMouseDown; _eventSource.MouseUp += this.OnMouseUp; _eventSource.MouseMove += this.OnMouseMove; _eventSource.KeyDown += OnKeyDown; } } //this need be replaced by button clicks. private void OnKeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Left) _translate.OffsetX = -1; else if (e.Key == Key.Right) _translate.OffsetX = 1; else if (e.Key == Key.Up) _translate.OffsetY = 1; else if (e.Key == Key.Down) _translate.OffsetY = -1; } //need add Petzold.Media3D copyright here. private void OnMouseDown(object sender, MouseEventArgs 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; //_cameraLookPoint = new Point3D(visul3d.Content.Bounds.X, visul3d.Content.Bounds.Y, visul3d.Content.Bounds.Z); TranslateTransform3D tempTranslate = visul3d.Transform as TranslateTransform3D; if (tempTranslate == null) return; Petzold.Media3D.LineRange line; Petzold.Media3D.ViewportInfo.Point2DtoPoint3D(_eventSource as Viewport3D, pclick, out line); _cameraLookPoint = line.PointFromZ(tempTranslate.OffsetZ); _rotationTransform.CenterX = _cameraLookPoint.X; _rotationTransform.CenterY = _cameraLookPoint.Y; _rotationTransform.CenterZ = _cameraLookPoint.Z; _camera.LookDirection = _cameraLookDirection = Point3D.Subtract(_cameraLookPoint, _camera.Position); isTracking = true; _eventSource.CaptureMouse(); _eventSource.Focus(); e.Handled = true; } private void OnMouseUp(object sender, MouseEventArgs e) { // Mouse.Capture(EventSource, CaptureMode.None); isTracking = false; _rotation.Angle = 0; _eventSource.ReleaseMouseCapture(); string mmm = mm; mm = ""; } private void OnMouseMove(object sender, MouseEventArgs e) { Point currentPosition = e.GetPosition(EventSource); if (e.LeftButton == MouseButtonState.Pressed && (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))) { //Look(currentPosition); } else if (e.LeftButton == MouseButtonState.Pressed && (Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt))) { if (isTracking) { Focus(currentPosition); //AxisRotation(currentPosition); } } else if (e.LeftButton == MouseButtonState.Pressed) { // Pan(currentPosition); } else if (e.RightButton == MouseButtonState.Pressed) { // Zoom(currentPosition); } _previousPosition2D = currentPosition; } #endregion Event Handling private void Look(Point currentPosition) { Vector3D currentPosition3D = ProjectToTrackball( EventSource.ActualWidth, EventSource.ActualHeight, currentPosition); Vector3D axis = Vector3D.CrossProduct(_previousPosition3D, currentPosition3D); double angle = Vector3D.AngleBetween(_previousPosition3D, currentPosition3D); Quaternion delta = new Quaternion(axis, -angle); // Get the current orientantion from the RotateTransform3D AxisAngleRotation3D r = _rotation; Quaternion q = new Quaternion(_rotation.Axis, _rotation.Angle); // Compose the delta with the previous orientation q *= delta; // Write the new orientation back to the Rotation3D _rotation.Axis = q.Axis; _rotation.Angle = q.Angle; _previousPosition3D = currentPosition3D; } private void Pan(Point currentPosition) { Vector3D currentPosition3D = ProjectToTrackball( EventSource.ActualWidth, EventSource.ActualHeight, currentPosition); Vector change = Point.Subtract(_previousPosition2D, currentPosition); Vector3D changeVector = new Vector3D(change.X, change.Y, 0); _translate.OffsetX += changeVector.X * .104; _translate.OffsetY -= changeVector.Y * .104; _translate.OffsetZ += changeVector.Z * .104; _previousPosition3D = currentPosition3D; } private Vector3D ProjectToTrackball(double width, double height, Point point) { double x = point.X / (width / 2); // Scale so bounds map to [0,0] - [2,2] double y = point.Y / (height / 2); x = x - 1; // Translate 0,0 to the center y = 1 - y; // Flip so +Y is up instead of down double z2 = 1 - x * x - y * y; // z^2 = 1 - x^2 - y^2 double z = z2 > 0 ? Math.Sqrt(z2) : 0; return new Vector3D(x, y, z); } private void Zoom(Point currentPosition) { double yDelta = currentPosition.Y - _previousPosition2D.Y; double scale = Math.Exp(yDelta / 100); // e^(yDelta/100) is fairly arbitrary. _scale.ScaleX *= scale; _scale.ScaleY *= scale; _scale.ScaleZ *= scale; } private void Focus(Point currentPosition) { //about zoom: //set the camera to lookat the position of mouse clicked //Move the camera along the camera's looking direction TO zoom in/out //rotate around with the axix z and center is the position of mouse clicked. double yDelta = currentPosition.Y - _previousPosition2D.Y; double scale = yDelta / 100; double distance = Point3D.Subtract(_cameraLookPoint, _camera.Position).Length; //distance = (_cameraLookPoint.X - _camera.Position.X) * (_cameraLookPoint.X - _camera.Position.X) + // (_cameraLookPoint.Y - _camera.Position.Y) * (_cameraLookPoint.Y - _camera.Position.Y) // + (_cameraLookPoint.Z - _camera.Position.Z) * (_cameraLookPoint.Z - _camera.Position.Z); //if (distance >= 1024 * 1024 || distance <= 10) //{ // isTracking = false; // return; //} //_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.Position = Point3D.Add(_camera.Position, new Vector3D(scale * _cameraLookDirection.X,scale * _cameraLookDirection.Y,scale * _cameraLookDirection.Z));// -= //rotation double xDelta = currentPosition.X - _previousPosition2D.X; _rotationTransform.CenterX = _cameraLookPoint.X; _rotationTransform.CenterY = _cameraLookPoint.Y; _rotationTransform.CenterZ = _cameraLookPoint.Z; _rotation.Axis = new Vector3D(0, 0, 1); _rotation.Angle += xDelta; // _cameraLookDirection = Point3D.Subtract(_cameraLookPoint, _camera.Position); } string mm = ""; //private void AxisRotation(Point currentPosition) //{ // //rotation // double xDelta = currentPosition.X - _previousPosition2D.X; // if (xDelta == 0) // return; // _rotation.Axis = new Vector3D(0, 0, 1); // _rotation.Angle += xDelta; // // _previousPosition2D = currentPosition; // // mm += _camera.LookDirection.ToString(); //} } }
| ViewVC Help | |
| Powered by ViewVC 1.0.0 |

