# Calculating rotation matrix for an object relative to a planets surface in MonoGame

I have a 3D planet and I would like to place models on the planet and have them start with a base rotation relative to the planet surface at their location. So a model at the north pole will have zero rotation, and one at the south pole will be upside down etc.

I have some code that kind of works but not very well so i guess that there are errors with the math. I'm trying to calculate the Pitch based on the angle between the location and Y axis, and the Roll based on the angle between the location and X axis.

public Matrix CalculateBaseRotation(Vector3 vLocation)
{
// Calculate Up Direction (Assumes planet position is Vector.Zero)
Vector3 WorldUp = Vector3.Normalize(vLocation);

// Compute Dot Products relative to Y and X axis
float Dot_A = Vector3.Dot(Vector3.UnitY, WorldUp);
float Dot_B = Vector3.Dot(Vector3.UnitX, WorldUp);

// Calculate Angles From Dot Products
float Angle_A = (float)Math.Acos(Dot_A);
float Angle_B = (float)Math.Asin(Dot_B);

// When Z is negative, invert Angle A to prevent curve following S pattern
// This seems hackish, there must be a more mathematically elegant solution
if (WorldUp.Z < 0)
Angle_A = MathHelper.TwoPi - Angle_A;

// Invert Arc Of AngleB
if (WorldUp.Y > 0)
Angle_B = MathHelper.TwoPi - Angle_B; // Keeps curve to planet surface
else
Angle_B = Angle_B + MathHelper.Pi; // Prevent flipping upside down in southern hemisphere

// Clamp Angles
Angle_A = MathHelper.WrapAngle(Angle_A); // PITCH
Angle_B = MathHelper.WrapAngle(Angle_B); // ROLL

// Create Base Rotation Matrix
// AngleA Should Be Second, AngleB Should Be Third
return Matrix.CreateFromYawPitchRoll(0, Angle_A, Angle_B);
}

• Just to clarify, you're trying to go from 3D world coordinates on the surface of a sphere (relative to the center of that sphere), to a local rotation matrix such that your model is always upright relative to the centre of the sphere. Correct? – Yousef Amar Dec 2 '15 at 1:02
• Can you elaborate on what you mean by "kind of works"? Does it work at any of the poles? What exactly happens when it isn't working? – Chris Mills-Price Dec 2 '15 at 1:15
• @Paraknight yes, thats correct – Snowpaw Dec 3 '15 at 1:39
• @ChrisMills-Price Im also using the rotation for the camera and when it moves side to side the camera dips and points down, when it gets to the poles on the X axis it starts to flicker. Its a bit disorientation trying to see what is happening exactly when the cameras view flickers or jumps. – Snowpaw Dec 3 '15 at 1:44

Something like this is often easier if you avoid using angles.

The following assumes you know the world coordinates of the center of the planet and the world coordinates of the location on the planet surface that you want to place the object .

Matrix GetWorldMatrixForModel(Vector3 surfaceLocation, Vector3 planetCenter)
{
Vector3 modelUp = Vector3.Normalize(surfaceLocation - planetCenter);
Vector3 tempCross = Math.Abs(Vector3.Dot(modelUp, Vector3.Up)) > 0.1 ?   Vector3.Up : Vector3.Right;
Vector3 modelRight = Vector3.Normalize(Vector3.Cross(ModelUp, tempCross));
Vector3 modelForward = Vector3.Cross(modelUp, modelRight);

Matrix modelWorld;
modelWorld.Up = modelUp;
modelWorld.Right = modelRight;
modelWorld.Forward = modelForward;
modelWorld.Translation = surfaceLocation;

return modelWorld;
}

• Thanks for the solution Steve, at first it wouldn't work but after I swapped the up and right vectors round in the calculation of tempCross it worked quite well. There is still some problems in the southern hemisphere and also when moving close to the X axis of the planet it will flicker between two very different views. Also at times it seems to rotate around the X axis as i move the camera sideways. As well as using the rotation for mesh, I am also using it for a FPS camera to follow the surface so any way to prevent the spiral effect at the poles on the x axis would be important. – Snowpaw Dec 3 '15 at 1:50
• I managed to fix the problems with poles and moving into the southern hemisphere by keeping a reference to the last rotation and using that as a reference when updating the matrix. Marking as resolved. Thanks :) – Snowpaw Dec 7 '15 at 5:12