title: Generated SLERP paths not coplanar with the sphere's origin, but both SceneKit and OpenGL routines produce the same result
body: <p>I am trying to generate paths between points in the surface of a sphere in SceneKit.</p>
  
  <p>I currently place "beacons" at the start and end coordinates, and then I use <code>GLKQuaternionSlerp</code> to calculate the intermediate points.</p>
  
  <p>To calculate the rotation quaternions for coordinates I use the following formula:</p>
  
  <pre><code>// Computed variable in the GlobeCoordinates struct
  var quaternion: GLKQuaternion
  {
      let lat = self.latitude * Deg2Rad * -1
      let lon = self.longitude * Deg2Rad
  
      let qlat = GLKQuaternionMakeWithAngleAndAxis(lat, 1, 0, 0)
      let qlon = GLKQuaternionMakeWithAngleAndAxis(lon, 0, 1, 0)
  
      return GLKQuaternionNormalize(GLKQuaternionMultiply(qlon, qlat))
  }
  </code></pre>
  
  <p>This is very consistent with what's produced by SceneKit when the <code>eulerAngles</code> are used instead, so I believe this formula is correct. Then, I use the following algorithm to interpolate and place nodes at sampled points on the SLERP curve:</p>
  
  <pre><code>let sampleCount = 32
  for sampleIndex in 0..&lt;sampleCount
  {
      let sampleQuaternion = GLKQuaternionSlerp(startQuaternion, endQuaternion, Float(sampleIndex)/Float(sampleCount))
  
      let ballGeometry = SCNSphere(radius: 0.6)
      ballGeometry.materials = [ballMaterial]
  
      let ballNode = SCNNode(geometry: ballGeometry)
  
      // The planet radius is 100 units, so we translate the sphere 100 units on the Z axis.
      // We use the Z axis so that the sphere appears at the geographical coordinates (0, 0)
      // when no rotation is applied to it. These are local coordinates to the ball "pole" node.
      ballNode.position = SCNVector3(0, 0, 100)
  
      let ballPoleNode = SCNNode()
      ballPoleNode.addChildNode(ballNode)
  
      // We apply the quaternion to this node because it never leaves the planet center vertex, so the resulting
      //  effect is that the ball "orbits" the planet
      ballPoleNode.orientation = sampleQuaternion.scnQuaternion
      planet.addChildNode(ballPoleNode)
  }
  </code></pre>
  
  <p>This is the result:</p>
  
  <p><a href="https://i.stack.imgur.com/yaIAz.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/yaIAz.jpg" alt="SLERP result"></a></p>
  
  <p>At first it looks correct, but if you pay attention you'll see the path plotted by the slerp routine is not coplanar with the planet's origin. And it is also much longer than the shortest path.</p>
  
  <p>To prove this I manually placed a torus centered at the planet's origin and with the same radius as the planet, and rotated it such that it touches both the start and end coordinates, which is the great circle that is defined by the coordinates. This is what it looks like:</p>
  
  <p><a href="https://i.stack.imgur.com/8kSCK.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/8kSCK.jpg" alt="Torus representing the great circle between the coordinates"></a></p>
  
  <p>Therefore it is obvious something is very wrong. However, having all quaternions centered at the planet's origin, how can the calculated slerp be wrong? I fail to find the problem with my algorithm, but I also have little experience with 3D graphics programming.</p>