Coin3D-Qt Paper
Coin3D-Qt Paper
Coin3D consists of a core 3D rendering library (Coin), file import/export libraries and GUI-bindings.
This whitepaper will describe how to integrate Coin and Qt using SoQt. SoQt is the GUI-binding between Coin and Qt
that allows Qt applications to display complex 3D scenes with ease. Because Coin is fully compatible with SGI’s Open
Inventor, the de facto standard 3D graphics API for complex visualization applications, legacy Inventor applications
can be updated to use Coin. SoQt’s interface closely matches SGI’s original SoXt GUI bindings, making it easier to port
legacy X Windows Inventor applications to Qt.
SoInput sceneInput;
if ( !sceneInput.openFile( “stagedancers.iv” ) )
return -1;
// Clean up resources.
delete eviewer;
root->unref();
return 0;
}
KONGSBERG SIM
Coin3D and Qt:
The Solution for Cross-platform 3D Application Development
This code produces the application shown in Figure 1. Notice that this is a complete scenegraph viewer that handles
drawing, interaction via the mouse, and has several buttons and thumbwheels to control the display. Of course SoQt allows
the use of the complete Qt API to create far more sophisticated user interfaces. This example just demonstrates how easy
it can be load, display, and manipulate a scenegraph in a Qt application using Coin and SoQt.
Examining the code in more detail provides some insight into how SoQt and Coin work. The first key piece of code from
the example above is:
This initializes the SoQt and Qt libraries, and returns a pointer to a QWidget that will act as a container for the viewer once
it is created. The next several lines open an Inventor scene file and load the data into a scene graph..
SoInput sceneInput;
if ( !sceneInput.openFile( “stagedancers.iv” ) )
return -1;
SoSeparator is a scenegraph node that holds a group of child nodes and isolates them from transformations made to other
parts of the scenegraph. The next few lines create the viewer and its subwidgets, putting them into the shell widget.
KONGSBERG SIM
Coin3D and Qt:
The Solution for Cross-platform 3D Application Development
This example uses the high-level SoQtExaminerViewer class to provide a complete viewer with all the features described
above. SoQt offers several classes capable of displaying a scenegraph, each with different levels of features and flexibility.
These will be described in detail later. Next we give the viewer the scenegraph to display and then show it:
eviewer->setSceneGraph(root);
eviewer->show();
SoQt::mainLoop();
3 Architecture
Coin is written entirely on top of OpenGL and provides 3D rendering and scene management but no user interface
components. Qt, on the other hand, offers OpenGL integration, but at a fairly low level. It provides a way to wrap an OpenGL
context in QWidget and draw onto that widget using OpenGL; however, it does not provide an easy way to integrate with
more complex rendering libraries like Coin. SoQt is the glue between Qt and Coin, allowing the application programmer to
use the power of Coin for 3D rendering and the simplicity of Qt for the user interface. Both Coin and Qt isolate the developer
from the underlying platform dependencies and are completely cross-platform.
SoQt builds on Qt’s QGL library. Qt interacts with the underlying windowing system to create OpenGL contexts, create
and manage windows, and handle windows system events. SoQt uses the OpenGL widgets created by Qt, but adds an
interface for rendering Coin scenegraphs instead of pure OpenGL. SoQt provides automatic event handling: just as Qt
translates low-level window system events into higher-level QEvents, SoQt translates these QEvents into Coin SoEvents.
SoEvents describe how to manipulate the camera or other objects in the scenegraph. Event types handled by SoQt include
mouse events, keyboard events, and window resizing events.
It is important to note that SoQt classes are NOT instances of QWidget or QObject. SoQt uses delegation rather than
inheritance to integrate with Qt. This allows greater flexibility and a cleaner architecture. Internally, SoQt creates an
instance of a QGLWidget to perform rendering.
4 Displaying a Scenegraph
The fundamental purpose of SoQt is to allow a Coin scenegraph to be rendered in a Qt application. Adding a scenegraph
to a Qt application involves creating an instance of a SoQt class that is capable of rendering the scenegraph. There are
several available classes, each offering differing levels of abstraction and customization. Some can be used directly while
others are abstract and must first be subclassed.
KONGSBERG SIM
Coin3D and Qt:
The Solution for Cross-platform 3D Application Development
Figure 2 The inheritance hierarchy of
the viewing classes
4.2.1 SoQtGLWidget
While it is rare to need to inherit directly from SoQtGLWidget, this class does contain several virtual functions that can be
overridden in derived classes. Two of the most important are processEvent() and buildWidget(). The processEvent() function
makes the translation from QEvents to SoEvents, while the buildWidget() function takes constructs all the necessary viewer
GUI components including the internal QGL. These functions will be discussed in more detail in Section 5.1.
SoQtGLWidget also has several functions for controlling the OpenGL rendering context. The setDoubleBuffer() function
specifies whether OpenGL should use double buffering. There are analogous functions for setting stereo buffers, stencil
buffers, overlay planes, alpha channels, etc. The SoQtGLWidget class also gives you access to the underlying QGLWidget
used to render the scenegraph via the getGLWidget() function.
4.2.2 SoQtRenderArea
SoQtRenderArea inherits from SoQtGLWidget and adds a SoSceneManager and a scenegraph. The SoSceneManager class
is part of the Coin API and contains functions for querying/setting the size of the render area, redrawing the screen, getting
to the “real root” of a scenegraph, among others. When using the SoQtRenderArea, it is the programmer’s responsibility to
create a scenegraph that contains a camera and at least one light source.
To trigger a redraw of the scenegraph, SoQtRenderArea offers several options. The redraw() function immediately redraws
the scenegraph, while the scheduleRedraw() function will schedule a redraw on the event loop. After the event loop
processes any pending events, the scene will be redrawn. This can often be more efficient as several consecutive redraw
requests can be compressed into a single redraw. Another way to redraw the scenegraph is use setAutoRedraw() to enable
automatic redraws when the scenegraph data changes.
KONGSBERG SIM
Coin3D and Qt:
The Solution for Cross-platform 3D Application Development
4.3 SoQtViewer
The abstract SoQtViewer class is derived from the SoQtRenderArea. It adds many convenience functions, mostly for
camera handling. It will either detect a camera in the scenegraph or will automatically create one when none exists. Other
functionality includes toggling the camera between orthographic and perspective projection, setting the camera such that
the entire scene is visible, changing stereo modes, saving/restoring “home” camera positions, and automatically configuring
the clipping planes to ensure optimal use of the z-buffer. SoQtViewer also has a built-in headlight that will always illuminate
the scene. This can be useful during development to ensure the scene will always be lit correctly until a custom lighting
configuration can be established and tested.
The SoQtViewer class does not handle camera movement. To handle camera motion, the programmer will need to override
SoQtRenderArea::processSoEvent (). This function is called after SoQt has translated QEvents into SoEvents and gives
the programmer a chance to processes the SoEvent. The easiest way to get started writing a custom processSoEvent()
function is to look at the source code for one of the full viewers, such as the SoQtExaminerViewer. A typical implementation
will determine the event type, check which mouse button is pressed, then update the camera based on these parameters and
the movements of the mouse. Because Coin is fully compatible with SGI’s Open Inventor, developers can leverage legacy
Inventor code that already contains routines to handle SoEvents. Because SoQt translates QEvents into full SoEvents,
integration is simple, with no need to interpret the Qt events directly.
These classes are meant primarily for prototyping and rapid development as well as writing test bed applications for
developing scenegraphs. The opening example demonstrated how little code is required to use these classes. These
classes allow programmers to view and interact with the scenegraph very early in the development process, ensuring the
maximum amount of time for perfecting and debugging what is often the most complex part of the application. While the
SoQtFullViewer and derived classes are excellent for prototyping, they impose a lot of functionality and look-and-feel that
is typically either not appropriate or not necessary for an application. As the application architecture becomes more stable,
the application will switch to the more flexible classes to create a custom user interface.
The SoQtFullViewer is an abstract class that provides everything from the SoQtViewer, plus the widgets visible in Figure 1. It
also provides a popup menu with options to change many rendering parameters and viewer configuration. The SoQtFlyViewer
adds controls to move the camera in a flying motion while keeping the camera upright. The SoQtPlaneViewer includes
controls to move the camera into orthogonal planes for CAD-style viewing along the x-y-z axes. The SoQtExaminerViewer
is the most complete viewer class and contains controls for panning, rotating, and zooming via the mouse or keyboard.
KONGSBERG SIM
Coin3D and Qt:
The Solution for Cross-platform 3D Application Development
5 Linking the GUI to Coin
SoQt makes it easy to harness the power of Qt to create sophisticated user interfaces that control and interact with the
scenegraph. One of the most powerful aspects of Qt is its signal/slot mechanism. But what is the best way create and link
Qt widgets to the scenegraph?
QWidget * MyViewer::buildWidget(QWidget * parent)
{
//have the superclass build and return it’s widget.
QWidget * viewerWidget = SoQtViewer::buildWidget(parent);
//call private fns to create some widgets
createToolbars(parent);
createPopupMenus(parent);
Commonly used widgets can be stored as member variables for later access, including connecting signals and slots.
Providing accessor functions to allow outside access to these widgets will facilitate making signal/slot connections to
widgets outside the viewer class.
The next step is to connect widgets using signals and slots. In addition to the viewer widgets created in buildWidget(), there
are will also be outside widgets from the rest of the application that need to be connected. The best way to handle this is to
create a “manager” class that inherits from QObject and holds references to the various classes that need to be connected.
This class will typically contain: a custom viewing class discussed in section 4, any scenegraphs, and managers holding
the actual objects represented in the scenegraph. It will have slots to perform common functions and provide signals for
other widgets to connect to. For example:
public slots:
void redrawScene();
void setBackgroundColor(const SbColor &color);
KONGSBERG SIM
Coin3D and Qt:
The Solution for Cross-platform 3D Application Development
signals:
void objectSelected(Object *picked);
private:
ViewerWidget *viewerWidget;
SoSeparator *rootSceneGraph;
SoSceneManager *sceneManager;
ObjectManager *objectManager;
};
In this example, the ViewerWidget class is one of the viewing classes, such as a SoQtRenderArea or SoQtExaminerViewer.
The MySceneManager class is the class that the rest of the UI components will interact with. It is a QObject, so it can
implement the signal/slot mechanism. The objectSelected() signal notifies outside listeners that a new object in the
scenegraph has been selected. For more details on selection, see section 5.3
To handle custom translation from QEvents to SoEvents, override the processEvent() function from SoQtRenderArea.
This is the function that parses QEvents and creates the appropriate SoEvents. The SoEvents are then passed on to the
processSoEvent() function described above in section 4.3
The following code shows the basic principles of selection and editing with Qt and Coin. It is similar to the example from
section 2, but this time with a simple scenegraph consisting of a yellow cone. When user clicks the cone, a QColorDialog is
shown to allow the user to change its color. It is quite easy to extend this basic example to pop up a custom editing widget
based on the type of object selected and populate it with the object’s current parameters.
//save the root and color nodes for use in the callback
static SoSeparator *root = 0;
static SoBaseColor *coneCol = 0;
KONGSBERG SIM
Coin3D and Qt:
The Solution for Cross-platform 3D Application Development
//create a color and a cone and insert them under the selection node
coneCol = new SoBaseColor;
coneCol->rgb = SbColor(1, 1, 0);
selection->addChild(coneCol);
selection->addChild(new SoCone);
6 Conclusion
This paper has demonstrated multiple ways to integrate Coin and Qt using SoQt. SoQt is easy-to-use, powerful and
flexible, offering both ready-made viewers for prototyping and classes that support complete customization. Events and
selection can be handled with ease. SoQt makes it possible to efficiently create cross-platform 3D applications that using
the full power of both Coin and Qt.
KONGSBERG SIM