wissen.leben | WWU Münster 


tgt Trackball Example

Overview

A trackball is a navigation metaphor meant to rotate an object in front of the users. The user should get the feeling of looking at an object within a ball of glass, being able to rotate the ball using the mouse or keyboard.

tgt::Trackball

As using this metaphor or at least similar metaphores are wanted in numerous applications (including voreen), tgt provides a trackball mechanism for flexible but unlabored usage. Using tgt’s default trackball is very simple, while still many advanced settings on trackball handling can be achieved.

tgt::Trackball is derived from tgt::Navigation.

Standard trackball

The Constructor of tgt:Trackball can be called with just giving a tgt::GLCanvas* as a parameter. This way, a trackball with ‘default’ behavior will be created. It will rotate on left mouse button, move the object on shift + left mouse button, zoom in and out on ctrl + left mouse button dragging upwards and downwards or mouse wheel and roll on ctrl + mouse wheel.
(Note that glut and therefor tgt glut applications do not support for mouse wheel events.)

Rotation center will be the coordinate origin.

To use a standard trackball, creating with the constuctor and registering at the event handler will suffice to get it working.

Customize trackball

The default behavior of the trackball can of course be modified. E.g. calling setMouseRotate(MouseEvent::MOUSE_BUTTON_RIGHT, Event::CTRL) will disable rotation using left mouse button and enable rotation using shift + right mouse button instead. setMouseRotate(MouseEvent::NO_MOUSE_BUTTON, 0) will disable mouse rotation at all.

In our example, we enable default keyboard rotation by calling setKeyRotate() method, we also enable zooming on PgUp and PgDn key presses by calling setKeyZoom(10.f, KeyEvent::K_PAGEUP, KeyEvent::K_PAGEDOWN, Event::NONE).

Have a look at the tgt::Trackball::setMouse* / tgt::Trackball::setKey* methods for further details. (TODO: link to doxygen)

Dumb trackball

The second parameter of the tgt::Trackball consturctor is a boolean variable named defaultEventHandling. The default of this optional parameter is true, which will cause the trackball to be a standard trackball as the one mentioned above. If you want to have a trackball that does not react on any mouse or keyboard input by default, you should use false as second parameter. E.g. you want to get a trackball that only will rotate when user presses one of the keys a, s, d or w. You could of course create a standard trackball, disable mouse roation, movement and zooming and mouse wheel zooming and rolling and then enable keyboard rotation:

Trackball trackball(glCanvas);

trackball.setMouseRotate(MouseEvent::NO_MOUSE_BUTTON);
trackball.setMouseMove(MouseEvent::NO_MOUSE_BUTTON);
trackball.setMouseZoom(MouseEvent::NO_MOUSE_BUTTON);
trackball.setMouseWheelZoom(0.f);
trackball.setMouseWheelRoll(0.f);

trackball.setKeyRotate(10.f, 'a', 'd', 'w', 's');

glCanvas->getEventHandler()->addListenerToFront(&trackball);

But this is quite circuitous. You should use the constructor with false as second parameter:

Trackball trackball(glCanvas, false);

trackball.setKeyRotate(10.f, 'a', 'd', 'w', 's');

glCanvas->getEventHandler()->addListenerToFront(&trackball);

Continuous spinning

tgt::Trackball comes with a feature that causes the trackball to keep spinning at continuous speed when the user ends rotation by mouse dragging. Have a try in our sample application samples/trackballnavi to make sure to get a feeling what it is about: Rotate the trackball (press left mouse button, keep pressed and move the mouse) and release the mouse button while the mouse is still moving. The trackball will keep spinning around the same axis at the same speed as before left mouse button was released.
This feature is called continuous spinning.

To enable continuous spinning, we need a tgt::Timer object. As the trackball cannot create one itselft (we wanted to keep trackball independent of the toolkit factory classes), the user has to supply such. To enable continuous spinning, call the constructor with a tgt::Timer object as third parameter.

Moving rotation center

