Download source files - 16 Kb
This piece of code was born inside an (unfinished) project of mine: a graphical curve editor with a real time 3D preview using OpenGL libraries.
At first to let the user see the object being constructed from different points of view in the 3D window I simply linked mouse movement with rotation about two axes (usually X and Y when the camera is along Z).
This method become unsatisfactory after a brief period of use cause it presented an odd effect when the object was "upside-down": moving the mouse to the right caused an apparent left rotation and vice-versa.
The oddity was caused by the fact that the rotation has to be referred to the local object coordinate system, in the latter example the object is actually turning right while being upside-down.
In computer graphics literature there are several papers about "intuitive" rotation controllers; I think K. Shoemake's arcball controller represents one of the best solutions: the idea is to project mouse movement on an hypothetical sphere filling the 3D window and to apply the rotation resulting from the sphere being manipulated when the mouse button is pressed to the object.
The global rotation is internally represented and adjusted by using quaternions instead of rotation matrices since this approach is more numerically stable when dealing with small, incremental rotations.
This trackball is a features merging among the original arcball C code (rewritten in OO style) and a virtual trackball controller by J.Childs (used in his GLcube project) which is in turn derived from some code in M.J.Kilgard's GLUT library.
The two code presented several similarities (such as the use of quaternions) but different sphere projection algorithms therefore I decided to retain both: J.Childs' controller project mouse movement on a parabolic sheet when it is outside the sphere while K.Shoemake's one project mouse movement on a plane; the first method (the default one) is somewhat more natural because it's effect is continuous while the second one is abruptly interrupted when the mouse leave/enters the virtual sphere.
In the code I've (re)used a set of math classes which are part of my frequently used graphics programming tools, it's well commented and contains some documentation which can be extracted using Doxygen.
The trackball code is demonstrated in the companion article
CGLEnabledView - An MDI view class
To use a CBallController in your programs follow these steps:
BallController.h where needed.
- Construct a
CBallController somewhere in your application (I suggest the view class) and specify at construction time the radius of the virtual sphere varying from 0.1 to 1.0 (a radius of 1.0 means that the sphere completely fills the window).
- [optional] Call
ToggleMethod member functions to set a project-to-sphere method.
- Call the
ClientAreaResize method in your window resize handler routine (which should be called before showing the window for the first time too) passing the size of your client area.
- [optional but recommended] Call the
Key method passing the character code in your key press handler to enable manipulation trough keyboard (see below for the key bindings).
- [optional] Set the constraint axes via the
UseConstraints method, constraints drawing can be controlled via
- Call the
MouseMove methods in your mouse handlers routines passing the mouse coordinates represented in local window coordinates (origin in upper left corner); it may be a good idea to capture mouse movements outside the windows during mouse button dragging.
- Call the
IssueGLrotation method just before (re)drawing the scene.
- [optional] Call the
DrawBall method after drawing the scene to let the BallController show some feedback during rotations using the alternate method.
GetDrawConstraints and you can check if constraint drawing is activated.
SetAngleKeyIncrement allow to respectively retrieve and set the angle increment used in keyboard interactions.
SetColorV specify or retrieve the color used in DrawBall method, the color can be passed using a COLORREF structure or a vector of [0-1] ranging floats.
|Esc||Interrupts current rotation operation (a rotation operation starts at every mouse button press)|
|Canc or Numpad 5||Resets the current rotation (corresponds to an identity rotation matrix)|
|Right arrow or Numpad 6||rotates +keyIncrement degrees about X axis|
|Left arrow or Numpad 4||rotates -keyIncrement degrees about X axis|
|Up arrow or Numpad 8||rotates +keyIncrement degrees about Y axis|
|Down arrow or Numpad 2||rotates -keyIncrement degrees about Y axis|
|Page Up or Numpad 9||rotates +keyIncrement degrees about Z axis|
|Home or Numpad 7||rotates -keyIncrement degrees about Z axis|
|TAB||during a constrained rotation swicth the constrain axis|
|0.2||Initial public release|
|0.1||Personal development release|