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

2D vs 3D MovePosition (dynamic rigidbodies)

Discussion in 'Physics' started by lightbug14, Jan 31, 2021.

  1. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    446
    Hi, i'm just wondering: Why MovePosition works differently in 2D vs 3D for dynamic rigidbodies?

    2D: MovePosition will modify the position during the next physics update, the body will also interact with other RB (similar to setting an internal velocity value).

    3D: MovePosition modifies the rigidbody position right after the call (thus teleporting the body from A to B) while maintaining interpolation.

    See the next example:
    2D on the top , 3D on the bottom, all bodies use continuous collision detection + interpolation.
    They move from left to right --> MovePosition( rb.position + Vector3.right * distance )
    2DV3DMovePosition.gif

    Is this behaviour associated with the physics engine itself (PhysX vs Box2D)? or maybe with Unity's implementation?


    Thanks in advance
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,507
    I am a 2D physics dev so I can only really speak with authority on the 2D side but I do know some of the history here. The above 3D physics behaviour was already in-place long before 2D physics came along. PhysX AFAIK only supports Kinematic swept pose changes (targets) i.e. MovePosition/MoveRotation. When doing this on a Dynamic body, the choice therefore was to not allow it and push a console message or just instantly change the pose (teleport). The choice made was to just set the global pose instantly. Note that a move on a 3D Dynamic body does not support interpolation as you indicated above.

    For 2D which uses Box2D there is no support for this whatsoever so we had to implemement this from scratch. The implementation here didn't care if it was a Kinematic or Dynamic body-type so it's naturally supported for both so no decision on how to handle Dynamic was needed.

    So why doesn't 3D now follow what 2D does? It'll probably come down to several factors including maybe nothing/little posted about this being an issue nor bug reports nor it being a priority. I did speak to a 3D physics dev before posting this and they confirmed the above.

    In short, the MovePosition/MoveRotation for 3D is designed around the PhysX feature to set a target which is limited to Kinematic body-types only and doesn't require any Unity code to do so. Box2D has no support so it's entirely handled by Unity code (at least setting it up for a targetted move).
     
    lightbug14 likes this.
  3. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    446
    Thank you @MelvMay for the detailed answer!

    The reason why i mentioned this is because calling rb.position = p in 2D/3D right after the simulation (inside coroutine + waitForFixedUpdate) breaks interpolation, which is totally understandable. For example:
    Code (CSharp):
    1. IEnumerator PostSimulationUpdate()
    2. {
    3.     YieldInstruction waitForFixedUpdate = new WaitForFixedUpdate();
    4.     while( true )
    5.     {
    6.         yield return waitForFixedUpdate;
    7.            
    8.         rb.position = p;
    9.         transform.position = p;
    10.     }
    11. }
    I'm assuming this happens because p (in this case) is not considered as the "last fixed update" position (see "posB"):

    upload_2021-2-1_12-28-51.png
    Calling MovePosition( p ) instead seems to work perfectly fine for 3D. My guess is that it simply resets some internal values or something. I do something similar using my own interpolation:
    Code (CSharp):
    1. protected void ResetInterpolation()
    2. {
    3.     posA = posB = rb.position;
    4.     rotA = rotB = rb.rotation;
    5. }

    For 2D this is another story, so relying on MovePosition is not possible for me (i think). I have "fixed" this by implementing my custom interpolation script with one key difference, the interpolation data is being updated after this PostSimulationUpdate:

    Code (CSharp):
    1. IEnumerator PostSimulationUpdate()
    2. {
    3.     YieldInstruction waitForFixedUpdate = new WaitForFixedUpdate();
    4.     while( true )
    5.     {
    6.         yield return waitForFixedUpdate;
    7.            
    8.         // Here i modifiy rb.position/rotation however i like it
    9.         PostSimulationUpdate( Time.deltaTime );
    10.  
    11.         // Save RB position and rotation, these values will be used in update when interpolation is needed.
    12.         UpdateInterpolationData();
    13.        
    14.         // rb --> transform
    15.         SyncTransforms();                      
    16.     }
    17. }
    This works for 2D and 3D as well (since i don't rely on MovePosition/Rotation).

    Sorry for the long the post :oops:, i just wanted to share why i was interested in this "unified" behaviour.
     
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,507
    If you change the Transform or Rigidbody2D position/rotation then there's no interpolation until the next simulation step and this is on purpose. For instance, if a dev was to change the position by 1000m on the X axis then the body would be interpolated over that distance. We explicitly disable any running interpolation because of that. Next simulation step, it will be set-up again. This is why MovePosition/MoveRotation exist.

    I'm totally confused on what you're trying to achieve here with 2D. Interpolation works perfectly fine and so does MovePosition so I'm here scratching my head.

    Calling MovePosition/MoveRotation doesn't modify the Rigidbody2D at all. It simply flags the position/rotation target is required for the next simulation step. When the simulation runs, the move happens. After the simulation step the body position is at the target you specified and the Transform interpolates from the position/rotation before the last simulation step to the current position/rotation.
     
  5. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    446
    Yes it does work perfectly, i'm just saying that 3D MovePosition does exactly what i need in the particular scenario... let me explain (it is a bit confusing i know).

    In my own project (2D/3D dynamic rigidbody character) i use waitForFixedUpdate (a.k.a after physics but before Update) a lot, i do all sort of unnatural physics behaviours, especially supporting very fast moving/rotating platforms (vanilla rigidbodies moving around) which are interpolated as well. So, knowing exactly when and how things happen is very important for me, not to mention i have to deal with both physics system at the same time, which can be really annoying sometimes.
    Long story short, I was looking for a way to say to the physics: "use this new position p as your target position for interpolation, ignore the one you got from the simulation"... and to my surprise, that seems to be what 3D MovePosition is doing :) (at least the console says so). Calling 3D MovePosition(p) after the simulation does this:
    1. Sets rb.position = p
    2. Sets the "target" position for interpolation as p.

    Unlike 2D, this is not processed in the next physics update, subsequent Update frames use this position "p" as the target position.
    Please, take a look at the following gif, it has everything (this is from a simple demo i made in Unity 2019.4.8f1):
    2DV3DMovePosition_2.gif

    All spheres are dynamic rigidbodies (no gravity) with interpolation enabled, DCD.
    The movement code:
    Code (CSharp):
    1. void MoveRigidbody()
    2.     {
    3.         if( actionType == ActionType.MovePosition )
    4.         {                      
    5.             if( rb != null )
    6.                 rb.MovePosition( rb.position + upDisplacement * Vector3.up );
    7.             else
    8.                 rb2D.MovePosition( rb2D.position + upDisplacement * Vector2.up );
    9.         }
    10.         else
    11.         {
    12.             if( rb != null )
    13.                 rb.position += upDisplacement * Vector3.up;
    14.             else
    15.                 rb2D.position += upDisplacement * Vector2.up;
    16.         }
    17.  
    18.      
    19.     }
    Some observations:
    1. Changing position directly doesn't break interpolation in 2D (?). Look at the first and third (left to right) 2D spheres (from the top).
    2. Note how the forth 3D sphere (bottom) is being interpolated just like the second 2D sphere is (what i mentioned before about using "p" as the target). Unlike 2D, interpolation starts after the call. I guess MovePosition supports interpolation if it is called after the simulation (?).


    Sorry for bothering you with the 3D stuff! I just thought it would be interesting to show how different both systems are when dealing with interpolation.


    Thank you for your time.
     
    Last edited: Feb 3, 2021
  6. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,507
    Yes, as I mentioned above, calling MovePosition on a 3D rigidbody does NOT issue a moveposition, it just sets the RB position instantly because it's not support by PhysX. This is why you can read it because it's essentially the same as just setting the RB position. Here's the internal code:
    Code (CSharp):
    1. void Rigidbody::MovePosition(const Vector3f& position)
    2. {
    3.     ABORT_INVALID_VECTOR3(position, position, rigidbody);
    4.  
    5.     GetPhysicsManager().SyncBatchQueries();
    6.  
    7.     if (GetIsKinematic())
    8.     {
    9.         UpdateKinematicTarget(Vec3ToPx(position));
    10.         m_DisableReadBack = false;
    11.     }
    12.     else
    13.     {
    14.         m_Actor->setGlobalPose(PxTransform(Vec3ToPx(position), m_Actor->getGlobalPose().q));
    15.     }
    16. }
    17.  
    So a Dynamic body just instantly sets the global pose which again is the reason you can read it instantly after.

    Yes, as I said above, changing the position directly on the RB or indirectly via the Transform resets any interpolation until the next simulation step.

    In the end, it's not complicated though; In 2D, when you call MovePosition/Rotation it flags the target but does nothing. It makes no difference when you call it, the result is the same and you cannot ready the target position from the body because it's not been set yet. As I just said above, in 3D this happens for a Dynamic body because it's NOT doing a MovePosition. When the 2D simulation runs, the move happens. After the simulation step the body will be at the position so you can read it then. Interpolation is set-up when the simulation runs; it's the point at which everything starts so subsequent frame(s) interpolate. During that period and until the next simulation step, interpolation happens. If, during that time you modify the body position then interpolation is reset until the next simulation step at which point it'll start again. Also note that any issued MovePosition is cancelled if you subsequently change the position.

    For the curious, here's what happens when you set the Rigidbody2D.position property:
    Code (CSharp):
    1. void Rigidbody2D::SetPosition(const Vector2f& position)
    2. {
    3.     ABORT_INVALID_VECTOR2(position, position, Rigidbody2D);
    4.  
    5.     // Ignore if no body is available.
    6.     if (m_Body == NULL)
    7.         return;
    8.  
    9.     // Clamp the position.
    10.     const b2Vec2 clampedPosition(
    11.         clamp<float>(position.x, -PHYSICS_2D_LARGE_RANGE_CLAMP, PHYSICS_2D_LARGE_RANGE_CLAMP),
    12.         clamp<float>(position.y, -PHYSICS_2D_LARGE_RANGE_CLAMP, PHYSICS_2D_LARGE_RANGE_CLAMP));
    13.  
    14.     // Set body transform.
    15.     m_Body->SetTransform(clampedPosition, m_Body->GetAngle());
    16.  
    17.     // Wake the body.
    18.     m_Body->SetAwake(true);
    19.  
    20.     // Reset any linear movement state.
    21.     m_RigidbodyMovementState.ResetLinearMoveState();
    22.  
    23.     // Reset interpolation movement state.
    24.     m_RigidbodyMovementState.ResetInterpolationState();
    25. }
    I apologise if I've missed a vital point you were making. Lots of moving parts, tired eyes, I miss stuff. :)
     
    Last edited: Feb 3, 2021
  7. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    446
    Thanks again @MelvMay for the quick answer!

    Yes, we can agree on that. I still don't understand why subsequent Update calls (after calling 3D MovePosition inside the coroutine) use the interpolated version of the body, instead of the teleported one (no interpolation) :(.

    Well, i guess i'm missing the "reset" part, because interpolation is still working, otherwise, how is it possible for the body to "remember" the old position (see the gif)?
    In order to interpolate you need the last two "physics positions" (let's say the one updated in the sim, and the previous one). So, by "resets any interpolation" i imagine these two values being fully reset as well (e.g. intPosA = intPosB = rb.position).

    Visually speaking, calling 2D position or 2D MovePosition in FixedUpdate is the same thing. The only real difference is that MovePosition doesn't change the position right away.
    PosInterp.gif


    Haha don't worry! Sorry for posting so many gifs, (i find them very helpful for this).

    For now i'm quite happy with my custom interpolation script, at least i get the same behaviour in both 2D and 3D physics (+ i have full control), so i guess i'll use that instead.

    Just know that from a user POV, having the exact same behaviour for 2D and 3D (especially regarding interpolation) would be absolutely great. Learning physics is hard enough, and on top of that having to handle with all these small differences (gif from previous post) can be a little annoying sometimes.
    Also being able to manually changed the interpolation target position/rotation after the simulation would be very cool ... :cool: Physics.SetInterpolationTarget( position , rotation ) ... basically what 3D MovePosition does after the sim.
     
    Last edited: Feb 3, 2021
  8. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,507
    Probably because how interpolation is done there; Interpolation is a function of the physics system and it's a completely different system after all.
    Yes, calling it immediately before the simulation during FixedUpdate won't change interpolation for the reasons I already mentioned above and that it's only affected during the period in-between simulations. It's updated per-frame. It makes no difference if you change it and the next step is a simulation because again, that's when the interpolation is set-up. The first jittery body in the GIF shows this.

    It is the same because you turn on the option and it works. To be fair, you're using a method call that's outside of it' scope i.e. MovePosition on a Dynamic body to you're expecting the 3D fallback to be the same as the 2D one but the 2D one doesn't have a fallback, it's fully supported.

    But this is an oversight and not a feature. I can see where potentially being able to set a position for interpolation might come in handy but it's very edge-case and would cause a huge amount of confusion for most users.

    I hear what you're saying though in that uniformity would help you here but it'd come at a cost.
     
    Last edited: Feb 4, 2021
  9. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,507
    BTW I wanted to add that whilst I'm replying to your points I wanted to ensure you understand I'm not trying to counter/push-back everything you say and ignore it. I might misunderstand some of your points but I'm always interested in discussing this stuff so feel free to continue. Until I can clearly see where 2D is doing something it shouldn't and not just another "Can 2D behaviour be the same as 3D even though it's wrong and/or not supported" then I'm unable to take action on it. I spoke to the 3D physics dev about this and they confirmed they just never got around to working on Dynamic move-position because it wasn't a priority.

    Again, setting position on the body or transform should not be an interpolated event and it isn't in 2D so if it's happening in 3D then that is actually a bug.
     
  10. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    446
    Hi @MelvMay, don't worry, you have been really helpful so far. To be honest, i'm not trying to push something like "Hey Unity implement this because i need it" kind of thing. I receive those type of requests at least 3 times a week (really annoying). Sorry if gave you that impression. I'm just a user that's giving you some feedback, maybe some of the things i say call your attention, maybe not.

    Just to be clear, i'm not asking to replace the 2D version of MovePosition with the 3D one just because i find it useful, i'm not that crazy (i think).

    I really appreciate that, thanks!
    I'm more interested in extracting what 3D MovePosition does, rather than having a MovePosition 2.0.

    Yeah that's totally understandable. By "system" you mean (for example) Unity's 2D Physics system or Box2D (the engine)?
    I always thought Unity was in charge of the interpolation process.

    Well, maybe it is, but also consider that you are expanding the capabilities of dynamic rigidbodies by just extracting what's already there (MovePosition/Rotation). Plus, MovePosition3D ends up behaving like the 2D version... that's a win win ;).

    The users... who cares, just include a new setting under Physics/Physics2D, no one is going to notice that :D.
     
  11. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,507
    Yes I mean exactly that but also the way interpolation is done in Unity code for each physics system i.e. how the previous and current body positions are stored (etc) and how its simulation step works on the Unity side. I'm just highlighting that conceptually stuff is similar but no code is shared and implementations are guided by internal needs of the underlying physics system.

    I showed the code above. I think though you're referring to interpolation which has nothing to do with MovePosition directly and maybe the source of confusion or at least incorrect focus in the discussion. MovePosition/Intepolation are not a compound operation. It's not like you do a MovePosition and it sets-up some interpolation, not at all.

    I'd ilke to agree but I don't know what setting you mean and specifically what you'd want to see changed in 3D. Maybe if you could focus on one specific thing. The initial discussion was about why tunnelling occured for Dynamic 3D bodies using MovePosition but the discussion drifted into Interpolation which is confusing me at least on what specifically it is that you'd like to change being as the two are not the same thing.
     
    Last edited: Feb 4, 2021
  12. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    446
    Fair enough, the reason why i brought interpolation into the discussion is because it is the main issue, MovePosition is just the "fix". For some reason (which we already discussed) one MovePosition helps (3D) but the other doesn't (2D). This is why i was interested in the difference between the two in the first place (start of the thread).

    Another reason why i mixed the two concepts --> this statement: "If the rigidbody has isKinematic set to false, it works like transform.position=newPosition and teleports the object to the new position (rather than performing a smooth transition)." which is true and false at the same time.

    Good to know! that makes sense, probably that's also why storing those positions is not as easy as i was initially thinking.

    What would i like to add?
    A way to set 2D/3D interpolation targets after the simulation (OnCollisionXXX, OnTriggerXXX and/or coroutine), either directly (API, setting, etc) or indirectly (like 3D MovePosition does now, some internal change, etc).

    What's the problem?
    I have a problem with 2D :(. Unity gives us a really nice coroutine that runs after the simulation but before interpolation (perfect place), but I can't use it properly in 2D (for example: changing rb.pos/rot and still getting interpolated results) because anything i do forces me to wait until the next physics update (not enough).
    I know, this is how MovePosition works, i have no issues with that.

    What for?
    Having the control to tweak this type of things after the simulation is great (i guess we can agree on that), you can do some really nice things without the need to introduce extra "in your way" hacks, which unfortunately reduces compatibility with other tools (for example, by introducing custom components, wrappers, etc).
    A character vs (default vanilla rigidbody-based) moving platforms is the first thing that comes to mind, climbing dynamic steps is another, etc... there are other things as well, basically any "post-simulation" behaviour can be affected/improved by this.

    I agree, both are not connected in a direct way, but there is no doubt at this point that you call MovePosition in order to "set some flags" for later (interpolation).

    Regarding the code you showed me, knowing about MovePosition definition definitely helps, however, without some context doesn't say much about how interpolation works in the big picture (i'm always talking about dynamic rigidbodies), especially considering that the code just teleports the body to the target position (and that's pretty much it). What i mean by "some context" is:
    - How/When those targets are handled (set/reset,disabled).
    - Is this task delegated to some specific process within the simulation... StoreInterpolationPoses sounds about right:
    upload_2021-2-6_3-29-0.png
    - How exactly is interpolation disabled (3D)? (based on what you said before "We explicitly disable any running interpolation because of that.").

    ...things like that. Like i said before, i don't want to fill you with 3D-specific questions (i know 2D is your field). Also, to be honest i don't really know what i'm doing with this thread :D, i guess I'm trying to figure what's going on under the hood. Please forgive my "maybe this, maybe that" theories.
    I guess i'm also also trying to put together some feedback as well, based on my knowledge of how Physics works o_O.
     
    Last edited: Feb 6, 2021
  13. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,507
    Saturday morning, got a coffee so let me try to clarify my thoughts. Actually, clarity on a Saturday morning isn't something I do well so forgive my potentially unstructured reply. ;)

    It's actually always true from the physics POV. I think you're referring to interpolation which is just Transform smoke/mirrors and whilst it might interpolate between positions, the new position is already set in the body. This means teleporting and potential for tunnelling (for Dynamic body as it just has its pose set).

    I will say that though that the fact that you can set the interpolated target is a bug in 3D physics. You should never be able to do that. MovePosition is always the way its been designed.

    My fear is that adding in an explicit interpolated target is going to add a lot of confusion because it'd have to be used at a specific time and users will set a position of the body which changes instantly and it will interpolate the Transform so you'll get tunnelling so it'd be a bad version of MovePosition which won't collide in the interveining space. Also, interpolation doesn't just need old/new positions; it needs to know time-wise where inbetween fixed updates it is. We cannot control when the user will call this so what do we set as the current time? It'd mean it could potentially be half-way inbetween fixed updates so it'd immediately be set half-way which would be a big jump. Yeah add some docs but experience tells me it's just another confusing thing.

    Personally I don't like the above idea as it upsets my spider senses. I'd probably go for an option in 2D physics that allows you to control if interpolation is reset if an explicit position/rotation is set either directly on the Rigidbody2D or via the Transform. It could default to true (existing behaviour) but could be turned off. It'd mean you could potentially set huge position jumps and interpolation would work which would look odd but it's an option rather than a method change.

    I'm always talking about 2D unless I say 3D. :) When you set a 3D Rigidbody position then interpolation is reset until its set-up again next simulation step; same as 2D. It's as simple as that. Again, this is for Dynamic bodies. MovePosition for 3D Dynamic Rigidbody doesn't reset the interpolation position which is a bug and just sets the position immediately. it'll interpolate to that position. This bug is useful to you though.

    A Rigidbody or Rigidbody2D have a small structure associated with them. What these structures contain is different for each but in common they have a target pose (pos/rot) and a flag saying if interpolation is active or not. If Interpolation is off for the body then this structure is not used. If interpolation is on then it is used. Prior to simulating the world, this structure is set-up snapshoting the current body pose and this is used as the from pos/rot. The simulation runs and the interpolation target i.e. the new pose is stored in the structure. Then the physics callbacks occur and it returns and it's done. Then, during each frame (Update) these Rigidbody(2D) structures are iterated and any that are enabled have their Transform pose calculated with a pos Lerp and rot Slerp. The Transform is set. Multiple frames happen with this Lerp/Slerp process. Next update this all starts again.

    If at any point in time a Rigidbody(2D) position/rotation is set and the body is set to Interpolate then this interpolation structure simply has its enabled flag set to false. This immediately stops interpolation of the Transform. To be clear, none of the above changes the body pose; it's all about Transforms.

    You're asking about MovePosition and in 2D as you know, it's only actioned in the next simulation step. This is true for 3D too apart from the above-mentioned fallback where you do this with a Dynamic body. It doesn't support that so its fallback is to just set the position instantly and yes, it is a teleport action. It will NOT contact anything inbetween the previous and new position. It's a bug that it doesn't reset the interpolation target there which I can understand you're using as a feature but it's an oversight/bug. As I said above, for 2D we support both Kinematic & Dynamic seemlessly so both get actioned when they should i.e. during the next simulation step and both interpolate and both move through the intervening space thus no tunnelling.

    It's all good. I'm happy to provide any kind of information as long as I know it's not making things more confusing and is in-fact helping.

    In short, there's nothing to fix/change in 2D MovePosition as it's doing what it should do without issue. 3D MovePosition however does not support Dynamic bodies but just does a RB.pos = pos but also doesn't (bug/feature) reset interpolation so it gives you what you want. The only common solution would be to have a setting in both 2D/3D that stopped the intepolation reset (until next simulation step) when you explicitly set the RB pos/rot. This would mean you can consistently set that but I will say, doing this on a Dynamic body is BAD and introduces tunneling which you showed clearly on your first image (3D failed, 2D didn't).
     
    lightbug14 likes this.
  14. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    446
    Thanks a lot @MelvMay for all the info, it is much more clear now :)

    100% agree on that, in this particular case i was taking advantage of the bug, rather than using the feature.

    Really good info, thanks.

    For 3D, Doesn't this also mean that the target pose (from the structure) needs to be updated after the coroutine? If not, how is the target updated immediately after? In any case, this seems to be a bug, i don't expect an answer to this (i'm just thinking out loud).


    That sounds nice, just one question: What about the target pos/rot? Because at this point the struct has already been updated, right?
     
  15. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,507
    There is no target explicitly, it's the current body position and angle so changing them naturally sets a new "target". What it won't do with the above option off is just disable interpolation.
     
    lightbug14 likes this.
  16. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    446
    Hi, me again :). I have one question related to this topic (2D vs 3D + interpolation). I noticed one more "little" different between 2D and 3D that's causing some issue (especially with my OCD).

    The situation: In 2D (kinematic and dynamic bodies using interpolation) the Transform component doesn't get "updated/synced" before FixedUpdate (Rigidbody2D data to Transform data). So, the Transform data i get is the last "interpolated data".
    For 3D this doesn't happen at all (before FixedUpdate Transform and Rigidbody are synced). I'm guessing the system assumes at this point the transform should be equal to the target (rb.position), since the interpolation t factor (Lerp) should be 1 (we have reached the next FixedUpdate).

    If i want to simulate what 3D does i need to change that Transform manually (transform.position/rotation = rb.position/rotation) but in doing so i'm forcing a sync transform later (collider and rigidbody need to be updated), because the Transform is "dirty" now.


    What do you think? Because in this case i think what 3D does makes more sense.

    Thanks.
     
    Last edited: Feb 15, 2021
  17. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,507
    I'm not sure what (when) you mean here by "before FixedUpdate" because technically there isn't anything like this. Physics only runs during FixedUpdate which is after the user callbacks and then during each Update it interpolates so I'm honestly not sure what else is going on there.

    Certainly the interpolation per-frame doesn't mean it'll get to the final (current) body position. When the FixedUpdate runs in 2D, the Transform is temporarily set to the current body position (the new simulated position) in-case someone reads it after the simulation has run (for things like manual simulation etc) but in Update the Transform will be set at the first interpolated/extrapolated position.

    I looked at physics and there's only a FixedUpdate, EarlyUpdate, Update callbacks. There's no pre-fixed-update callback being used here from what I can see. There's also a lot of old legacy code in 3D and some SyncTransform so it's likely what you're seeing might be by accident.

    Honestly though, I am not the person to speak to regarding 3D physics, that would be @yant.
     
  18. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    446
    I'm not implying that there is a user callback before FixedUpdate, I'm just saying some process/task is doing that sync before "FixedUpdate" (FixedUpdate.ScriptRunBehaviourFixedUpdate if you want).

    A "happy accident" i would say.
     
  19. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,507
    I understand that and I wasn't implying user callback, I'm talking about inside the engine and the 3D physics system isn't hooked into anything like that; only the ones I said and it cannot be inside the Update callback because that has no idea if the FixedUpdate is next or not (there might be several before a FixedUpdate).

    But yeah, Anthony Yakovlev is the man to discuss that with. Maybe he knows.
     
    Last edited: Feb 16, 2021
  20. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    446
    Sorry for the late reply, thank you again Melvyn for all the help!

    Anthony (@yant ), if you are reading this, i would like to share with you some of the "strange" behaviours i've discoved since i created this thread. It would be very interesting to know why the following situations happen, any help/advice will be appreciated.
    Interpolation is enabled for all cases:
    1. For a 3D dynamic RB, if i call MovePosition(p) after the simulation (OnCollisionXXX, OnTriggerXXX or coroutine) the body gets not only interpolated, but also the target pose (interpolation) gets updated as well (transition from current position to "p" over the next frames).
    2. For a 3D kinematic RB, if i change the position after the simulation (OnCollisionXXX, OnTriggerXXX or coroutine) the body gets not only interpolated, but also the target pose (interpolation) gets updated as well (transition from current position to "p" over the next frames)... similar to 1.
    3. For a moving 3D dynamic/kinematic RB , Transform and Rigidbody are always synced in FixedUpdate, transform.position == rigidbody.position. This exact behaviour doesn't happen with 2D when dealing with an interpolated object. Personally i prefer this 3D behaviour over 2D.
    BTW I'm using 2019.4.8f1.

    In any case, i made my own interpolation (now i'm in control), so i don't really need help regarding all of this. I just thought it would be really interesting to hear something from a 3D physics dev, that's all.

    Also, having different behaviours between 2D and 3D can be frustrating some times. I know that both engines/systems are not identical, however, i would love to see a more unified behaviour in the future (especially since most of these differences are associated with interpolation itself). Just my two cents.


    Thanks in advance.
     
  21. whitexroft

    whitexroft

    Joined:
    Oct 22, 2012
    Posts:
    48
    Sorry for intrusion, just wanted clarify a thing.. so if a 3d rigidbody was set to interpolate to a position, and in one of the subsequent frames .position is set (thus cancels interpolation), it teleports rigidbody to the new position, and does not generate contact pairs?
     
  22. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,507
    Interpolation has nothing to do with it. If you set the position of a Rigidbody(2D) then it's at that position. Bringing in interpolation just makes the question confusing.

    Contact pairs are generated when the simulation runs.

    Interpolation interpolates the Transform, it has nothing whatsoever to do with physics, contacts or positions of bodies. It's purely a visual feature allowing per-frame updates to Transforms because the physics (by default) doesn't run per-frame.
     
    whitexroft likes this.
  23. samvilm

    samvilm

    Joined:
    Jan 17, 2021
    Posts:
    43
    @MelvMay

    You seem to imply that rb2d.movepostition can be used for DYNAMIC rigidbodies.

    Can you confirm that? I'm confused because the docs seem to say otherwise....
     
  24. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,507
    I'm not implying anything; they can and always have been available to be used on Dynamic bodies.

    What specifically does it say that tells you that you cannot use it?

    https://docs.unity3d.com/ScriptReference/Rigidbody2D.MovePosition.html

    Also, please don't necro old posts. Please create your own thread and ask your own questions there.
     
  25. samvilm

    samvilm

    Joined:
    Jan 17, 2021
    Posts:
    43
    upload_2022-11-1_20-34-4.png

    sorry about the old post thing.
     
    MelvMay likes this.
  26. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,507
    Whilst that note is techically correct, it is intended for Kinematic bodies, it does work with Dynamic bodies as long as you understand the caveats described above it. Kinematic bodies don't have a collision response as described in the above text. Besides, if it didn't work with Dynamic bodies, it would do nothing or issue a warning. A quick test would show that it works perfectly fine. :)

    Maybe that can be changed to say that it will work with Dynamic bodies (as described above) but is primarily intended for Kinematic bodies.

    If you only read that but didn't read any of the above you'd be confused and/or you didn't know that Kinematic bodies don't collide and stop moving because of collisions.