Let’s think of the trackball as a glass ball again. We move the object we are looking at. This could effect two different things: The whole glass ball might be moved or the object might be moved within the glass ball. In the first case, the point the object is beeing rotated around will keep it’s relative position to the object, in the latter case, it will keep it’s relative position to the camera. As for the tgt::Trackball, we say we move the center in the latter case. (This is becase rotation center world coordinates change in that case.)

Moving the center is default behavior of tgt::Trackball. Voreen for example does not move the center, many other applications will not do so either.

Behavior can easily be changed using setMoveCenter() method. Use the example application samples/trackballnavi and have a try on both alternatives: Move the object (shift + left mouse button dragging) and rotate, you will quickly notice the difference.

Trackball size

The size of the Trackball affects the angular speed the trackball is rotated on certain mouse events. Imagine the glass ball again: As a smaller ball has a smaller circumference, same movements will effect larger changes in angles. A larger ball would be rotated by smaller angles.

Furthermore, the screen area that will map mouse coordinates onto a sphere in camera coordinates to calculate rotation angles will shrink at smaller trackball sizes. Outside this area, mapping is done using a hyperbolic sheet.

Example

Painter

We use a painter similar to the one of the navigation example.

class MyPainter : public Painter {
public:
    MyPainter(GLCanvas* canvas) : Painter(canvas) {};
    virtual void paint();
    virtual void sizeChanged(const ivec2& size);
    virtual void init();
};

void MyPainter::paint() {

    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

    // set Camera
    getCamera()->look();

    Sphere sp(1., 32, 16);
    Quad qu(2., 2., 2.);
    Cylinder cy(.5, .2, 5., 16, 3);

    glColor3d(.8,.8,.8);
    sp.render();

    glColor3d(1.,0.,0.);
    glPushMatrix();
      glRotated(90.,1.,0.,0.);
      cy.render();
    glPopMatrix();

    glColor3d(0.,1.,0.);
    glPushMatrix();
      glRotated(90.,0.,1.,0.);
      cy.render();
    glPopMatrix();

    glColor3d(0.,0.,1.);
    glPushMatrix();
      glRotated(90.,0.,0.,1.);
      cy.render();
    glPopMatrix();

    glColor3d(1.,1.,0.);
    glPushMatrix();
      glTranslated(-1., 1., -1.);
      qu.render();
    glPopMatrix();
}

void MyPainter::sizeChanged(const ivec2& size) {
    glViewport(0,0,size.x,size.y);
    getCamera()->setRatio((float) size.x/size.y);
}

void MyPainter::init() {
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    getCamera()->positionCamera(vec3(0.f,0.f,10.f), vec3(0.f,0.f,0.f), vec3(0.f,1.f,0.f));
}

main-Method

int main(int argc, char** argv) {
    tgtApp = ToolkitFactory::createApplication(argc, argv);
    glCanvas = ToolkitFactory::createCanvas("tgt Example: Trackball");
    tgtApp->addCanvas(glCanvas);
    tgtApp->init();
    Camera camera;
    glCanvas->setCamera(&camera);
    MyPainter painter(glCanvas);
    glCanvas->setPainter(&painter);
    // make a trackball with standard mouse interaction
    Trackball trackball(glCanvas, true, ToolkitFactory::createTimer(glCanvas->getEventHandler()));

    // for a more simple trackball without continuous spinning feature, use
    //    Trackball trackball(glCanvas);
    // instead.

    glCanvas->getEventHandler()->addListenerToFront(&trackball);
    // make trackball react on arrow keys as well (this is not default behavior)
    trackball.setKeyRotate();

    // make trackball zoom in and out on PageUp and PageDown keys (this is not default behavior)
    trackball.setKeyZoom(10.f, KeyEvent::K_PAGEUP, KeyEvent::K_PAGEDOWN, Event::NONE);
    trackball.setMoveCenter(false);
    tgtApp->run();
    delete glCanvas;
    delete tgtApp;
    return 0;
}

Complete source code


samples/trackballnavi.cpp
#include "tgt/navigation/trackball.h"

#include "tgt/quadric.h"
#include "tgt/toolkitfactory.h"
#include "tgt/guiapplication.h"
#include "tgt/painter.h"

