Interactive Pan / Zoom

Jun 10, 2011 at 1:44 PM

Hi all

I'm working on an interface that allows users to pan and zoom around a 3D model within my Silverlight 4 application.  The pan and zoom all work fine when there's no rotation of the camera - ie the planes of the camera are coincident with the planes of the world.

But, as soon as I rotate things, the pan, rotation and zoom all get intermingled.  I'm pretty sure I need to add a COS/SIN factor to my camera position and target... but the math escapes me.

Here is some of the relevant code snippets

        private void Page_MouseMove(object sender, MouseEventArgs e)
        {
            if (!_leftmousedown)
                return;

            Point mousePoint = e.GetPosition(this);
            double deltaX = 0.25 - 1 * Math.Cos((float)_xSlider.Value); // _lastmouseposition.X - mousePoint.X;
            double deltaY = 0.25 - 1 * Math.Sin((float)_ySlider.Value); // _lastmouseposition.Y - mousePoint.Y;

            // ControlKey = Rotate
            if (_controlkeydown)
            {
                if (mousePoint.X < _lastmouseposition.X)
                    _xSlider.Value -= deltaX ;
                else if (mousePoint.X > _lastmouseposition.X)
                    _xSlider.Value += deltaX;

                if (mousePoint.Y < _lastmouseposition.Y)
                    _ySlider.Value -= deltaY ;
                else if (mousePoint.Y > _lastmouseposition.Y)
                    _ySlider.Value += deltaY;

                CalculateCameraPosition();
            }

            // ShiftKey = Pan
            if (_shiftkeydown)
            {
                if (mousePoint.X < _lastmouseposition.X)
                {
                    gameWireframe.Camera.Position.X -= deltaX;
                    gameWireframe.Camera.Target.X -= deltaX;
                }
                else if (mousePoint.X > _lastmouseposition.X)
                {
                    gameWireframe.Camera.Position.X += deltaX;
                    gameWireframe.Camera.Target.X += deltaX;
                }
                if (mousePoint.Y < _lastmouseposition.Y)
                {
                    gameWireframe.Camera.Position.Y -= deltaY;
                    gameWireframe.Camera.Target.Y -= deltaY;
                }
                else if (mousePoint.Y > _lastmouseposition.Y)
                {
                    gameWireframe.Camera.Position.Y += deltaY;
                    gameWireframe.Camera.Target.Y += deltaY ;
                }
                CalculateCameraPosition();
            }
            _lastmouseposition = mousePoint;
        }

        private void Slider_ValueChanged(object sender, System.Windows.RoutedPropertyChangedEventArgs e)
        {
            if (null != _xSlider)
            {
                CalculateCameraPosition();
            }
        }

        private void CalculateCameraPosition()
        {
            try
            {

                Balder.Math.Matrix mymatrix = new Balder.Math.Matrix();


                Balder.Math.Matrix rotationX = Balder.Math.Matrix.CreateRotationX((float)_xSlider.Value);
                Balder.Math.Matrix rotationY = Balder.Math.Matrix.CreateRotationY((float)_ySlider.Value);
                Balder.Math.Matrix combined = rotationX * rotationY;
                var forward = Vector.Forward;
                var zoomedForward = forward * (float)_zoomSlider.Value;
                var position = zoomedForward * combined;
                var target = new Vector((float)gameWireframe.Camera.Target.X,
                                                (float)gameWireframe.Camera.Target.Y,
                                                (float)gameWireframe.Camera.Target.Z);
                var actualPosition = target - position;
                gameWireframe.Camera.Position.X = actualPosition.X;
                gameWireframe.Camera.Position.Y = actualPosition.Y;
                gameWireframe.Camera.Position.Z = actualPosition.Z;
            }
            catch
            {
            }
        }
I suspect the issue is in how I'm calculating the deltaX and deltaY values (and I guess I need a deltaZ too) but everything I've tried makes it worse - ie, it doesn't work on a non-rotated camera.
Thanx,
Peter