Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Spacecraft Nav Orientation Widget Dyslexia

Discussion in 'Scripting' started by ippdev, May 24, 2023.

  1. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,791
    I have two spherical widgets of XYZ rings and axes. The spacecraft sphere has a Quaternion.Identity rotation, or is static and the other sphere is the absolute coords.The trick is that the relative coords are the ship and the absolute coords the world space coords.. But the ship widget always faces forward from the pilots POV and the absolute coords revolve in inverse about the pilot. I am using the Quatenrion.Inverse rotation of the actual spacecraft to drive the wold space coords widget. I think it looks correct but I also think one of the axes may be reversed or my programmers dyslexia is kicking in. Is this the proper approach for inverting relative to absolute coords?
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,769
    I think you may have it reversed, or maybe overcomplicated? The world sphere should probably be tethered to a world rotation (such as Quaternion.identity) and the ship's sphere probably doesn't have to do anything and just remain stationary, leading to the impression of movement as the world sphere rotates itself to match the world orientation.

    Depends on the specifics as my brain immediately thinks of something like Kerbal Space Program's little sphere widgets right now.
     
  3. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,317
    I started writing this, and it turned into a wall off text.

    Long story short, if you're trying to reimplement Elite Dangerous navigation widget and are talking about target hologram displayed on the left, then the ghost ship orientation is global orinetation of the target multiplied by INVERSE global orinetation of your ship.

    upload_2023-5-24_4-49-2.png

    If you're talking about about the ship miniature on the right, then there's no "north" in space, so you can't orient it, but could use it to indicate how fast you're turning. For that you could take global orientation of your ship and multiply it by, from, say, INVERSE of global ship orientation from 0.2 seconds ago. Or you could extract angular velocity from physics, convert it to local space, and use that for ship rotation display, after scaling down angle to some small value.

    Overall, in this situaiton it may be easier to deal with vectors instead of quaternions. Because vectors are intuitively understood, and with quaternions, you need to rack your brain trying to remember if their rotational order combines from left to right or right to left. I.e. when multiplying two quaternions which one is parent transform, which multiplication moves results in which coordinate system. The confusion about "which one is local transform" originates from the mess created when matrix multiplications were implemented in videogames. Basically OpenGL uses columns to store matrix vectors, but stores matrices as column major. DirectX uses rows to store matrix components, and it is row major. That results in the same layout in memory, but adds confusion, because "on paper" multiplication has different order and layout.

    Below some explanation regarding standard widgets in flightsims and coordinate systems.

    Basically, let's say you have vectors for position, right (x), up(y), andforward(z) for your ship.

    To convert point P from world to local, you do this:

    Code (csharp):
    1.  
    2. diff = pWorld - pos;
    3. pLocal = vec4(dot(diff, x) , dot(diff, y), dot(diff, z));
    4.  
    And to convert from local to world you do:
    Code (csharp):
    1.  
    2. pWorld = pos + pLocal.x * x + pLocal.y * y + pLocal.z * z;
    3.  
    This effectively implement multiplying vector by a matrix and inverse matrix, on assumption that matrix is not skewed.

    The reason why I suggest vectors is because you can easil construct this small x/y/z coordinate system can can convert in and out of it, and all conversions will be easy to understand and visualize in it in your mind, without testing.

    Now, regarding the widget.

    Standard flight widget is this:
    upload_2023-5-24_4-22-22.png upload_2023-5-24_4-23-36.png
    The top one is a bit overkill, but the bottom one is what you'd normally want on a plane on a plane. Horizon and Heading (flying in a sim without horizon is a pain).

    Basically, the top gadget (horizon) shows where you are relative to horizon, and how much you're tilting, the bottom one (HDG, i.e. heading) shows where t he north is relative to the plane. In case of HDG, you basically take forward vector, project it on the ground, and using it and forward vector build a small coordiante system within which you find angle to the north with atan2, and then spin the dial using it.

    For the horizon you could, uh, one sec... take the vector to horizon (i.e. tangent to planet's surface), then you bring it into local space, kill it's x component (meaning you project it onto xz), determine angle with atan2, that will give you pitch, which you use to drive vertical spinning 'ruler" of the gadget.

    Now you need tilt comonent of the gadget, for that you could, for example, hmm... computed "untilted" x using cross product of global up vector and plane's forward, and use atan2 to calcualte tilt which you then feed into gadget's tilt.

    This is a bit cumbersome, but it is all easily visualizable dot products, cross products and atan. You technically don't need an atan, because you could just get sine/cosine components of tilt angle and build gadgets transform from them. If you want to. There's probably a dozen way to do it.

    Now. All of this can be done with quaternions. For example, you could drive heading gadget with quaternion. Let's assume f or sanity's sake that you're looking at the gadget from above.

    To do that. You'd need to take direction to global north. Multiply it by inverse rotation of the plane. Which will give you a localspace direction to the north, but it'll also include tilt component you do not need, and you'll need to either project andn ormalize, then atan, then you'd need to cancel it with another quaternion, which is a point where it starts getting a bit messy. So it is easier with vectors.

    Now, you're talking about space sim. In spacesim, there's technically no ground and no north. If you're close to a planet, you could use flightsim widgets more or less fine, but if you're in the void, there's no coordinate system to reference. As a result, a more or less standard is Elite Dangerous widget.

    upload_2023-5-24_4-49-2.png
    For orientation you use scanner, which shows directions for everything relative to your ship. And that can be achieved by inverse transform into ship's space.
     
  4. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,791
    There are no ships ..just two sets of center aligned axes and rings. The ship globe remains static because the POV of the pilot is always forward relative.. The world coords globe spins so if my ship is pointed world coords y+ then the world space globe rotates so that the world space globe Y+ aligns with the ship globe Z+. I think @neginfinity has it right with multiplying one set of coords by the other. It gives me dyslexia because the local rotation drives a representation of the world space coords..in reverse..kinda...
     
  5. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,317
    Actually, there's a slight problem with terminology.

    "local coordinates" are relative to object's transform.
    However, object's local coordinates are stored in space of its parent.

    So, it can get confusing.

    if it helps, it goes like this:

    Code (csharp):
    1.  
    2. worldCoord = localCoord * localMatrix * parentMatrix * grandParentMatrix * grandGrandParentMatrix
    3.  
    4. localCoord = worldCoord * invGrandGrandparentMatrix * invGrandParentMatrix * invParentMatrix * invLocalMatrix
    5.  
    As you can see, the order is reversed between between local to world and world to local. It is somewhat similar to scopes, and if you worked with OpenGL, remember glPushMatrix and it should start making sense immediately. When you move from parent to child, you push matrix, when you return, you pop it.

    Long story short, to move mesh to where it is supposed to be, transforms are chained, and matricies are multiplied. Unity hides chaining step and gives you ready to use combined matrices. Because
    localMatrix * parentMatrix * grandParentMatrix * grandGrandParentMatrix
    is equivalent to "localToWorld" and
    invGrandGrandparentMatrix * invGrandParentMatrix * invParentMatrix * invLocalMatrix
    is equivalent to worldToLocal matrices. That is assuming the operations are chained from left to right.
     
  6. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,791
    I am not ignorant of world vs local in proper practice and know the terms are flipped in verbally describing the scenario. I got it now though. I was overthinking the inversion.
     
  7. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,317
    No offense was intended. I have a habit of explaining unnecessary things. This was simply a case where this habit manifested.
     
    ippdev likes this.