Note: I am using the Unity DOTS ECS framework, which contains less maths functions, but I can probably implement the same functions from standard unity if the code is public. This question is not specific to unity though, I think.
I'm trying to have a player be able to run around the inside of a sphere such that their local up direction is always pointing at the centre of the sphere. So, when they run "forward" they naturally run in an orbit around the sphere surface.
I already have an artificial gravity system implemented, that applies a force pushing the player towards the sphere walls.
I calculate the new up direction, and then calculate the new forward direction from that. Feeding these into the built-in quaternion.LookRotation(newForward, newUp) function does orient my player towards the centre, but this also updates the local y-axis rotation of the player, meaning I can't turn the player, and it spins around when you cross each hemisphere.
float3 centerDir = math.normalize(sphereCenter.Value - translation.Value);
quaternion newRotation = rotation.Value;
float3 newUp = centerDir;
float3 newForward = mathx.Forward(newUp);
newRotation = quaternion.LookRotation(newForward, newUp);
rotation.Value = newRotation;
I then tried to negate the Y axis rotation by trying to find the difference in y axis rotation, and multiplying the rotation by another quaternion rotated on Y only by the negative of this angle. But I'm pretty sure I have the wrong vectors in my calculation to find this angle.
This had some success, but the player starts 90 degrees rotated and did strange things as I moved near to the axes. Where forward would bend towards the axis and start spinning.
float3 centerDir = math.normalize(sphereCenter.Value - translation.Value);
quaternion newRotation = rotation.Value;
float3 newUp = centerDir;
float3 newForward = mathx.Forward(newUp);
newRotation = quaternion.LookRotation(newForward, newUp);
float angleDiff = mathx.Angle(ltw.Forward, newForward);
quaternion negateYRotation = quaternion.RotateY(-angleDiff);
rotation.Value = math.mul(newRotation, negateYRotation);
I've been banging my head against a wall for days with this. I even tried converting all of the quaternions into Euler angles and setting the y angle to the original y angle, but this also affects the other angles so the player is no longer oriented correctly. (I assume this might be to do with the z axis being applied after the y axis).
Any help with this would be much appreciated.