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

Help with realistic spaceship movement (roll/spin issue)

Discussion in 'Physics' started by Lazy_Sloth, Oct 31, 2020.

  1. Lazy_Sloth

    Lazy_Sloth

    Joined:
    Apr 3, 2018
    Posts:
    39
    Hello,

    I'm trying to make a realistic physics based spaceship movement, (something like in X4 game) but I got some very strange "wobble" motion/rotation when I try to roll the ship on z (forward) axis. I try to fix it for two days now and I would kill myself at this moment as I can't fix it on my own.. I also check online but I didn't find anything which can solve my problem.

    CONCEPT:

    My ship object has rigidbody and it has many children objects (thrusterPoints). The thrusterPoints empty objects with meshrenderer (to help me visualize their positions). The parent ship object also has a script (Thrust.cs).

    This script responsible for give thrust (force) to the given point. When I press a control key on my keyboard (say Q for roll left), the script give push by 'AddForceAtPosition' at the position of the linked thrusterPoint. Each control key has its own thrusterPoint of course, and they align at the proper position and rotation (force always applied on blue axis "forward", so I rotate the given thrustPoint object to get proper force direction).

    For a left roll with ship I need two thrusterPoint object (called them: rotate_roll_L1 & ... L2) aligned opposite to each other (one point up, other point down). The two thrusters mirrored each other position (one at pos: 1:0:0, while other: -1;0;0). So everything in balance to make a good left roll

    Relevant code for this:

                rigidb.AddForceAtPosition(rotate_roll_L1.transform.forward * force_roll, rotate_roll_L1.transform.position);
    rigidb.AddForceAtPosition(rotate_roll_L2.transform.forward * force_roll, rotate_roll_L2.transform.position);


    The 'AddForceAtPosition" is relative to parent ship object even if it's use world coordinates as I use the thrusterPoints (rotate_roll_L1-2) positions and they children of parent ship object so the position will be relative to main ship object.

    EXCPETED BEHAVIOUR:
    The ship start to roll along Z axis perfectly (easy to imagine..)

    MY RESULTS:
    I show 3 scenario, where I build different ship by modules (actually, just prototypes here to demonstrate more clearly, build by simple blocks.. ).

    • 1st case:
    The "ship" is symmetrical and very simple construction. The center of mass (COM - yellow sphere) is in the middle. I marked the left roll thrusters forward direction (direction thrust applied) as green arrows.. the thrusters are the spheres to visualize, No question here, it is rolling perfectly!



    • 2nd case:
    I put one block at top of the ships centre.. the COM slightly moved up but not an issue! The ship rotate around blue axis even if the middle of rotation is the COM not ship's middle position. I can fix it easy if I align the ship's position to down a bit (then COM will be at the position 0:0:0). Other fix is to modify COM position by code and put to the middle, but I don't want to "cheat" with the centre of mass of the ship. The picture shows the unmodified version (original position of ship & COM). Everything fine with this as it's working!



    • 3rd case:
    I moved the extra block to front of the ship, but keep its height. So the COM is not only a bit moved up but also forward. As a result the full ship start to tilt away, not parallel with blue axis... WRONG!. If I modify the COM by code and force it to be at middle (0:0:0), then I got the same wrong result! See: the blue relative axis not parallel with thicker blue word axis anymore! So, don't matter where the COM is...



    IMPORTANT!
    I tested other rotations like yaw and pitch! They are working properly without any problem like roll has...

    SOME NOTE:
    -
    Doesn't matter where I positioning the thrusters I got the same wrong rolling.. so, for example, if i put them forward and up.. they forces are "extinguished" each other, so they rolling good as in the first example, but thanks to the different construction of the ship I got wrong result. So, don't say "put thrusters aligned with COM"...
    - I use only 'AddForceAtPosition'. The idea behind this is the realism... in the real spaceship's thrusters working like this as they give push (when fire the thruster) exactly where the thruster is and push the ship on that point. When all of the forces with well placed thrusters are balanced with centre of mass etc.. the ship is rotating how the pilot want. If I would use torque or modify rotation directly wouldn't be real as they not apply forces from thruster just do on full ship... I hope you got what I'm talking about.
    - I don't really want to modify the centre of mass of the my ships, as I want to be realistic, but if this would be the only way I would do this but should to avoid...
    - I tried to modify everything... thruster, COM, ship position, but looks not this it the way to fix!
    - Can be Gimbal-lock issue... but according to what I read online it is probably not...

    PLEASE TRY TO HELP ME!
    Give ideas or anything what in your mind. There's a many spaceship game and also airplane games with real physics... someone should to meet with my problem! Very difficult to explain this problem even in my native language, but I hope you can understand what I'm about. If not clear something just let me know!

    THANKS!
     
    Last edited: Oct 31, 2020
  2. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,428
    That behavior is caused by the Inertia Tensor (Rigidbody.inertiaTensor and inertialTensorRotation). The inertia tensor defines the angular accelerations of the rigidbody when forces are applied off-center.

    By default the inertia tensor is automatically calculated out of the colliders present in the rigidbody. This is why you are observing different results depending on where you place the extra cube.

    Fix 1:
    1. Play your 1st case
    2. Get the value of Rigidbody.inertiaTensor somehow. For example:
      Debug.Log(myRigidbody.inertiaTensor)
    3. Explicitly configure your inertia tensor to that value from any script's OnEnable. For example:
      myRigidbody.inertiaTensor = new Vector3(100, 1000, 1000);
      myRigidbody.inertiaTensorRotation = Quaternion.identity;
    4. Play any of your other cases.
    Assigning a value to Rigidbody.inertiaTensor disables the internal automatic recalculation. So you may then modify your ship's colliders, CoM and mass freely, and the inertia tensor will conserve the value provided.

    Fix 2:
    1. Play your 1st case
    2. Assign Rigidbody.inertiaTensor to its same value:
      myRigidbody.inertiaTensor = myRigidbody.inertiaTensor;
    3. Add additional colliders in runtime to resemble any of the other cases.
    As you've assigned explicitly a value to inertiaTensor then the automatic recalculation is disabled. Therefore you can add/remove colliders, modify CoM etc without the inertia tensor being recalculated any further.
     
    Sab_Rango and Lazy_Sloth like this.
  3. Lazy_Sloth

    Lazy_Sloth

    Joined:
    Apr 3, 2018
    Posts:
    39
    Thank you very very much! I can't believe how simple it is.... If I follow your steps the ship do perfectly parallel rolls with the Z axis, even with complex construction! Thanks again to save me from further suffer!

    I have two question about your solution if you don't mind:
    - As I mentioned I try to be as realistic as possible with physics. I'm not familiar with inertia tensor, so I don't know how reduce your "trick" the level of realism.. If I apply this to every object in my game will I lose any degree of realism compared to the real physics with real ships in space? Don't misunderstand me I love your fix and I have no choice so I gonna use your solution, but I want to know what I "lose" if I use this (if any..). If my objects collide each other or a missile hit it for example and push the ship away... will the ship react according to realistic force interaction or is not possible if I don't let Unity to constantly upgrade the tensor?
    - Is there any difference between the fixes of yours? I mean the first same like the second, do the same thing, the only difference that I can modify the tensor value to any unique one if I want (if not copy the debugged version fully for example)?

    I notice a strange displacement in Z axis if I roll/pitch/yaw... I took my first case where everything balanced and the COM is on the middle at 0;0;0 in world/locale space. I use tensor freeze just how you told me (and it's working!). Of course rolling parallel and this works great but in the Z axis there's a tiny displacement which increase when I pump more force (hold down key)... I didn't find any explanation why it is as everything symmetrical and balanced... and this is occur with yaw and pitch too! But this thing shouldn't exist right? NO reason to move out from any axis as I just rotate the ship around midpont/COM..

    Do you have any idea?

    Here's a picture about the displacement (would increase the value if I would have run it longer). As you can see the ship move on Z axis slowly.. also the ship has velocity/speed, but it should have only angular velocity as it's rotating only..

     
    Last edited: Nov 1, 2020
  4. Sab_Rango

    Sab_Rango

    Joined:
    Aug 30, 2019
    Posts:
    121
    I found a simple explanation about inertia tensor, hope it helps!
     
    Last edited: Nov 4, 2020
  5. Lazy_Sloth

    Lazy_Sloth

    Joined:
    Apr 3, 2018
    Posts:
    39
    Thanks it's really good and simple explanation to calculate inertia tensor! Can be useful if someone wanna to code own physics engine but also for deeper knowledge in this theme.

    Maybe do you have any idea why my ship is always drifting a bit along the Z axis? You can read the description of the issue here in the "I notice a strange displacement" part or in my separated thread about this called "Why my object is moving/drifting towards Z direction with no reason?" on the forum/physics. There I explain it more clearly. I have a suspicion this a bug which came with the new beta version of the Unity (2020.2.0b9), but if it is, I could find a many complain about it on the internet.. I don't know why it is happen...
     
  6. Sab_Rango

    Sab_Rango

    Joined:
    Aug 30, 2019
    Posts:
    121
    In my perspective, I think it is better to customize the physics by IK or some specific logic that calculates physically correct for your need!

    Since, PhysX is lightweight, there is no whole life in it.

    I strongly suggest you to debug your condition by recording the game object components to an animation clip.
    How to do link

     
  7. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,428
    Letting Unity upgrading the tensor would be unrealistic in many cases, as it assumes the rigidbody's mass to be homogeneously distributed within the colliders' volume. In reality the mass would be distributed heterogeneously.

    Defining your inertia tensor explicitly allows you to fine-tune each ship's handling carefully based on how you expect it to react to rotations. First, you would set the inertia tensor rotation to identity to prevent unwanted rotational effects:
    Code (CSharp):
    1. rb.inertiaTensorRotation = Quaternion.Identity;
    Let m be the rigidbody's mass. A ship shaped mostly like in your 1st case would have similar average pitch and roll rates, but faster roll rates. So the inertia tensor may be like this:
    Code (CSharp):
    1. rb.inertiaTensor = new Vector3(m, m, m/4);
    This inertia tensor defines this:
    • Average rotation rate around the X axis (pitch)
    • Average rotation rate around the Y axis (yaw)
    • Fast rotation rate around the Z axis (roll)
    Now you could test the ship and adjust the X, Y, and Z components of the inertia tensor accordingly to what you expect from that ship. For example, if you want faster orientation changes (yaw) you could install an "upgrade" that modifies the Y component of the inertia like this:
    (m, m * 0.75f, m/4)
    .

    This provides a great flexibility to configure the ship by using the rotational inertia as an additional gameplay element.

    There's no difference. In the first case you "copy" the value of the simplest case and apply it, while in the second case you start with the simplest case and build the rest of the ship in runtime.

    Maybe you're applying the torques within an Update method? You should apply forces and torques (and any physics effects in general) within the FixedUpdate method only.
     
  8. Lazy_Sloth

    Lazy_Sloth

    Joined:
    Apr 3, 2018
    Posts:
    39

    I have no idea how to code a physics on my own... I already did something same with 2D where I calculated my ship physics (yeah I love spaceship games ;) ) by vectors and moved according to it. Actually it was based on "steering behaviours" by this tutorial: https://gamedevelopment.tutsplus.com/series/understanding-steering-behaviors--gamedev-12732

    But in a 3D game which is located in space and the precision is very important, I don't know how to code a full-range physics engine. Not only the movement can be problematic but the ships can collide, they can pushed away by missile attack etc etc etc... looks much more complex then I can handle... or would it be easier then I think? the 2D stuff what I mentioned above was quite easy! easier than I thought..

    I don't see how the 'animation clip' thing would help. I would see the same thing.. strange drifting/rotating movement, but it wouldn't reveal the reason of this. Or I missed something?
     
    Sab_Rango likes this.
  9. Lazy_Sloth

    Lazy_Sloth

    Joined:
    Apr 3, 2018
    Posts:
    39
    Thanks again! The possibilities of the fine-tuned inertia tensor is very interesting! I will make some experiment with the settings and see how these change the behaviour of my ship. To be honest I didn't use the 'inertiaTensorRotation' part as it wasn't in your second fix, only the 'rg.inertiaTensor = rg.inertiaTensor'. I will add its rotation as well, maybe it will help with my inaccuracy problem.

    No, I always use physics related things in FixedUpdate method. On the other hand I don't use torque force, only simple 'AddForceAtPosition' applied on the proper location and facing which will cause to roll (for example) the ship. On my other thread about the problem ( https://forum.unity.com/threads/why...ng-towards-z-direction-with-no-reason.998593/ ) a guy told me this inaccuracy at movement/rotation can caused by Unity inner system (using float) and when I move an object so many thing happening inside Unity (degrees into radiant + quaternions stuff) that the final result will by inaccurate which is cumulatively be significant.

    If you not too bored about this issue you can check my linked thread, where I focus on that issue clearly. Actually you already solved my "rolling" problem by tensor so it's not an issue anymore, but thanks to this I realised, I have an other problem which is this mysterious inaccuracy which cause a lot of headache for me. Thanks again your time!
     
  10. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,428
    The inertia tensor in your 1st case should be Quaternion.Identity already. Otherwise, something is not symmetrical in your rigidbody.
     
  11. Lazy_Sloth

    Lazy_Sloth

    Joined:
    Apr 3, 2018
    Posts:
    39
    Got it, thanks!