View of /trunk/DefaultRenderer/CameraControl.cs
Parent Directory
|
Revision Log
Revision 83 -
(download)
(annotate)
Mon Dec 8 10:48:48 2008 UTC (4 years, 5 months ago) by albert
File size: 23680 byte(s)
Mon Dec 8 10:48:48 2008 UTC (4 years, 5 months ago) by albert
File size: 23680 byte(s)
not stable(can't load prims)
//------------------------------------------------------------------ // // 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; using _3DTools; using Xenki.Framework; using System.Collections.Generic; using OpenMetaverse; using Quaternion = System.Windows.Media.Media3D.Quaternion; namespace Xenki.DefaultRenderer { public delegate void CamPositionChanged(Point3D oldpos,Point3D newpos); public class CameraControl { private FrameworkElement _eventSource; private Point _previousPosition2D; private Vector3D _previousPosition3D = new Vector3D(0, 0, 1); public event CamPositionChanged OnCameraPositionChanged; private PerspectiveCamera _camera; private Point3D _cameraLookPoint; ModelVisual3D visul3d; Point3D _clickedCenterPosition; DefaultAvatarManager avatarManager = DefaultAvatarManager.SingletonInstance(); HotkeyDispatcher KeyDispatcher = HotkeyDispatcher.GetInstance(); DefaultPrimControl m_primitiveData; bool isTracking = false; bool isPanningObject = false; [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "SetCursorPos")] [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] public static extern bool SetCursorPos(int X, int Y); /// <summary> /// The FrameworkElement we listen to for mouse events. /// </summary> public FrameworkElement EventSource { get { return _eventSource; } set { _eventSource = value; } } public CameraControl(PerspectiveCamera camera, DefaultPrimControl datacontrol) { //dataControl = DefaultNetwork.DefaultNetwork.m_primitiveData; _camera = camera; m_primitiveData = datacontrol; avatarManager.OnAvatarPosChanged += new AvatarPositionChanged(avatarManager_OnAvatarPosChanged); avatarManager.OnAvatarTrunAround += new AvatarTurnAround(avatarManager_OnAvatarTrunAround); KeyDispatcher.OnMouseLeftDown += new MouseLeftDown(KeyDispatcher_OnMouseLeftDown); KeyDispatcher.OnMouseMove += new MouseMove(KeyDispatcher_OnMouseMove); KeyDispatcher.OnMouseRightDown += new MouseRightDown(KeyDispatcher_OnMouseRightDown); KeyDispatcher.OnMouseWheel += new MouseWheel(KeyDispatcher_OnMouseWheel); KeyDispatcher.OnMouseUp += new MouseUp(KeyDispatcher_OnMouseUp); } void KeyDispatcher_OnMouseUp(XMouseEventArgs arg) { //set the mouse to the original position when clicked the object. if (_eventSource.Cursor != Cursors.Arrow) { SetCursorPos((int)originalMouseClickPos.X, (int)originalMouseClickPos.Y); _eventSource.Cursor = Cursors.Arrow; } Mouse.Capture(EventSource, CaptureMode.None); isTracking = false; if (isPanningObject == true) { isPanningObject = false; _cameraLookPoint = GetObjectCenterPosition(visul3d); } _eventSource.ReleaseMouseCapture(); } void KeyDispatcher_OnMouseWheel(MouseWheelEventArgs arg) { double scale = -arg.Delta / 800.000; if (_cameraLookPoint != null && _cameraLookPoint != new Point3D(0, 0, 0)) _camera.LookDirection = Point3D.Subtract(_cameraLookPoint, _camera.Position); int count = Math.Abs((int)(scale / zoomFactor)); for (int i = 1; i <= count; i++) { if (scale > 0) AdjustCameraPosition(_camera, _camera.LookDirection, zoomFactor); else AdjustCameraPosition(_camera, _camera.LookDirection, -zoomFactor); } } void KeyDispatcher_OnMouseRightDown(XMouseEventArgs arg) { Mouse.Capture(_eventSource, CaptureMode.Element); Point pclick = arg.MouseClicked; originalMouseClickPos = arg.ScreenPoint; HitTestResult hitresult = VisualTreeHelper.HitTest(EventSource, pclick); RayMeshGeometry3DHitTestResult result3d = hitresult as RayMeshGeometry3DHitTestResult; if (result3d == null) return; visul3d = result3d.VisualHit as ModelVisual3D; if (visul3d == null) return; //for ALT + MOUSE + ROTATE VisualTreeHelper.HitTest(_eventSource, null, HitTestCallback, new PointHitTestParameters(pclick)); _camera.LookDirection = Point3D.Subtract(_cameraLookPoint, _camera.Position); isTracking = true; _eventSource.CaptureMouse(); _eventSource.Focus(); } void KeyDispatcher_OnMouseMove(XMouseEventArgs arg) { currentPosition = arg.MouseClicked; if (arg.MouseArgs.RightButton == MouseButtonState.Pressed && (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))) { LookUpDown(currentPosition); } else if (arg.MouseArgs.LeftButton == MouseButtonState.Pressed && (Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt))) { if (isTracking) { _eventSource.Cursor = Cursors.None; Focus(currentPosition); } } else if (arg.MouseArgs.RightButton == MouseButtonState.Pressed && Keyboard.IsKeyDown(Key.A)) { if (isTracking) { _eventSource.Cursor = Cursors.None; CameraPanLeftRight(currentPosition); } } else if (arg.MouseArgs.LeftButton == MouseButtonState.Pressed && (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))) { if (isTracking) { _eventSource.Cursor = Cursors.None; RotateObject(currentPosition); } } else if (arg.MouseArgs.LeftButton == MouseButtonState.Pressed && (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))) { if (isTracking) { _eventSource.Cursor = Cursors.None; isPanningObject = true; PanObject(currentPosition); } } else if (arg.MouseArgs.LeftButton == MouseButtonState.Pressed) { if (isTracking) LookAround(currentPosition); } else if (arg.MouseArgs.RightButton == MouseButtonState.Pressed) { if (isTracking) CameraPanUP(currentPosition); } _previousPosition2D = currentPosition; } void KeyDispatcher_OnMouseLeftDown(XMouseEventArgs arg) { Point pclick = arg.MouseClicked; originalMouseClickPos = arg.ScreenPoint; HitTestResult hitresult = VisualTreeHelper.HitTest(EventSource, pclick); RayMeshGeometry3DHitTestResult result3d = hitresult as RayMeshGeometry3DHitTestResult; if (result3d == null) return; visul3d = result3d.VisualHit as ModelVisual3D; if (visul3d == null) return; //for ALT + MOUSE + ROTATE VisualTreeHelper.HitTest(EventSource, null, HitTestCallback, new PointHitTestParameters(pclick)); _camera.LookDirection = Point3D.Subtract(_cameraLookPoint, _camera.Position); _clickedCenterPosition = GetObjectCenterPosition(visul3d); //TRACK BALL _previousPosition3D = ProjectToTrackball( EventSource.ActualWidth, EventSource.ActualHeight, _previousPosition2D); isTracking = true; } void avatarManager_OnAvatarTrunAround(Point3D avatarposition, Vector3D avatarlookdir) { _camera.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new System.Windows.Forms.MethodInvoker(delegate { ResetCameraPos(avatarposition,avatarlookdir); })); } void avatarManager_OnAvatarPosChanged(uint avatarid, Point3D oldpos, Point3D newpos,Vector3D avatarlookdir) { ResetCameraPos(newpos,avatarlookdir); } #region Event Handling void ResetCameraPos(Point3D avatarpos,Vector3D avatarLookDirection) { KeyDispatcher.EventSource.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new System.Windows.Forms.MethodInvoker(delegate { Point3D oldpos = _camera.Position; _camera.Position = Point3D.Add(avatarpos, avatarLookDirection*10); Vector3D cameralookdir = avatarLookDirection; cameralookdir.Z += -0.2; _camera.LookDirection = cameralookdir; if (OnCameraPositionChanged != null) { OnCameraPositionChanged(oldpos, _camera.Position); } })); } void ResetCameraLookDirection(Point3D npos) { Vector3D cameralookdir = npos - _camera.Position; cameralookdir.Z += 8; _camera.LookDirection = cameralookdir; } void ResetCameraLookDirection(Vector3D avatarlookdir) { Vector3D cameralookdir = avatarlookdir; cameralookdir.Z += 8; _camera.LookDirection = cameralookdir; } private void CameraLookLeftRight(Point3D rotatecenter, double angle) { Vector3D axis = new Vector3D(0, 0, 1); Quaternion delta = new Quaternion(axis, -angle); Matrix3D avatarMatrix3D = new Matrix3D(); avatarMatrix3D.RotateAt(delta, rotatecenter); _camera.LookDirection = Vector3D.Add(avatarManager.MySelfLookDirection,new Vector3D(0,0,-2));// avatarMatrix3D);// Point3D.Subtract(_cameraLookPoint, _camera.Position); } Point originalMouseClickPos = new Point(); private Point3D GetObjectCenterPosition(ModelVisual3D visual) { return Point3D.Add(visual.Content.Bounds.Location, new Vector3D(visual.Content.Bounds.SizeX / 2, visual.Content.Bounds.SizeY / 2, visual.Content.Bounds.SizeZ / 2)); } Point currentPosition; private void OnMouseMove(object sender, MouseEventArgs e) { 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.A)) { if (isTracking) { _eventSource.Cursor = Cursors.None; CameraPanLeftRight(currentPosition); } } else if (e.LeftButton == MouseButtonState.Pressed && (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))) { if (isTracking) { _eventSource.Cursor = Cursors.None; RotateObject(currentPosition); } } else if (e.LeftButton == MouseButtonState.Pressed && (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))) { if (isTracking) { _eventSource.Cursor = Cursors.None; isPanningObject = true; PanObject(currentPosition); } } else if (e.LeftButton == MouseButtonState.Pressed) { if(isTracking) LookAround(currentPosition); } else if (e.RightButton == MouseButtonState.Pressed) { if (isTracking) CameraPanUP(currentPosition); } _previousPosition2D = currentPosition; } private void LookAround(Point currentPosition) { if (_cameraLookPoint == new Point3D(0, 0, 0)) return; Vector3D currentPosition3D = ProjectToTrackball(EventSource.ActualWidth, EventSource.ActualHeight, currentPosition); if (_previousPosition3D == currentPosition3D) return; Vector3D axis = Vector3D.CrossProduct(_previousPosition3D, currentPosition3D); double angle = Vector3D.AngleBetween(_previousPosition3D, currentPosition3D); angle *= 2; // We negate the angle because we are rotating the camera. // Do not do this if you are rotating the scene instead. Quaternion delta = new Quaternion(axis, -angle); Matrix3D cameraMatrix3D = new Matrix3D(); cameraMatrix3D.RotateAt(delta,_cameraLookPoint); _camera.Position = Point3D.Multiply(_camera.Position, cameraMatrix3D); _camera.LookDirection = Point3D.Subtract(_cameraLookPoint, _camera.Position); _previousPosition3D = currentPosition3D; } private void RotateObject(Point currentPosition) { Vector3D currentPosition3D = ProjectToTrackball(_eventSource.ActualWidth, _eventSource.ActualHeight, currentPosition); Vector3D axis = Vector3D.CrossProduct(_previousPosition3D, currentPosition3D); double angle = Vector3D.AngleBetween(currentPosition3D, _previousPosition3D); angle *= 3.00000; Matrix3D mat = new Matrix3D(); mat.RotateAt(new Quaternion(axis, angle), _clickedCenterPosition); RotateObject(mat, visul3d); IEnumerator<Visual3D> children = m_primitiveData.GetChildrenByVisual3D(visul3d); while (children.MoveNext()) { RotateObject(mat, children.Current); } _previousPosition3D = currentPosition3D; } private void RotateObject(Matrix3D mat,Visual3D visual) { GeometryModel3D geometryModel3D = (visual as ModelVisual3D).Content as GeometryModel3D; if (geometryModel3D != null) { MeshGeometry3D meshGeometry3D = geometryModel3D.Geometry as MeshGeometry3D; if (meshGeometry3D != null) { Point3DCollection points = meshGeometry3D.Positions; for (int i = 0; i < points.Count; i++) points[i] = Point3D.Multiply(points[i], mat); } } } 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; Vector3D v = new Vector3D(x, z, y); v.Normalize(); return v; } #endregion Event Handling private void CameraPanLeftRight(Point currentPosition) { double scalex = currentPosition.X - _previousPosition2D.X; Vector3D vector3D = GetTranslationVector3D(visul3d, _previousPosition2D, currentPosition); Point3D cPos = _camera.Position; cPos += Math.Abs(scalex) * vector3D; if (OnCameraPositionChanged != null) OnCameraPositionChanged(_camera.Position, cPos); _camera.Position = cPos; } private void PanObject(Point currentPosition) { IEnumerator<Visual3D> children = m_primitiveData.GetChildrenByVisual3D(visul3d); Vector3D vector3D = GetTranslationVector3D(visul3d, _previousPosition2D, currentPosition); MoveObject(visul3d, vector3D); while( children.MoveNext()) { MoveObject(children.Current, vector3D); } } private void MoveObject(Visual3D visual, Vector3D vector3D) { GeometryModel3D geometryModel3D = (visual as ModelVisual3D).Content as GeometryModel3D; if (geometryModel3D != null) { MeshGeometry3D meshGeometry3D = geometryModel3D.Geometry as MeshGeometry3D; if (meshGeometry3D != null) { Point3DCollection points = meshGeometry3D.Positions; for (int i = 0; i < points.Count; i++) points[i] = Point3D.Add(points[i], vector3D * 50); } } } string mm = ""; private Vector3D GetTranslationVector3D(DependencyObject modelHit, Point startPosition, Point endPosition) { Vector3D translationVector3D = new Vector3D(); Viewport3DVisual viewport = null; bool success = false; Matrix3D matrix3D = MathUtils.TryTransformTo2DAncestor(modelHit, out viewport, out success); if (success && matrix3D.HasInverse) { matrix3D.Invert(); Point3D startPoint3D = new Point3D(startPosition.X, startPosition.Y, 0); Point3D endPoint3D = new Point3D(endPosition.X, endPosition.Y, 0); Vector3D vector3D = endPoint3D - startPoint3D; translationVector3D = matrix3D.Transform(vector3D); } return translationVector3D; } private void LookUpDown(Point currentPosition) { double scale = currentPosition.Y- _previousPosition2D.Y; // scale = scale; _camera.LookDirection = new Vector3D(_camera.LookDirection.X, _camera.LookDirection.Y, _camera.LookDirection.Z + scale); } double zoomFactor = 0.0500; private void Focus(Point currentPosition) { //zoom double yDelta = currentPosition.Y - _previousPosition2D.Y; double scale = yDelta/20 ; int count = Math.Abs( (int)(scale / zoomFactor)); for (int i = 1; i <= count; i++) { if (yDelta > 0) AdjustCameraPosition(_camera, _camera.LookDirection, zoomFactor); else AdjustCameraPosition(_camera, _camera.LookDirection, -zoomFactor); } //rotate the camera double axisAngle = _previousPosition2D.X - currentPosition.X; Matrix3D matrixRoateCamera = new Matrix3D(); matrixRoateCamera.RotateAt(new Quaternion(new Vector3D(0, 0, 1), axisAngle), _cameraLookPoint); Point3D pos = Point3D.Multiply(_camera.Position, matrixRoateCamera); if (OnCameraPositionChanged != null) OnCameraPositionChanged(_camera.Position, pos); _camera.Position = pos; _camera.LookDirection = Point3D.Subtract(_cameraLookPoint, _camera.Position); } private void AdjustCameraPosition(PerspectiveCamera camera,Vector3D lookDirection, double factor ) { Point3D cameraPos = new Point3D(camera.Position.X - factor * lookDirection.X, camera.Position.Y - factor * lookDirection.Y, camera.Position.Z - factor * lookDirection.Z); //too fast //if (Point3D.Subtract(cameraPos, camera.Position).Length > 0.5000000000) // cameraPos = new Point3D(camera.Position.X - factor / 10 * lookDirection.X, // camera.Position.Y - factor / 10 * lookDirection.Y, // camera.Position.Z - factor / 10 * lookDirection.Z); double distance = Point3D.Subtract(_cameraLookPoint, cameraPos).Length; if (distance > 512.0000 || distance <= 0.5000000) { } else { if (OnCameraPositionChanged != null) OnCameraPositionChanged(camera.Position, cameraPos); camera.Position = cameraPos; } } //get the clicked 3d position public HitTestResultBehavior HitTestCallback(HitTestResult result) { if (result.VisualHit != null) { RayHitTestResult r = result as RayHitTestResult; if (r != null) { RayMeshGeometry3DHitTestResult t = r as RayMeshGeometry3DHitTestResult; _cameraLookPoint = t.PointHit; 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 / 5.00; _camera.Position = new Point3D(_camera.Position.X, _camera.Position.Y, _camera.Position.Z + scale); } } }
| ViewVC Help | |
| Powered by ViewVC 1.0.0 |

