Search Unity

Bug (Case 1320783) Nested rigidbody2d inconsistencies between engines

Discussion in 'Physics' started by CDF, Mar 11, 2021.

  1. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,313
    Been raking my brain about this one.

    I want to move and rotate a nested rigidbody2d when its parent also moves and rotates.
    I want correct physics response when I do this. i.e cannot set transform.position or rotation directly.

    It seems like this works correctly in 3d physics, with a slight caveat: must manually move the child.

    here's a animation of the issue:
    physics.gif

    top is 2d physics
    bottom is 3d physics.

    Both run the same code:
    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class PhysicsAnimator : MonoBehaviour {
    7.  
    8.     #region Properties
    9.     #endregion
    10.  
    11.     #region Fields
    12.  
    13.     public float rotationSpeed = 30;
    14.     public float rotation;
    15.  
    16.     public bool rotate = true;
    17.     public bool move = true;
    18.  
    19.     private Rigidbody2D rb2d;
    20.     private Rigidbody rb3d;
    21.     private Vector3 position;
    22.  
    23.     #endregion
    24.  
    25.     #region Unity Methods
    26.  
    27.     private void OnEnable() {
    28.  
    29.         position = transform.localPosition;
    30.  
    31.         rb2d = GetComponent<Rigidbody2D>();
    32.         rb3d = GetComponent<Rigidbody>();
    33.     }
    34.  
    35.     private void FixedUpdate() {
    36.      
    37.         if (rb2d) {
    38.  
    39.             if (move) rb2d.MovePosition(GetPosition());
    40.             if (rotate) rb2d.MoveRotation(GetRotation());
    41.         }
    42.         else if (rb3d) {
    43.  
    44.             if (move) rb3d.MovePosition(GetPosition());
    45.             if (rotate) rb3d.MoveRotation(GetRotation());
    46.         }
    47.     }
    48.  
    49.     #endregion
    50.  
    51.     #region Public Methods
    52.     #endregion
    53.  
    54.     #region Private Methods
    55.  
    56.     private Vector3 GetPosition() {
    57.  
    58.         if (transform.parent) {
    59.  
    60.             return transform.parent.TransformPoint(position);
    61.         }
    62.  
    63.         return position;
    64.     }
    65.  
    66.     private Quaternion GetRotation() {
    67.  
    68.         rotation = (rotation + rotationSpeed * Time.deltaTime) % 360;
    69.  
    70.         if (transform.parent) {
    71.  
    72.             return transform.parent.rotation * Quaternion.Euler(0, 0, rotation);
    73.         }
    74.  
    75.         return Quaternion.Euler(0, 0, rotation);
    76.     }
    77.  
    78.     #endregion
    79. }
    80.  
    simple setup (all objects have the above script running):

    physics_hierarchy.png

    How can I rotate and move both the 2d parent and 2d child at the same time while maintaining correct physics responses from other objects?

    seems impossible :(
     
    Last edited: Mar 11, 2021
  2. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,313
    Can see here, the 3d physics info correctly displays velocity and angular velocity: physics3d_info.gif

    Whereas the 2D physics info does not
    physics2d_info.gif
     
  3. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,313
    What's even stranger is the physics response you get even though the child appears not to rotate:
    It's almost like the child rigidbody2D IS rotating/calculating angular velocity behind the scenes, but gets removed once presented to screen.

    physics_response.gif

    Vs how it should behave, according to what is seen:
    WpuxpaP2hE.gif
     
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    I took a look at your case but before I say what I can change, let me mention something.

    2D physics MovePosition/MoveRotation DO NOT change the velocity permanently of the body, it's calculated just prior to the simulation step internally with a simple calculation of the difference between the target position/rotation and the current position/rotation and uses the simulation step time, whatever that might be. This also means it works perfectly for manual simulation or per-frame simulation. The velocity cannot be changed when you call MovePosition/MoveRotation because the simualtion step time is not known then, it could be anything. The simulation is run and it moves/rotates fast to the designated position/rotation.

    When a Kinematic body is a child of another body then it is in transform read mode where it will read its new position as a child from the Transform so would be completely driven by the parent. It's been like this for a long time.

    Your report shows that you can also, under certain circumstances, also issue a MovePosition and/or a MoveRotation. This means it might be reading/writing position/rotation depending on those combinations.

    I've taken the case though for the issue with 2D physics which is that if you do have a kinematic child driven by a parent and you issue a move position or rotation, it should write the position or rotation from the move rather than reading them from the Transform and it should do this independently for position or rotation. This should mean turning off "Move" results in the capsule moving with the parent rotation i.e. the natural transform position. If you turn off "Rotation" then it'll do the same but not have its own local rotation.

    With regards to the high velocity impact; that's simply because a move position/rotation results in a high velociy because that's what it is; a very fast movement through space. It'll impact things at that velocity. It's not a teleportation because that's what setting the Rigidbody2D position/rotation would be.

    Anyway, here's it with the fix:
    https://gyazo.com/12fbb7e5a139a993d0fe3e5f9471b986

    Public Issue Link - May not be live yet because I have only just been converted the case to a public bug.

    EDIT: There seems to be an odd thing in the 3D physics side of things which you mention as a caveat and not a bug; having to set the position of the child manually. Not sure why you don't consider this a bug too. I'll mention that to that team. If you don't issue a move position on the child, that position should still follow the natural child position because that's what the nesting implies.
     
    Last edited: Mar 12, 2021
  5. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    This is the 3D physics which clearly shows the impulse because you're using MovePosition/Rotation which causes high velocities and high impulses: https://gyazo.com/fb886c31cf6309355f34fa52a6981424 The same will happen in 2D physics. It isn't a teleport, it has high velocity.

    You cannot move through space without velocity. You cannot fake some other velocity when moving to a target position/rotation. The solvers don't work like this. If you want that then set the position/rotation explicitly on the body. You'll then get overlaps but there's no inherent velocity.
     
  6. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,313
    Thanks for taking the time to investigate this. I honestly just expected a "won't fix"

    My use case is that I want to have full control over world position and rotation for kinematic bodies (unnested and nested). But at the same time produce a physics response when dynamic bodies hit the kinematic bodies. A high velocity response is fine, and would expect that like you mentioned. What I don't want is no response at all i.e the kinematic body just pushes the dynamic body

    Sounds like with the fix you made, that should be possible?

    Any idea if this might make it into 2020.3 LTS?
     
  7. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    That doesn't change with my fix because it's not broken. You'll still get large impulses because MovePosition/MoveRotation makes things move fast over short distances. Don't forget though that in 2D, MovePosition/MoveRotation are not supported in Box2D so all we really do is set the velocities. Try that yourself by setting the Kinematic velocity in a test for some collisions.

    I've only just made the fix and not even commited it yet so I couldn't even tell you when it'll land even in our master branch. Also, LTS is far stricter than 2021.2 & 2021.1 so I cannot even guarantee it'll land there. Not saying it won't but that's out of my hands.
     
    CDF likes this.
  8. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    The fix has been submitted to 2021.2, 2021.1 & 2020.3. It'll undergo QA test pass then land into the streams. You can monitor the status in the Public Case.

    Thanks for the report.
     
    CDF likes this.
  9. shelim

    shelim

    Joined:
    Aug 26, 2017
    Posts:
    29
    It seems I run into the same problem with project started in January, 2021.

    I could not find that information in Issue Tracker, nor on the changelog (searching through case number reported) - which version of 2021.1.X it is actually fixed?
     
  10. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    2020.3.5f1
    2021.1.2f1
    2022.1.0a7


    You should submit a bug report because the above was fixed, verified and has unit-tests. If you have a problem it'll be caused by something else. Best not to assume it's the same thing.