Search Unity

Question Proper way to update transform from Rigidbody2D?

Discussion in 'Physics' started by aegis123321, Jul 28, 2021.

  1. aegis123321

    aegis123321

    Joined:
    Jul 5, 2015
    Posts:
    71
    I have a program like a extension of physics simulation that read write the Rigidbody2D position and rotation.
    like this:
    Code (CSharp):
    1.  
    2. Rigidbody2D[] bodies;
    3.  
    4. void MySimulationUpdate() {
    5.     Physics2D.SyncTransform(); // Flush transform to rigidbody.
    6.  
    7.     // do something with body.position and body.rotation.
    8.     DoMySimulation(bodies);
    9.  
    10.     // TODO: Write all transforms from rigidbody.
    11.     //
    12. }
    13.  
    14.  
    I knew SyncTransforms() is only to update rigidbody from transform from this thread: https://forum.unity.com/threads/physics-synctransforms-questions.487424/#post-3180021
    Then I want to know if there is any way to update transforms from rigidbody?

    My simulation is working on Time.scale = 0, so the Unity physics system won't update.
    And I also don't want physics system to work at the moment because my simulation could make colliders overlap and I don't want to make them "collide" in physics.

    I've tried this way to update transform from rigidbody.
    Code (CSharp):
    1.  
    2. rigidbody.transform.position = rigidbody.position;
    3. rigidbody.transform.eulerAngle = new Vector3(0, 0, rigidbody.rotation);
    4.  
    But there is a problem that it makes transform dirty:
    Next time it do SyncTransform(), it will write the transform back to rigidbody.

    It's not the serious problem in most cases.
    But it breaks if the rigidbody is connected by joint which matters relative angle between bodies. (fixed and hinge joints)
    Because the rotation of rigidbody could be lost by Quaternion. (e.g. rotation changes from 350 to -10)
    Then it could make joints totally wrong.
     
  2. aegis123321

    aegis123321

    Joined:
    Jul 5, 2015
    Posts:
    71
    Eventually, I had this solution.
    Although it looks pretty inefficient since it actually did assign twice for each rigidbody, but it works.

    Code (CSharp):
    1.  
    2. Rigidbody2D[] bodies;
    3.  
    4. void MySimulationUpdate() {
    5.     Physics2D.SyncTransform(); // Flush transform to rigidbody.
    6.     // do something with body.position and body.rotation.
    7.     DoMySimulation(bodies);
    8.     // Write all transforms from rigidbody.
    9.     SyncToTransform();
    10. }
    11.  
    12. void SyncToTransform() {
    13.     Vector2[] originalBodyPositions = new Vector2[bodies.Length];
    14.     float[] originalBodyRotations = new float[bodies.Length];
    15.     int i = 0;
    16.     foreach(var body in bodies) {
    17.         // Assign to transform.
    18.         body.transform.position = body.position;
    19.         body.transform.eulerAngle = new Vector3(0, 0, body.rotation);
    20.         // Store the position and rotation.
    21.         originalBodyPositions[i] = body.position;
    22.         originalBodyRotations[i] = body.rotation;
    23.         i += 1;
    24.     }
    25.  
    26.     // Flush transform to rigidbodies.
    27.     // To make sure the dirties are flushed.
    28.     Physics2D.SyncTransform();
    29.  
    30.     // Assign back to rigidbody to prevent from degree loss by sync
    31.     i = 0;
    32.     foreach(var body in bodies) {
    33.         body.position = originalBodyPositions[i];
    34.         body.rotation = originalBodyRotations[i];
    35.         i += 1;
    36.     }
    37. }
    38.  
     
    Last edited: Aug 3, 2021
    tanoccb likes this.
  3. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,474
    When you set the Transform then the transform system stores a changed flag so components see that when they update. The physics system is no different so will see it and read the Transform change back into the Rigidbody(2D).

    So something like Rigidbody(2D) ".SyncTransform()" or ".WriteTransform()" that doesn't trigger the read-back to the Transform later would solve the issue for you? I don't believe that would be a difficult feature albeit a bit of a specialized feature. I'd certainly consider it but because new API cannot be backported, you wouldn't see it for a while.

    For potential backporting; it's not really a bug and I can't see how it could be implemented without an API change either.
     
  4. aegis123321

    aegis123321

    Joined:
    Jul 5, 2015
    Posts:
    71
    That is exactly what I'm looking for.

    Understandable. It's not a serious problem to me since I had the above solution.
    I'd appreciate if it is implemented so that I don't need the that inefficient solution anymore. :)
     
    MelvMay likes this.
  5. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,474
    It's such a simple thing to do that I've added it. Best I can do is get it in 2022.1.
     
    aegis123321 likes this.
  6. Epsilon_Delta

    Epsilon_Delta

    Joined:
    Mar 14, 2018
    Posts:
    258
    Sorry for a bit of a necroposting, but was this API added (if yes what's the name)? I can't find it in 2022.3.0 in Rigidbody nor Rigidbody2D
     
    SolidAlloy likes this.