Qt 5.6 | Qt Canvas 3D | Planets Example

Qt 5.6.3 Reference Documentation

# Planets Example

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.

The selection buttons change the `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()` method.

      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` type.

      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()` method.

      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.

Files:

- threejs/planets/FpsDisplay.qml
- threejs/planets/InfoSheet.qml
- threejs/planets/PlanetButton.qml
- threejs/planets/StyledSlider.qml
- threejs/planets/planets.js
- threejs/planets/planets.qml
- threejs/planets/main.cpp
- threejs/planets/planets.pro
- threejs/planets/planets.qrc

Images:

- threejs/planets/images/earth.png
- threejs/planets/images/earthbump1k.jpg
- threejs/planets/images/earthcloudmapcolortrans.png
- threejs/planets/images/earthmap1k.jpg
- threejs/planets/images/earthspec1k.jpg
- threejs/planets/images/galaxy_starfield.png
- threejs/planets/images/jupiter.png
- threejs/planets/images/jupitermap.jpg
- threejs/planets/images/mars.png
- threejs/planets/images/marsbump1k.jpg
- threejs/planets/images/marsmap1k.jpg
- threejs/planets/images/mercury.png
- threejs/planets/images/mercurybump.jpg
- threejs/planets/images/mercurymap.jpg
- threejs/planets/images/moonbump1k.jpg
- threejs/planets/images/moonmap1k.jpg
- threejs/planets/images/neptune.png
- threejs/planets/images/neptunemap.jpg
- threejs/planets/images/plutobump1k.jpg
- threejs/planets/images/plutomap1k.jpg
- threejs/planets/images/saturn.png
- threejs/planets/images/saturnmap.jpg
- threejs/planets/images/saturnringcolortrans.png
- threejs/planets/images/sun.png
- threejs/planets/images/sunmap.jpg
- threejs/planets/images/uranus.png
- threejs/planets/images/uranusmap.jpg
- threejs/planets/images/uranusringcolortrans.png
- threejs/planets/images/venus.png
- threejs/planets/images/venusbump.jpg
- threejs/planets/images/venusmap.jpg