using namespace tgt;

GuiApplication* tgtApp;
GLCanvas* glCanvas;

class MyPainter : public Painter {
public:
    MyPainter(GLCanvas* canvas) : Painter(canvas) {};
    virtual void paint();
    virtual void sizeChanged(const ivec2& size);
    virtual void init();
};

void MyPainter::paint() {

    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

    // set Camera
    getCamera()->look();

    Sphere sp(1., 32, 16);
    Quad qu(2., 2., 2.);
    Cylinder cy(.5, .2, 5., 16, 3);

    glColor3d(.8,.8,.8);
    sp.render();

    glColor3d(1.,0.,0.);
    glPushMatrix();
      glRotated(90.,1.,0.,0.);
      cy.render();
    glPopMatrix();

    glColor3d(0.,1.,0.);
    glPushMatrix();
      glRotated(90.,0.,1.,0.);
      cy.render();
    glPopMatrix();

    glColor3d(0.,0.,1.);
    glPushMatrix();
      glRotated(90.,0.,0.,1.);
      cy.render();
    glPopMatrix();

    glColor3d(1.,1.,0.);
    glPushMatrix();
      glTranslated(-1., 1., -1.);
      qu.render();
    glPopMatrix();
}

void MyPainter::sizeChanged(const ivec2& size) {
    glViewport(0,0,size.x,size.y);
    getCamera()->setRatio((float) size.x/size.y);
}

void MyPainter::init() {
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    getCamera()->positionCamera(vec3(0.f,0.f,10.f), vec3(0.f,0.f,0.f), vec3(0.f,1.f,0.f));
}

int main(int argc, char** argv) {

    std::cout 
        << "tgt Sample Program: trackballnavi" << std::endl
        << std::endl
        << "Demonstrate usage of tgt's trackball navigation." << std::endl
        << std::endl;
    
    std::cout
        << "Usage" << std::endl
        << "Drag-and-Drop with left mouse button, arrow keys" << std::endl
        << " ==> rotate the trackball" << std::endl
        << "SHIFT + Drag-and-Drop with left mouse button" << std::endl
        << " ==> move the trackball" << std::endl
        << "CTRL  + Drag-and-Drop with left mouse button, mouse wheel, PageUp-, PageDown-key" << std::endl
        << " ==> resize the trackball (zoom)" << std::endl
        << "SHIFT + mouse wheel" << std::endl
        << " ==> roll the trackball (tile camera)" << std::endl
        << std::endl;

    tgtApp = ToolkitFactory::createApplication(argc, argv);

    glCanvas = ToolkitFactory::createCanvas("tgt Example: Trackball");
    tgtApp->addCanvas(glCanvas);

    tgtApp->init();

    Camera camera;
    glCanvas->setCamera(&camera);
    MyPainter painter(glCanvas);
    glCanvas->setPainter(&painter);

    // make a trackball with standard mouse interaction
    Trackball trackball(glCanvas, true, ToolkitFactory::createTimer(glCanvas->getEventHandler()));

    // for a more simple trackball without continuous spinning feature, use
    //    Trackball trackball(glCanvas);
    // instead.

    // make sure trackball gets informed about events
    glCanvas->getEventHandler()->addListenerToFront(&trackball);

    // make trackball react on arrow keys as well (this is not default behavior)
    trackball.setKeyRotate();

    // make trackball zoom in and out on PageUp and PageDown keys (this is not default behavior)
    trackball.setKeyZoom(10.f, KeyEvent::K_PAGEUP, KeyEvent::K_PAGEDOWN, Event::NONE);

    // uncomment to try trackball with fixed center
    //trackball.setMoveCenter(false);

    tgtApp->run();

    delete glCanvas;
    delete tgtApp;

    return 0;
}

Impressum | © 2009 Arbeitsgruppe VisCG | Edit this page
Arbeitsgruppe Visualisierung und Computergrafik
Einsteinstraße 62 · 48149 Münster
Tel.: +49 (251) 83-32700 · Fax: +49 (251) 83-33755