Download source files - 16 Kb
Intro
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.
Internals
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.
Use
The trackball code is demonstrated in the companion article
CGLEnabledView - An MDI view class
supporting OpenGL
To use a CBallController in your programs follow these steps:
- Include
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
SetAlternateMethod
or 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 SetDrawConstraints
method.
- Call the
MouseDown
, MouseMove
and 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.
Other methods
With GetDrawConstraints
and you can check if constraint drawing is activated.
GetAngleKeyIncrement
and SetAngleKeyIncrement
allow to respectively retrieve and set the angle increment used in keyboard interactions.
GetColorV
, GetColor
, SetColor
and 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.
Keys
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 |
History
Revision |
Description |
0.2 |
Initial public release |
0.1 |
Personal development release |