Planets Example

Demonstrates combining Qt Quick and three.js rendering.

The Planets example demonstrates how to implement an application that combines the use of three.js library-based Canvas3D rendering with Qt Quick 2D elements. The example shows the eight planets of our Solar System with the Sun.

The planets are rotating around the Sun based on their orbit at a given time. The rotation starts at 2000 Jan 0.0 UT. The planet positions are calculated based on the formulas found here: http://www.stjarnhimlen.se/comp/ppcomp.html and http://www.davidcolarusso.com/astro/ .

Qt Quick Implementation

The Qt Quick Implementation planets.qml of the example renders the 3D content using Canvas3D type. The type calls JavaScript code that uses three.js to initialize, paint, and resize the 3D view.

Canvas3D {
    id: canvas3d
    anchors.fill: parent
    onInitializeGL: {
        GLCode.initializeGL(canvas3d, eventSource, mainview);
    }
    onPaintGL: {
        GLCode.paintGL(canvas3d);
        fpsDisplay.fps = canvas3d.fps;
    }
    onResizeGL: {
        GLCode.onResizeGL(canvas3d);
    }
    ControlEventSource {
        anchors.fill: parent
        focus: true
        id: eventSource
    }
}
					

The planet related information is stored into ListModel . The selection buttons for the planets and the information sheet are created based on the model. The 2D elements, selection buttons and sliders, are implemented in the QML side.

选择按钮改变 focusedPlanet property of the mainview. As the property changes the planet information is updated and the camera is animated to the new position. The camera position and the camera look at point are updated based on values that are animated on QML side.

onFocusedPlanetChanged: {
    if (focusedPlanet == 100) {
        info.opacity = 0;
        updatePlanetInfo();
    } else {
        updatePlanetInfo();
        info.opacity = 0.5;
    }
    GLCode.prepareFocusedPlanetAnimation();
    lookAtOffsetAnimation.restart();
    cameraOffsetAnimation.restart();
}
					

The sliders are used to adjust the rotation speed, the planet size, and the viewing distance. When the slider value changes, JavaScript code is called to adjust the given property. For example, changing the value of the "Viewing Distance" slider calls the setCameraDistence() 方法。

onValueChanged: GLCode.setCameraDistance(value);
					
					

The JavaScript Code

The JavaScript side of the implementation, planets.js , is done using a version of three.js that is ported for Qt Canvas 3D : three.js .

The initializeGL() method creates the camera and the scene. It also adds the lights to the scene and creates the planet meshes. The Canvas3D renderer needs to be created at initialization phase too.

Planet texture maps are Copyright (c) by James Hastings-Trew http://planetpixelemporium.com/planets.html used with permission. To calculate the ring geometry for the planets with rings, the _RingGeometry() method from three.xplanets extension is used.

The scene is rendered in paintGL() method. That is also the place where the positions for all of the planets are calculated. The planets are rotated based on their axial tilt and their sidereal rotation period. In the paintGL() method the camera position and look at point are updated based on the focused planet.

For more information on how to use three.js the documentation is available here: three.js/docs

Handling the Mouse Events

In order to handle the mouse event in JavaScript code the Canvas3D type has to include the ControlEventSource 类型。

ControlEventSource {
    anchors.fill: parent
    focus: true
    id: eventSource
}
					

This type is then passed to the JavaScript code on initialization.

onInitializeGL: {
    GLCode.initializeGL(canvas3d, eventSource, mainview);
}
					

On JavaScript code in the initializeGL() method the eventSource object is saved to a global variable. In this example mouseDown event is connected to the onDocumentMouseDown() 方法。

eventSource.mouseDown.connect(onDocumentMouseDown);
					

Based on the mouse position variables passed to onDocumentMouseDown() method, it's checked if the event takes place on top of a planet or not. The focused planet is changed according to the mouse position.

文件:

图像: