Adding 'pan' to the TrackBall class

Topics: Developer Forum, User Forum
Sep 19, 2007 at 8:24 PM
I've spent a few hours today tryign to figure out how to add the ability to pan (say with middle mouse button) to the trackball class. Adding in a Translate method to the class was not hard, but calculating the correct offsets for the translation is proving difficult for me to wrap my brain around.

It seems to me that 'panning' means to move the camera w.r.t. current camera position (and direction) and the vector described in 2D by the change in mouse position. So, I can imagine a vector from the camera to the center of the Viewport, lets call it C<a1,a2,a3>, that would mean that C would be normal to a plane, P(X,Y,Z), which is basically my screen. So, that would mean that P can be described in terms of C, and that my 2d translation vector would also lie on P, so I should be able to figure out the 3D coordinates of this vector Therefore, I should be able to calculate the translation offsets from the 2d translation vector.

Am I again making something way to complicated or am I on the right track? I would greatly appreciate any pointers. When I get it working I will post the modified class.
Sep 22, 2007 at 10:35 PM
OK, I finally got it figured out I think. Here are the changes:

First we need a place to stash our translation
private TranslateTransform3D _translate = new TranslateTransform3D();

Then we need to add our translation to the transform group in the constructor:
public Trackball()
{
_transform = new Transform3DGroup();
transform.Children.Add(scale);
transform.Children.Add(new RotateTransform3D(rotation));
transform.Children.Add(translate);
}

Oh, we need a class global to keep track of a double used to scale the translation vector we describe with the mouse movement to the size of the mesh or object being displayed:

private Double transScale = 1;

Of course that means we need a property to get/set our scaler:

// This property used to set the scaler value for the 'panning' translation vector
// value is dependant upon object/mesh size
public Double TranslateScale
{
get { return transScale; }

set { transScale = value; }
}

Add this to the OnMouseMove:

else if (e.MiddleButton == MouseButtonState.Pressed)
{
Translate(currentPosition);
}

and then our new function:

private void Translate(Point currentPosition)
{
// Calculate the panning vector from screen(the vector component of the Quaternion
// the division of the X and Y components scales the vector to the mouse movement
Quaternion qV = new Quaternion(((_previousPosition2D.X - currentPosition.X) / transScale),
((currentPosition.Y - _previousPosition2D.Y) / transScale), 0, 0);

// Get the current orientantion from the RotateTransform3D
Quaternion q = new Quaternion(_rotation.Axis, _rotation.Angle);
Quaternion qC = q;
qC.Conjugate();

// Here we rotate our panning vector about the the rotaion axis of any current rotation transform
// and then sum the new translation with any exisiting translation
qV = q * qV * qC;
_translate.OffsetX += qV.X;
_translate.OffsetY += qV.Y;
_translate.OffsetZ += qV.Z;
}

Sep 30, 2007 at 7:45 PM
Nice one jeff,
I see you are active on MSDN too..

Excellent work,

I relish the chance to use this on a future project.

Good man.
Oct 26, 2007 at 11:13 AM
So if I want to skin my cursor with 3DTool I need to use ?

Or any thing else ?

_3DTools.TrackballDecorator || _3DTools.Trackport3D || _3DTools.Trackball
Nov 19, 2007 at 7:26 AM
Great job, how to set the panning margins(boundaries) so our object doesn't leave view entirely?
May 29, 2009 at 1:23 PM
Edited May 29, 2009 at 1:23 PM

I have been using the 3d tools trackport and trackball for a little project of mine and also added some pan functionality, although i believe when I get home and try this, it will prove to be more natural feeling.  its for a single touch point touchscreen application so getting the model in the right spot is left to the user save for a few stock animations.  I have put bpundaries on my scale and translate transforms but not net on the the rotate.  see I want the boundaries to be specified per axis of rotation. say 90 araound X, 45 around Y and 180 around Z (Z is my up).  So how can i figure out from the quat how much rotation there is around anyone of these axis.  I was thinking to grab the axis from the axis angle rotation, dot it with my unit vector and then take this dot prouct and multiply it with the angle of rotation to get angle on that axis.  i'm not sure if this is correct though?  any ideas?

Jun 25, 2010 at 12:20 PM

Old post, but this works great thanks for posting.  You need to add an underscore to any uses of translate since the variable is actually named _translate (ie in the constructor) but obviously that's trivial. 

Aug 4, 2010 at 10:07 PM

I would like to use this approach, but it doesn't take into affect a UpDirection, Position and LookDirection that is initially set on the camera.  It seems that if I want to use the approach described in this discussion, then I need to leave UpDirection, Position and LookDirection at their defaults, but I really need to point the camera along a preferred look direction (still targeted at 0,0,0).

Perhaps I should set the Rotation Axis and Angle of the trackball, but I can't seem to convert the camera's position and look direction to the a Rotation Transform.

Any thoughts out there?