Qt 5.6 | Qt 3D | Qt 3D: Planets QML Example | SolarSystem.qml Example File

Qt 5.6.3 Reference Documentation

# SolarSystem.qml Example File

planets-qml/SolarSystem.qml

      /****************************************************************************
      **
      ** Copyright (C) 2015 The Qt Company Ltd.
      ** Contact: http://www.qt.io/licensing/
      **
      ** This file is part of the Qt3D module of the Qt Toolkit.
      **
      ** $QT_BEGIN_LICENSE:LGPL3$
      ** Commercial License Usage
      ** Licensees holding valid commercial Qt licenses may use this file in
      ** accordance with the commercial license agreement provided with the
      ** Software or, alternatively, in accordance with the terms contained in
      ** a written agreement between you and The Qt Company. For licensing terms
      ** and conditions see http://www.qt.io/terms-conditions. For further
      ** information use the contact form at http://www.qt.io/contact-us.
      **
      ** GNU Lesser General Public License Usage
      ** Alternatively, this file may be used under the terms of the GNU Lesser
      ** General Public License version 3 as published by the Free Software
      ** Foundation and appearing in the file LICENSE.LGPLv3 included in the
      ** packaging of this file. Please review the following information to
      ** ensure the GNU Lesser General Public License version 3 requirements
      ** will be met: https://www.gnu.org/licenses/lgpl.html.
      **
      ** GNU General Public License Usage
      ** Alternatively, this file may be used under the terms of the GNU
      ** General Public License version 2.0 or later as published by the Free
      ** Software Foundation and appearing in the file LICENSE.GPL included in
      ** the packaging of this file. Please review the following information to
      ** ensure the GNU General Public License version 2.0 requirements will be
      ** met: http://www.gnu.org/licenses/gpl-2.0.html.
      **
      ** $QT_END_LICENSE$
      **
      ****************************************************************************/

      import QtQuick 2.0 as QQ2
      import Qt3D.Core 2.0
      import Qt3D.Render 2.0
      import Qt3D.Logic 2.0

      import "planets.js" as Planets

      Entity {
          id: sceneRoot

          property bool ready: false

          property real cameraNear: 0
          property real xLookAtOffset: 0
          property real yLookAtOffset: 0
          property real zLookAtOffset: 0
          property real xCameraOffset: 0
          property real yCameraOffset: 0
          property real zCameraOffset: 0

          property var planetData
          property var planets: []

          property vector3d defaultUp: Qt.vector3d(0, 1, 0)
          property vector3d defaultCameraPosition: Qt.vector3d(Planets.solarDistance,
                                                               Planets.solarDistance,
                                                               Planets.solarDistance)
          property vector3d tiltAxis: Qt.vector3d(0, 0, 1)
          property vector3d rollAxis: Qt.vector3d(0, 1, 0)
          property real cameraDistance: 1
          property vector3d oldCameraPosition
          property vector3d oldFocusedPlanetPosition

          property color ambientStrengthStarfield: "#000000"
          property color ambientStrengthSun: "#ffffff"
          property color ambientStrengthClouds: "#000000"
          property color ambientStrengthRing: "#111111"
          property color ambientStrengthPlanet: "#222222"
          property real shininessSpecularMap: 50.0
          property real shininessClouds: 10.0
          property real shininessBasic: 1.0

          property real saturnRingInnerRadius
          property real saturnRingOuterRadius
          property real uranusRingInnerRadius
          property real uranusRingOuterRadius

          // Time variables
          property int year: 2000
          property int month: 1
          property int day: 1
          // Time scale formula based on http://www.stjarnhimlen.se/comp/ppcomp.html
          property real startD: 367 * year - 7 * (year + (month + 9) / 12) / 4 + 275 * month / 9 + day - 730530
          property real oldTimeD: startD
          property real currTimeD: startD
          property real deltaTimeD: 0
          property real daysPerFrame
          property real daysPerFrameScale

          property real planetScale

          property bool focusedScaling: false
          property int focusedMinimumScale: 20
          property real actualScale

          // Animate solar system with LogicComponent
          LogicComponent {
              onFrameUpdate: {
                  frames++
                  animate(focusedPlanet)
              }
          }

          PlanetsLight {
              id: light
              ratio: width / height
          }

          Camera {
              id: camera
              projectionType: CameraLens.PerspectiveProjection
              fieldOfView: 45
              aspectRatio: width / height
              nearPlane: 2500000.0
              farPlane: 20000000.0
              position: defaultCameraPosition
              upVector: defaultUp
              viewCenter: Qt.vector3d( xLookAtOffset, yLookAtOffset, zLookAtOffset )
          }

          Configuration  {
              controlledCamera: camera
          }

          components: [
              PlanetFrameGraph {
                  id: framegraph
                  viewCamera: camera
                  lightCamera: light.lightCamera
              }
          ]

          CloudEffectDS {
              id: effectDS
              light: light
          }

          PlanetEffectD {
              id: effectD
              light: light
          }

          PlanetShadowEffectD {
              id: shadowMapEffectD
              shadowTexture: framegraph.shadowTexture
              light: light
          }

          PlanetEffectDB {
              id: effectDB
              light: light
          }

          PlanetEffectDSB {
              id: effectDSB
              light: light
          }

          QQ2.Component.onCompleted: {
              planetData = Planets.loadPlanetData()
              // Push in the correct order
              planets.push(sun)
              planets.push(mercury)
              planets.push(venus)
              planets.push(earth)
              planets.push(mars)
              planets.push(jupiter)
              planets.push(saturn)
              planets.push(uranus)
              planets.push(neptune)
              planets.push(moon)
              // TODO: Once support for creating meshes from arrays is implemented take these into use
              //saturnRing.makeRing()
              //uranusRing.makeRing()
              saturnRingOuterRadius = planetData[Planets.SATURN].radius + Planets.saturnOuterRadius
              saturnRingInnerRadius = planetData[Planets.SATURN].radius + 6.630
              uranusRingOuterRadius = planetData[Planets.URANUS].radius + Planets.uranusOuterRadius
              uranusRingInnerRadius = planetData[Planets.URANUS].radius + 2
              ready = true
              changeScale(1200)
              changeSpeed(0.2)
              setLookAtOffset(Planets.SUN)
          }

          QQ2.NumberAnimation {
              id: lookAtOffsetAnimation
              target: sceneRoot
              properties: "xLookAtOffset, yLookAtOffset, zLookAtOffset"
              to: 0
              easing.type: Easing.InOutQuint
              duration: 1250
          }

          QQ2.NumberAnimation {
              id: cameraOffsetAnimation
              target: sceneRoot
              properties: "xCameraOffset, yCameraOffset, zCameraOffset"
              to: 0
              easing.type: Easing.InOutQuint
              duration: 2500
          }

          QQ2.Behavior on cameraNear {
              QQ2.PropertyAnimation {
                  easing.type: Easing.InOutQuint
                  duration: 2500
              }
          }

          function changePlanetFocus(oldPlanet, focusedPlanet) {
              setOldPlanet(oldPlanet, focusedPlanet)
              setLookAtOffset(focusedPlanet)
              setCameraOffset(oldPlanet, focusedPlanet)
              lookAtOffsetAnimation.restart()
              cameraOffsetAnimation.restart()
          }

          function setOldPlanet(oldPlanet, focusedPlanet) {
              oldCameraPosition = camera.position

              var planet = 0
              if (oldPlanet !== Planets.SOLAR_SYSTEM)
                  planet = oldPlanet
              oldFocusedPlanetPosition = Qt.vector3d(planets[planet].x,
                                                     planets[planet].y,
                                                     planets[planet].z)
              checkScaling(focusedPlanet)
          }

          function setScale(value, focused) {
              // Save actual scale
              if (!focused)
                  actualScale = value

              // Limit minimum scaling in focus mode to avoid jitter caused by rounding errors
              if (value <= focusedMinimumScale && (focusedScaling || focused))
                  planetScale = focusedMinimumScale
              else
                  planetScale = actualScale
              return planetScale
          }

          function checkScaling(focusedPlanet) {
              if (focusedPlanet !== Planets.SOLAR_SYSTEM) {
                  // Limit minimum scaling in focus mode to avoid jitter caused by rounding errors
                  if (actualScale <= focusedMinimumScale) {
                      planetScale = focusedMinimumScale
                      changeScale(focusedMinimumScale, true)
                  }
                  focusedScaling = true
              } else if (focusedScaling === true) {
                  // Restore normal scaling
                  focusedScaling = false
                  changeScale(actualScale, false)
              }
          }

          function setLookAtOffset(focusedPlanet) {
              var offset = oldFocusedPlanetPosition

              var planet = 0
              if (focusedPlanet !== Planets.SOLAR_SYSTEM)
                  planet = focusedPlanet

              var focusedPlanetPosition = Qt.vector3d(planets[planet].x,
                                                      planets[planet].y,
                                                      planets[planet].z)
              offset = offset.minus(focusedPlanetPosition)

              xLookAtOffset = offset.x
              yLookAtOffset = offset.y
              zLookAtOffset = offset.z
          }

          function setCameraOffset(oldPlanet, focusedPlanet) {
              var offset = oldCameraPosition

              var planet = 0
              if (focusedPlanet !== Planets.SOLAR_SYSTEM)
                  planet = focusedPlanet

              var newCameraPosition = getNewCameraPosition(focusedPlanet, Planets.getOuterRadius(planet))

              if (focusedPlanet !== Planets.SUN)
                  offset = offset.minus(newCameraPosition)

              if (oldPlanet === Planets.SOLAR_SYSTEM && focusedPlanet === Planets.SUN) {
                  xCameraOffset = Math.abs(offset.x)
                  yCameraOffset = Math.abs(offset.y)
                  zCameraOffset = Math.abs(offset.z)
              } else { // from a planet to another
                  xCameraOffset = offset.x
                  yCameraOffset = offset.y
                  zCameraOffset = offset.z
              }
          }

          function getNewCameraPosition(focusedPlanet, radius) {
              var position
              if (focusedPlanet === Planets.SOLAR_SYSTEM) {
                  position = defaultCameraPosition
                  position = position.times(cameraDistance)
              } else if (focusedPlanet === Planets.SUN) {
                  position = Qt.vector3d(radius * planetScale * 2,
                                         radius * planetScale * 2,
                                         radius * planetScale * 2)
                  position = position.times(cameraDistance)
              } else {
                  var vec1 = Qt.vector3d(planets[focusedPlanet].x,
                                         planets[focusedPlanet].y,
                                         planets[focusedPlanet].z)
                  var vec2 = defaultUp
                  vec1 = vec1.normalized()
                  vec2 = vec2.crossProduct(vec1)
                  vec2 = vec2.times(radius * planetScale * cameraDistance * 4)
                  vec2 = vec2.plus(Qt.vector3d(planets[focusedPlanet].x,
                                               planets[focusedPlanet].y,
                                               planets[focusedPlanet].z))
                  vec1 = Qt.vector3d(0, radius * planetScale, 0)
                  vec2 = vec2.plus(vec1)
                  position = vec2
              }
              return position
          }

          function advanceTime(focusedPlanet) {
              if (focusedPlanet === Planets.SOLAR_SYSTEM)
                  daysPerFrame = daysPerFrameScale * 10
              else
                  daysPerFrame = daysPerFrameScale * planetData[focusedPlanet].period / 100.0

              // Advance the time in days
              oldTimeD = currTimeD
              currTimeD = currTimeD + daysPerFrame
              deltaTimeD = currTimeD - oldTimeD
          }

          function positionPlanet(i) {
              var planet = planetData[i]
              var target = planets[i]

              if (i !== Planets.SUN) {
                  // Calculate the planet orbital elements from the current time in days
                  var N = (planet.N1 + planet.N2 * currTimeD) * Math.PI / 180
                  var iPlanet = (planet.i1 + planet.i2 * currTimeD) * Math.PI / 180
                  var w = (planet.w1 + planet.w2 * currTimeD) * Math.PI / 180
                  var a = planet.a1 + planet.a2 * currTimeD
                  var e = planet.e1 + planet.e2 * currTimeD
                  var M = (planet.M1 + planet.M2 * currTimeD) * Math.PI / 180
                  var E = M + e * Math.sin(M) * (1.0 + e * Math.cos(M))

                  var xv = a * (Math.cos(E) - e)
                  var yv = a * (Math.sqrt(1.0 - e * e) * Math.sin(E))
                  var v = Math.atan2(yv, xv)

                  // Calculate the distance (radius)
                  var r = Math.sqrt(xv * xv + yv * yv)

                  // From http://www.davidcolarusso.com/astro/
                  // Modified to compensate for the right handed coordinate system of OpenGL
                  var xh = r * (Math.cos(N) * Math.cos(v + w)
                                - Math.sin(N) * Math.sin(v + w) * Math.cos(iPlanet))
                  var zh = -r * (Math.sin(N) * Math.cos(v + w)
                                 + Math.cos(N) * Math.sin(v + w) * Math.cos(iPlanet))
                  var yh = r * (Math.sin(w + v) * Math.sin(iPlanet))

                  // Apply the position offset from the center of orbit to the bodies
                  var centerOfOrbit = planet.centerOfOrbit
                  target.x = planets[centerOfOrbit].x + xh * Planets.auScale
                  target.y = planets[centerOfOrbit].y + yh * Planets.auScale
                  target.z = planets[centerOfOrbit].z + zh * Planets.auScale
              }
              // Calculate the rotation (roll) of the bodies. Tilt does not change.
              target.roll += (deltaTimeD / planet.period) * 360 // In degrees
          }

          function changeScale(scale, focused) {
              if (!ready)
                  return

              var scaling = setScale(scale, focused)
              sun.r = planetData[Planets.SUN].radius * scaling / 100
              mercury.r = planetData[Planets.MERCURY].radius * scaling
              venus.r = planetData[Planets.VENUS].radius * scaling
              earth.r = planetData[Planets.EARTH].radius * scaling
              earthClouds.r = planetData[Planets.EARTH].radius * scaling * 1.02
              moon.r = planetData[Planets.MOON].radius * scaling
              mars.r = planetData[Planets.MARS].radius * scaling
              jupiter.r = planetData[Planets.JUPITER].radius * scaling
              saturn.r = planetData[Planets.SATURN].radius * scaling
              saturnRing.outerRadius = saturnRingOuterRadius * scaling
              saturnRing.innerRadius = saturnRingInnerRadius * scaling
              uranus.r = planetData[Planets.URANUS].radius * scaling
              uranusRing.outerRadius = uranusRingOuterRadius * scaling
              uranusRing.innerRadius = uranusRingInnerRadius * scaling
              neptune.r = planetData[Planets.NEPTUNE].radius * scaling
          }

          function changeSpeed(speed) {
              daysPerFrameScale = speed
          }

          function changeCameraDistance(distance) {
              cameraDistance = distance
          }

          function animate(focusedPlanet) {
              if (!ready)
                  return

              advanceTime(focusedPlanet)
              for (var i = 0; i <= Planets.NUM_SELECTABLE_PLANETS; i++)
                  positionPlanet(i)

              updateCamera(focusedPlanet)
          }

          function updateCamera(focusedPlanet) {
              // Get the appropriate near plane position for the camera and animate it with QML animations
              var outerRadius = Planets.getOuterRadius(focusedPlanet)
              cameraNear = outerRadius
              camera.nearPlane = cameraNear
              light.near = cameraNear

              // Calculate position
              var cameraPosition = getNewCameraPosition(focusedPlanet, outerRadius)
              var cameraOffset = Qt.vector3d(xCameraOffset, yCameraOffset, zCameraOffset)
              cameraPosition = cameraPosition.plus(cameraOffset)

              // Calculate look-at point
              var lookAtPlanet = Planets.SUN
              if (focusedPlanet !== Planets.SOLAR_SYSTEM)
                  lookAtPlanet = focusedPlanet
              var cameraLookAt = Qt.vector3d(planets[lookAtPlanet].x,
                                             planets[lookAtPlanet].y,
                                             planets[lookAtPlanet].z)
              var lookAtOffset = Qt.vector3d(xLookAtOffset, yLookAtOffset, zLookAtOffset)
              cameraLookAt = cameraLookAt.plus(lookAtOffset)

              // Set position and look-at
              camera.viewCenter = cameraLookAt
              camera.position = Qt.vector3d(cameraPosition.x, cameraPosition.y, cameraPosition.z)
              camera.upVector = defaultUp
          }

          //
          // STARFIELD
          //

          Mesh {
              id: starfield
              source: "qrc:/meshes/starfield.obj"
          }

          Entity {
              id: starfieldEntity

              property Material materialStarfield: PlanetMaterial {
                  effect: effectD
                  ambientLight: ambientStrengthStarfield
                  specularColor: Qt.rgba(0.0, 0.0, 0.0, 1.0)
                  diffuseMap: "qrc:/images/galaxy_starfield.png"
                  shininess: 1000000.0
              }

              property Transform transformStarfield: Transform {
                  scale: 8500000
                  translation: Qt.vector3d(0, 0, 0)
              }

              components: [ starfield, materialStarfield, transformStarfield ]
          }

          //
          // SUN
          //

          Planet {
              id: sun
              tilt: planetData[Planets.SUN].tilt
          }

          Entity {
              id: sunEntity

              property Material materialSun: PlanetMaterial {
                  effect: effectD
                  ambientLight: ambientStrengthSun
                  specularColor: Qt.rgba(0.0, 0.0, 0.0, 1.0)
                  diffuseMap: "qrc:/images/sunmap.jpg"
                  shininess: 1000000.0
              }

              property Transform transformSun: Transform {
                  matrix: {
                      var m = Qt.matrix4x4()
                      m.translate(Qt.vector3d(sun.x, sun.y, sun.z))
                      m.rotate(sun.tilt, tiltAxis)
                      m.rotate(sun.roll, rollAxis)
                      m.scale(sun.r)
                      return m
                  }
              }

              components: [ sun, materialSun, transformSun ]
          }

          //
          // PLANETS
          //

          // MERCURY

          Planet {
              id: mercury
              tilt: planetData[Planets.MERCURY].tilt
          }

          Entity {
              id: mercuryEntity

              property Material materialMercury: PlanetMaterial {
                  effect: effectDB
                  ambientLight: ambientStrengthPlanet
                  specularColor: Qt.rgba(0.2, 0.2, 0.2, 1.0)
                  diffuseMap: "qrc:/images/mercurymap.jpg"
                  normalMap: "qrc:/images/mercurynormal.jpg"
                  shininess: shininessSpecularMap
              }

              property Transform transformMercury: Transform {
                  matrix: {
                      var m = Qt.matrix4x4()
                      m.translate(Qt.vector3d(mercury.x, mercury.y, mercury.z))
                      m.rotate(mercury.tilt, tiltAxis)
                      m.rotate(mercury.roll, rollAxis)
                      m.scale(mercury.r)
                      return m
                  }
              }

              components: [ mercury, materialMercury, transformMercury ]
          }

          // VENUS

          Planet {
              id: venus
              tilt: planetData[Planets.VENUS].tilt
          }

          Entity {
              id: venusEntity

              property Material materialVenus: PlanetMaterial {
                  effect: effectDB
                  ambientLight: ambientStrengthPlanet
                  specularColor: Qt.rgba(0.2, 0.2, 0.2, 1.0)
                  diffuseMap: "qrc:/images/venusmap.jpg"
                  normalMap: "qrc:/images/venusnormal.jpg"
                  shininess: shininessSpecularMap
              }

              property Transform transformVenus: Transform {
                  matrix: {
                      var m = Qt.matrix4x4()
                      m.translate(Qt.vector3d(venus.x, venus.y, venus.z))
                      m.rotate(venus.tilt, tiltAxis)
                      m.rotate(venus.roll, rollAxis)
                      m.scale(venus.r)
                      return m
                  }
              }

              components: [ venus, materialVenus, transformVenus ]
          }

          // EARTH

          Planet {
              id: earth
              tilt: planetData[Planets.EARTH].tilt
          }

          Entity {
              id: earthEntity

              property Material materialEarth: PlanetMaterial {
                  effect: effectDSB
                  ambientLight: ambientStrengthPlanet
                  diffuseMap: "qrc:/images/earthmap1k.jpg"
                  specularMap: "qrc:/images/earthspec1k.jpg"
                  normalMap: "qrc:/images/earthnormal1k.jpg"
                  shininess: shininessSpecularMap
              }

              property Transform transformEarth: Transform {
                  matrix: {
                      var m = Qt.matrix4x4()
                      m.translate(Qt.vector3d(earth.x, earth.y, earth.z))
                      m.rotate(earth.tilt, tiltAxis)
                      m.rotate(earth.roll, rollAxis)
                      m.scale(earth.r)
                      return m
                  }
              }

              components: [ earth, materialEarth, transformEarth ]
          }

          // EARTH CLOUDS

          Planet {
              id: earthClouds
              tilt: planetData[Planets.EARTH].tilt
          }

          Entity {
              id: earthCloudsEntity

              property Material materialEarthClouds: PlanetMaterial {
                  effect: effectDS
                  ambientLight: ambientStrengthClouds
                  diffuseMap: "qrc:/images/earthcloudmapcolortrans.png"
                  specularMap: "qrc:/images/earthcloudmapspec.jpg"
                  shininess: shininessClouds
                  opacity: 0.2
              }

              property Transform transformEarthClouds: Transform {
                  matrix: {
                      var m = Qt.matrix4x4()
                      m.translate(Qt.vector3d(earth.x, earth.y, earth.z))
                      m.rotate(earth.tilt, tiltAxis)
                      m.rotate(earth.roll / 1.2, rollAxis)
                      m.scale(earthClouds.r)
                      return m
                  }
              }

              components: [ earthClouds, materialEarthClouds, transformEarthClouds ]
          }

          // MOON

          Planet {
              id: moon
              tilt: planetData[Planets.MOON].tilt
          }

          Entity {
              id: moonEntity

              property Material materialMoon: PlanetMaterial {
                  effect: effectDB
                  ambientLight: ambientStrengthPlanet
                  specularColor: Qt.rgba(0.2, 0.2, 0.2, 1.0)
                  diffuseMap: "qrc:/images/moonmap1k.jpg"
                  normalMap: "qrc:/images/moonnormal1k.jpg"
                  shininess: shininessSpecularMap
              }

              property Transform transformMoon: Transform {
                  matrix: {
                      var m = Qt.matrix4x4()
                      m.translate(Qt.vector3d(moon.x, moon.y, moon.z))
                      m.rotate(moon.tilt, tiltAxis)
                      m.rotate(moon.roll, rollAxis)
                      m.scale(moon.r)
                      return m
                  }
              }

              components: [ moon, materialMoon, transformMoon ]
          }

          // MARS

          Planet {
              id: mars
              tilt: planetData[Planets.MARS].tilt
          }

          Entity {
              id: marsEntity

              property Material materialMars: PlanetMaterial {
                  effect: effectDB
                  ambientLight: ambientStrengthPlanet
                  specularColor: Qt.rgba(0.2, 0.2, 0.2, 1.0)
                  diffuseMap: "qrc:/images/marsmap1k.jpg"
                  normalMap: "qrc:/images/marsnormal1k.jpg"
                  shininess: shininessSpecularMap
              }

              property Transform transformMars: Transform {
                  matrix: {
                      var m = Qt.matrix4x4()
                      m.translate(Qt.vector3d(mars.x, mars.y, mars.z))
                      m.rotate(mars.tilt, tiltAxis)
                      m.rotate(mars.roll, rollAxis)
                      m.scale(mars.r)
                      return m
                  }
              }

              components: [ mars, materialMars, transformMars ]
          }

          // JUPITER

          Planet {
              id: jupiter
              tilt: planetData[Planets.JUPITER].tilt
          }

          Entity {
              id: jupiterEntity

              property Material materialJupiter: PlanetMaterial {
                  effect: effectD
                  ambientLight: ambientStrengthPlanet
                  specularColor: Qt.rgba(0.2, 0.2, 0.2, 1.0)
                  diffuseMap: "qrc:/images/jupitermap.jpg"
                  shininess: shininessBasic
              }

              property Transform transformJupiter: Transform {
                  matrix: {
                      var m = Qt.matrix4x4()
                      m.translate(Qt.vector3d(jupiter.x, jupiter.y, jupiter.z))
                      m.rotate(jupiter.tilt, tiltAxis)
                      m.rotate(jupiter.roll, rollAxis)
                      m.scale(jupiter.r)
                      return m
                  }
              }

              components: [ jupiter, materialJupiter, transformJupiter ]
          }

          // SATURN

          Planet {
              id: saturn
              tilt: planetData[Planets.SATURN].tilt
          }

          Entity {
              id: saturnEntity

              property Material materialSaturn: PlanetMaterial {
                  effect: shadowMapEffectD
                  ambientLight: ambientStrengthPlanet
                  specularColor: Qt.rgba(0.2, 0.2, 0.2, 1.0)
                  diffuseMap: "qrc:/images/saturnmap.jpg"
                  shininess: shininessBasic
              }

              property Transform transformSaturn: Transform {
                  matrix: {
                      var m = Qt.matrix4x4()
                      m.translate(Qt.vector3d(saturn.x, saturn.y, saturn.z))
                      m.rotate(saturn.tilt, tiltAxis)
                      m.rotate(saturn.roll, rollAxis)
                      m.scale(saturn.r)
                      return m
                  }
              }

              components: [ saturn, materialSaturn, transformSaturn ]
          }

          // SATURN RING

          Ring {
              id: saturnRing
              innerRadius: saturnRingInnerRadius
              outerRadius: saturnRingOuterRadius
          }

          Entity {
              id: saturnRingEntity

              property Material materialSaturnRing: PlanetMaterial {
                  effect: shadowMapEffectD
                  ambientLight: ambientStrengthRing
                  specularColor: Qt.rgba(0.01, 0.01, 0.01, 1.0)
                  diffuseMap: "qrc:/images/saturnringcolortrans.png"
                  shininess: shininessBasic
                  opacity: 0.4
              }

              property Transform transformSaturnRing: Transform {
                  matrix: {
                      var m = Qt.matrix4x4()
                      m.translate(Qt.vector3d(saturn.x, saturn.y, saturn.z))
                      m.rotate(saturn.tilt, tiltAxis)
                      m.rotate(saturn.roll / 10, rollAxis)
                      m.scale((saturnRing.innerRadius + saturnRing.outerRadius) / 1.75)
                      return m
                  }
              }

              components: [ saturnRing, materialSaturnRing, transformSaturnRing ]
          }

          // URANUS

          Planet {
              id: uranus
              tilt: planetData[Planets.URANUS].tilt
          }

          Entity {
              id: uranusEntity

              property Material materialUranus: PlanetMaterial {
                  effect: shadowMapEffectD
                  ambientLight: ambientStrengthPlanet
                  specularColor: Qt.rgba(0.2, 0.2, 0.2, 1.0)
                  diffuseMap: "qrc:/images/uranusmap.jpg"
                  shininess: shininessBasic
              }

              property Transform transformUranus: Transform {
                  matrix: {
                      var m = Qt.matrix4x4()
                      m.translate(Qt.vector3d(uranus.x, uranus.y, uranus.z))
                      m.rotate(uranus.tilt, tiltAxis)
                      m.rotate(uranus.roll, rollAxis)
                      m.scale(uranus.r)
                      return m
                  }
              }

              components: [ uranus, materialUranus, transformUranus ]
          }

          // URANUS RING

          Ring {
              id: uranusRing
              innerRadius: uranusRingInnerRadius
              outerRadius: uranusRingOuterRadius
          }

          Entity {
              id: uranusRingEntity

              property Material materialUranusRing: PlanetMaterial {
                  effect: shadowMapEffectD
                  ambientLight: ambientStrengthRing
                  specularColor: Qt.rgba(0.01, 0.01, 0.01, 1.0)
                  diffuseMap: "qrc:/images/uranusringcolortrans.png"
                  shininess: shininessBasic
                  opacity: 0.4
              }

              property Transform transformUranusRing: Transform {
                  matrix: {
                      var m = Qt.matrix4x4()
                      m.translate(Qt.vector3d(uranus.x, uranus.y, uranus.z))
                      m.rotate(uranus.tilt, tiltAxis)
                      m.rotate(uranus.roll / 10, rollAxis)
                      m.scale((uranusRing.innerRadius + uranusRing.outerRadius) / 1.75)
                      return m
                  }
              }

              components: [ uranusRing, materialUranusRing, transformUranusRing ]
          }

          // NEPTUNE

          Planet {
              id: neptune
              tilt: planetData[Planets.NEPTUNE].tilt
          }

          Entity {
              id: neptuneEntity

              property Material materialNeptune: PlanetMaterial {
                  effect: effectD
                  ambientLight: ambientStrengthPlanet
                  specularColor: Qt.rgba(0.2, 0.2, 0.2, 1.0)
                  diffuseMap: "qrc:/images/neptunemap.jpg"
                  shininess: shininessBasic
              }

              property Transform transformNeptune: Transform {
                  matrix: {
                      var m = Qt.matrix4x4()
                      m.translate(Qt.vector3d(neptune.x, neptune.y, neptune.z))
                      m.rotate(neptune.tilt, tiltAxis)
                      m.rotate(neptune.roll, rollAxis)
                      m.scale(neptune.r)
                      return m
                  }
              }

              components: [ neptune, materialNeptune, transformNeptune ]
          }
      }