0

Using OpenGL as a rendering engine I'm attempting to generate a rotation matrix that will sit a mesh on the surface of a sphere at a given position. Initially I'd attempted to do this by calculating the spheres surface normal at the given position and using that as my meshes up vector.

This worked, but things are complicated by the fact that I'd also like to be able to rotate the mesh with absolute yaw, pitch and roll values - where a yaw of 0 will always leave the mesh pointing upwards (0, 1, 0) in a northern direction.

I have a mental block on how to achieve this and would appreciate any input.


Update with solution provided by Ripi2:

let earthAxisOfRotation = Vector3(0, 1, 0).normalized() // south -> north pole is `up` in world space
let surfaceNormal = position.normalized() // surface normal of the given position on sphere surface

let east = earthAxisOfRotation.cross(surfaceNormal).normalized()
let north = surfaceNormal.cross(east)

let rotationMatrix = Matrix4(
    east.x, east.y, east.z, 0,
    surfaceNormal.x, surfaceNormal.y, surfaceNormal.z, 0,
    -north.x, -north.y, -north.z, 0,
    0, 0, 0, 1
)
ndg
  • 2,585
  • 2
  • 33
  • 58
  • Your idea seems rigth to me. It's the same as defining a "lookAt" matrix (without the translation part), with the normal to sphere being "up" and the axis of rotation of the sphere (as for Earth) being the "eye-target" vector. What's your issue? – Ripi2 Mar 29 '17 at 22:24
  • I'm essentially failing to achieve the meshes being oriented in the upward direction. They're correctly positioned, but their 'forward' vectors will differ based on their position on the sphere. What you're suggesting seems to make sense, but I believe it's the calculation of the eye-target vector that I'm struggling with. Could you clarify what you mean by "the axis of rotation of the sphere?" – ndg Mar 29 '17 at 23:35

1 Answers1

2

Let's work on an "Earth". Its axis of rotation (r) goes from south pole to north pole. A normal (n) to the surface goes "out" of Earth.

The cross product e= r x n gives a vector heading east.
The cross product d= n x e gives a vector heading north.

With normalized versions of e, n, d and translating to the point in the surface you can construct a lookAt matrix (see here).
up = n and f= center-eye = d and s = e. Notice you may want to change f sign because this is not a real 'lookAt' transform, it doesn't look at, but just locates.

Now, if your mesh can be considered as another sphere concentric with the first sphere, all rotations must be over the shared center of both spheres. The axis of rotation, keeping always the "heading north" can be the "Earth axis" (r) and the "heading east" (e). When using 'e' you lose somehow north, vector goes "inside" the sphere. Angles can be computed from cross product, due to if c= a x b then |c| = |a|·|b|·sin(beta).

Community
  • 1
  • 1
Ripi2
  • 7,031
  • 1
  • 17
  • 33
  • Thank you for the detailed write-up, this seems to be working! I've included some pseudo-code in my original question for people with similar issues. Perhaps the only aspect of your answer I wasn't able to follow was with regards to your comment about losing north and having the vector go "inside" of the sphere. Could you clarify at all? – ndg Mar 30 '17 at 13:03
  • If you rotate over "east" vector located at surface, then the "north" vector spins towards the center of the sphere. The "normal" would also lose its perpendicular to surface property. To avoid this issue, rotate over "east", but located at the center of the sphere. – Ripi2 Mar 30 '17 at 14:53