Confused about rotations

Hey guys,
I have been struggling for a while now with rotating a Navball for my spaceship game. It looks a bit like this:

I have tried everything I can think of to get this to show the ships current rotation, but I have to admit defeat. The best I’ve gotten so far is that it works correctly around the Y axis, but the X and Z were in the wrong direction. Note that the ball is not stationary in world space, it rotates in the same direction to the one the ship is rotating in.

In the screenshot, the ship has just rotated from (0,0,0) 30 degrees around the Y axis (yaw to the right). The ball has not only rotated with the ship, but has rotated a further 30 to show the value of 30 on its display. This is the only bit that works correctly :frowning: It all turns to poo when I start rotating on the other axes.

For example, if I now pull my joystick back, to pitch up (rotate around the ships local X), I can’t get the navball to do the same, since it’s X is no longer parallel with the ships X.

Can some kind hearted soul please explain to me how I get this to work correctly?

What’s the code you got so far?

Is this thing a child of the spaceship? Have you considered just setting its global rotation to Quaternion.identity, so this way it’s local rotation relative to the ship would be oriented to the global norm. So essentially relatively speaking, you’d see the inverse of the ships current rotation.

2 Likes

I think you want the ball to not rotate.
For the ball if its the child of the ship…

void Update ()
    {
        this.transform.rotation = Quaternion.identity;
    }

with the right texture on it it should show the right direction.

Sry @ lord did only read the first line you already told it …

2 Likes

Yes the ball is a child of the ship. And nope, the ball cannot remain stationary in world space, it must rotate. If it is stationary in world space some of the rotations shown on it move in the wrong direction. And the direction it rotates in must be correct, i cant just flip the texture. When the ship rotates around its local Y to the right, the ball must rotate around its local Y to the right too, because that’s how these displays work… If the ball is stationary in world space (which I’ve managed) it will be displaying the inverse of the ships Y rotation, not the ships Y rotation. And I can get this working on one axis but when I start to do more complex than just rotating on Y it is very obviously wrong. The pitch and yaw seem to exchange based on how far i rotate around Y.

I don’t have any significant code, I’ve just been doing things like applying the ships euler angles to the balls local euler angles, applying the inverse of the ships euler angles, and various combinations.

Technically this is precisely how a gyroscopic attitude indicator works. The gyros hold it fixed while the airplane rotates around it. Obviously the ball moves POSITION with the airplane, but an ideal AI would never change its orientation.

Assuming your ship is changing its orientation you actually DO want the AI ball to stay completely fixed in orientation in space, especially since you have compass (longitudinal) markers on it too. North will always be north, up will always be up on the ball.

2 Likes

^ What Kurt said.

If that’s NOT what you want.

Then you need to define for us the behaviour you expect.

Technically, the gyroscopes are not located inside the ball. They are separate equipment, and the ball is only used to indicate attitude. It indicates pitch and yaw by rotating so that the central point appears to track along the balls surface in the same direction as it does in space. If I pitch the nose up, I expect the numbers on the ball to move from top to bottom, showing more of the light side of the ball. By the time the ship is rotated to point straight up, the ball should be showing all the light colored side.

If the ball is made to be stationary in world space, the opposite happens. As you pitch up, you would see more of the ball from underneath, not above.
The ball should be interpreted as if the balls normals are all flipped, and you view the inside surface of the sphere as the fixed stationary skybox, but of course that isn’t possible in reality.

The ball appears stationary in world space on the roll axis only, since the equator of the ball works as an artificial horizon.

It may be hard to see in the image, but if the north (zero yaw) line is in the center of the display, 90 degrees (east) is to the right. If the ball is stationary and the ship rotates from north to east, using the current, correct texturing) the West 270 line would become visible, moving in from left to right… What really should happen is that the ship rotates around to 90, and the ball follows along since it’s a child of the ship, also rotating to world space 90. To display the angle, the ball is required to rotate a further 90, bringing the East line in from right to left (as everything outside is apparently moving right-to-left, too.

Hope that explains the problem better. I am 100% certain that the direction of rotation for pitch and yaw are backwards if the ball is stationary, but I’m running into problem determining pitch from yaw once i have rotation on more than one axis.

Put another way, if the ship pitches up, the ball should apparently rotate its texturing from top to bottom, showing more of the light side. If the ship yaws right, the texture should rotate right to left, showing 3, then 6, then 9, then 12… If the ship rolls clockwise, the texture rotates anti-clockwise. All these ship rotations are relative to its current attitude… i think some of my problem is that the axes the ball rotates around are actually rotating. Pulling the joystick back, ie pitching the ships nose up, is always indicated by a rotation so the texture moves from the top of the control panel to the bottom, which is a rotation around an axis parallel with the face of the control panel, but as soon as i yaw the ball, that axis is moving. I am unable to rotate the ball as if it is driven by little wheels in the top and side of the control panel, ie, the axis to rotate around is always fixed in the ships coordinate space, and if I could do that, how would the ships world orientation correspond to the required ball input angles?

Attitude indicators don’t directly indicate what the internal gyro is rotating to. indeed a gyro would try to keep the same rotation (along its spinning axis) but the display would show the inverse of that. depending on the indicator (ones which hold the gyro in a ladle), some completely wonk out if you try to do a loop causing them to flail wildly (as you broke the gryo’s precession).

@Innovineit, it appears your indicator is a simple ball attitude. You can likely get away with just grabbing the plane’s world rotation setting it as the indicator’s local rotation on update. the result should appear as you desired.

Dude, I appreciate the attempt to help, but i just wrote a huge wall of text explaining why that is not the solution…

I don’t think they said what you think they said.

He’s talking about getting the world rotation of the ship and setting it as the local rotation of the indicator. So if the ship rotates to, say, -90 on Y the indicator will now be -90 on Y in local space and -180 on Y in world space.

This solution assumes that the ship model is aligned with its own local space (ie: if you just drop the model in Unity, do the “forward”, “up” and “right” directions of the ship line up with the Z+, Y+ and X+ axes of the gizmo when it’s selected?) and that there are no other rotated transforms in the hierarchy between them. Though even in those cases you can still calculate the rotation you need (see the Transform class).

That could easily be the case, this stuff is really difficult to put into words!!

I have tried this:

navball.transform.localEulerAngles = ship.transform.eulerAngles;

This definitely does not work as desired. It initally works ok when just rotating around Y, but as soon as any other rotation comes in it goes wrong. I am not at my Unity project to test it again but it was one of the things I tried. I think it also gets really out of whack if rotating on multiple axes. I also tried this with quaternions instead of euler angles, but I am unsure if i did it right. I think maybe it was working but didn’t work past 180 degrees? I’ll try again after work and report the exact code and result.

I believe this is the case, but I’m also exporting from blender to unity and sometimes the fbx’s are a bit confused. From what I remember, the scales in every step of the hierarchy were 1, and the rotations were all 0’s. I do have a vague memory of the Z pointing the wrong way for one of the objects, another thing i will definitely have to check out…

So I don’t know how navballs work. Not a pilot, nor do I play flight sims. I just assumed it was a gyroscope.

Which is why I asked for a definition.

What I do know though, is rotations.

And thanks for the definition.

So for starters I avoid euler angles like the plague because they just don’t work well with the maths. Especially when trying to unravel information like this. You need to concern yourself with the order unity puts the euler angles together (yaw->pitch->roll? Is it pitch->yaw->roll? What is it? I don’t know… I don’t care, I don’t want to care. I just avoid them because they’re the devil regardless).

So…

Based on your definition, and some videos I looked at, I take you to mean:

yaw is the inverse measure of your forward off of global forward (north in real world terms), as projected onto the ground (redact y information).

pitch is the inverse measure of your ships forward against the ground, which can be defined as a vector in the direction of that flattened forward we used for yaw

Which means we’d get:

    [SerializeField]
    private Transform ship;

    [SerializeField]
    private Transform navball;
 
    private void Update()
    {
        var forw = this.ship.forward;
        forw.y = 0f;
        if (forw.sqrMagnitude > 0.0001f) forw.Normalize();

        var yaw = -Vector3.SignedAngle(forw, Vector3.forward, Vector3.up);
        var pitch = Vector3.SignedAngle(forw, this.ship.forward, this.ship.right);

        var rot = Quaternion.AngleAxis(pitch, Vector3.right) * Quaternion.AngleAxis(yaw, Vector3.up);
        this.navball.localRotation = Quaternion.Slerp(this.navball.localRotation, rot, 0.5f); //used a little slerp to give a smoother look
    }

Resulting in something like this:
3476154--276285--Navball.gif

Is that what you described?

What I did was used some trig to calculate the angles around each (I used unity’s built in function for it… it’s actually not 100% accurate, they have optimizations done on it to speed it up which loses a tiny bit of accuracy. But it’s fine, and it’s better than me writing all the trig. Anyways, if you sanitize the inputs before hand the inaccuracies pretty much disappear, which I do.)

And with those angles around their respective axes I create Quaternion’s around the appropriate axes for pitch and yaw (right and up respectively), and set it to the local rotation.

Ooo, squeeeee! That is looking exactly as I meant…

Does it continue to work if you roll over sideways? :slight_smile: If you roll over 90 (at any yaw value) so the horizon appears vertical on the screen, the sphere should also be divided vertically (relative to the screen) down the middle, with the black on the ground side. In this position, if you pitch up and down, that division between the hemispheres stays where it is, with the ball rotating so the light hemisphere stays on one side, and the dark on the other. The vehicle will be rotating around the world vertical axis, you see the ground out one side and the sky on the other the whole time you rotate, and the navball reflects this by having the ground hemisphere on one side and the sky on the other.

Sorry if my terminology is confusing, I am struggling very much to convey what I mean here :slight_smile:

I’m sorry but I am not sure I follow this, and am not sure if it is correct… The pitch isn’t related to the ground as far as I can tell. If you are in a plane and you pull the joystick back towards yourself (pitching up), the plane rotates around the axis running through the wings. It will do this no matter which world orientation the plane is currently in (ignoring aerodynamic forces for simplicity). So for example… If you are flying parallel to the ground, right way up, and in any compass direction, when you pull the stick back to pitch up the nose goes up towards the sky and the aircraft gains altitude. More of the sky hemisphere of the navball becomes visible, exactly as you demonstrate in your video.

But if you do this when flying parallel to the ground but wrong side up, and you again pull the stick back towards yourself, now the nose goes down towards the ground and you lose altitude. But in both cases the navball will rotate around the axis through the wings, and with more of the top portion becoming visible. If I am flying up to the sky, I’ll see more of the light hemisphere coming into view. If I was inverted (rolled 180) the ground hemisphere will be on the upper part (relative to the screen) and more of the ground will come into view, from the top, relative to the screen. Is this the same as your statement? :slight_smile:

Finally, if you are flying on your side, one wing pointing directly down and one pointing directly at the sky zenith, (not a position you’ll remain flying in very long…) and you pull back the stick, you will rotate through all the compass values, but the nose will remain pointed at the horizon, and again the navball rotates in the same way, with more texture appearing from the top (relative to the screen).

Well for starters, it’d be trivial to give a try yourself and see if it acts as you believe.

As for what you say though… if I interpret what you say correctly, no, it would not behave in that manner.

So if like you’re upside down, it should act the same as if you were right side up. Hrmmm… how does… OHHHHHH. I get it, ok ok, it IS based on a gyroscope. But the gyroscope is bolted to the plane!

DERP!

I mean, of course it is… where the hell else would it be bolted?

lol

[edit]
OK, so this actually creates a problem. This means your navball isn’t actually based on orientation. This means your navball is the result of consecutive accelerative forces over time. Which explains its wobbily motion in the videos I’m watching.

I’m stuck at work for the next 6 hours, and THEN!! oh believe me I can’t wait to get home.

Isn’t it great when things click like that and it starts to make sense :slight_smile:
The gyroscope is feeding the navball the rotations, but the navball itself is rotating in a different way, so that it’s movements match the movements of the scenery outside.

I sure picked a hell of a starter project to learn this with.

It’s 5am here, and I’m a bit drunk… so yeah you might have to wait for me to wake up again to come back to this.

But I’ll be back later to see how this goes.

Great, get some sleep, and we’ll check it out later. Your help is massively appreciated, thanks!!!

In reality yes, it’s using the gyroscopes to sense rotation, but since the point is to show the pilot the vessels orientation in world space, a perfect navball has an exact 1-1 mapping from the vessels world space orientation to navball position. If only I could figure out what it is…

So before I go to bed I decided to come back in here and write up the foundation of what it was I was talking about.

Note though, due to float error it’d accumulate float error over time and slowly get out of whack. But this is the basic foundation of what I presume you mean.

As I said, this isn’t based on any specific orientation (hence why all attempts up to now don’t work). It’s based on accumulated rotation over time.

Now maybe there is a way to 1-1 map this to world space orientation. But that doesn’t sound right to me. As you stated that the rotation is based of its own rotation around its own wings… and not relative to the ground. If it’s not relative to the ground, that means it’s not an actual orientation. Orientations are by definition relative to something. This is why when it flips to the side or upside down it’d act in the manner as you describe… it’s motion is relative to itself.

Which makes sense to the engineering of it. If you have a gyroscope attached to a rigid body, and you want to measure orientation. Then you aren’t actually caring about gravity (which was all of our original suggestion… using gravity to determine information… orienting relative to the world). But instead you’d use the gravity to suss out the pull occurring on the body by gravity.

Mind you I’m slammered right now.

So maybe my brain is working backwards.

Anyways:
3476217--276293--Navball.gif

I think this is what you described. And if my assumptions about the physics of it make sense, this should be it.

Code:

using UnityEngine;

public class Navball : MonoBehaviour
{

    #region Fields

    [SerializeField]
    private Transform ship;

    [SerializeField]
    private Transform navball;

    private Quaternion _last;

    #endregion

    #region CONSTRUCTOR

    private void Start()
    {
        this.ResetNavball();
    }

    #endregion

    #region Methods

    public void ResetNavball()
    {
//this is naive, resetting would require some heavier calculations about where north is, 
//and to adjust for if the ship is currently pitched or rolled
//basically this needs to be called with the ship sitting at normal orientation in its current state
//I'm assuming a plane probably does this at startup as well, auto calibrating its initial orientation
        navball.localRotation = Quaternion.identity;
        _last = ship.rotation;
    }

    private void Update()
    {
        var delta = Quaternion.Inverse(_last) * ship.rotation;
        navball.localRotation = delta * navball.localRotation;
        _last = ship.rotation;
    }

    #endregion

}

Tomorrow when I’m more coherent I may see how this relates to orientation. But I really don’t think it will. Or well… I mean we could suss it out by just storing the initial rotation at the start and measure the delta from that…

Maybe that’d work?

Nah, that’d make the pitch relative to the world again, not itself.

1 Like

Looks nice, the pitch and yaw are correct but the roll is backwards :slight_smile: