#Teleporting a Rigidbody in a portal

1 messages · Page 1 of 1 (latest)

versed laurel
#

Hello! I have a player with a Rigidbody with Continuous Speculative collision detection and its interpolation method is set to Interpolate. I noticed that when I set the position of the player to the new position when they go through the portal at high speeds, it feels like the Rigidbody is bumping something ever so slightly. Here's my current teleportation method:

this.playerRigidbody.transform.position = newPosition

Pretty basic, I know. But I've tried other things like setting the Rigidbody.position directly, disabling the RigidbodyInterpolation then re-enabling it, Physics.SyncTransforms(), Rigidbody.Sleep() & Rigidbody.WakeUp(), and finally, enabling/disabling isKinematic and they all produce the same result, some worse than others.

Let me know if there's something I've missed. Thank you!

weak estuary
#

Are you sure it's not actually bumping into something? When are you running this code?

versed laurel
#

It's as if its velocity takes a tiny hit for a frame or two then speeds back up, like it's a desync issue or something

#

I have only trigger colliders so it's not colliding with anything

weak estuary
#

Any chance you could show a video? Also do you have a good reason for using Continuous Speculative?

#

my recommended setup would generally be:

  • Collision Detection Mode: Continuous
  • Use rb.position = newPosition; for the teleportation
  • Double check that your code is not modifying the object's Transform directly in any way, including rotation
#

If you are modifying the Transform directly (position or rotation) that will break interpolation and you may see some visual weirdness

versed laurel
#

I can try to get it on video but I don't know how well it would show up

#

Give me 1 sec

versed laurel
#

@weak estuary Here's the video. If you go frame by frame, you'll see that I jump forward a bit one frame, then the second frame I stay completely still

#

Granted, this is with setting transform.position

weak estuary
#

Any chance you can convert that to an mp4

versed laurel
#

But setting rigidbody.position delays the position update until the next FixedUpdate

#

Oh sure my bad lol

#

I'm recording at 120fps to make it more apparent so it might be hard to see the effect in Discord

weak estuary
#

ok I think I might understand what the problem is here. Are you doing the teleport in OnTriggerEnter?

versed laurel
#

I am

weak estuary
#

ok i think this might be an interpolation issue. I don't think your RB velocity is actually changing

versed laurel
#

okay gotcha

weak estuary
#

You're doing some kind of fancy render texture thing to render the stuff through the teleporter before you enter it I guess?

versed laurel
#

correct

weak estuary
#

Can you show your code for the teleportation?

#

like the whole OnTriggerEnter

#

or whatever

versed laurel
#

Sure

#
// Class on the Player object
public class Portal : MonoBehaviour
{
    private void OnTriggerEnter(Collider other)
    {
        if (!other.CompareTag("Portal")) return;
        
        LevelManager.ToNextLevel();
    }
}
// Level Manager Empty GameObject
private void ToNextLevel()
{

    var playerOffset = this.playerRigidbody.transform.position - previousLevel.exit.position;
    this.playerRigidbody.transform.position = this.activeLevel.entrance.position + playerOffset;
}```
#

I removed a lot of unnecessary code but that's basically it

#

and once again

#

I've done quite a few combinations for the actual teleporation of the player

#

so this variation might not be the best one but it gives me the same results as some of the other combos I've tried

#

And just for extra clarification, I recorded myself stepping through each frame with the previous video at a constant pace

#

On the 4th and 5th frame is where it happens

#

Where frame 4 is double(ish) the velocity and frame 5 is completely still

versed laurel
#

I can 100% confirm that it is an interpolation issue though because turning interpolation off makes it completely seamless

weak estuary
fathom pasture
#

I normally just turn interpolation off while teleporting the player around

weak estuary
#

the problem is for this use case we need to do some kind of interpolation to make the movement look smooth

#

All because of the portal visual illusion that's happening

analog obsidian
#

Although, in this case, you're setting the position in a collision callback

#

So that may happen after the interpolation is applied

#

anyway, Praetor is correct: set the position of the Rigidbody, not of the Transform on its object

#

If you want to continuously move a rigidbody use Rigidbody.MovePosition instead, which takes interpolation into account.

importantly, this means that when you use Rigidbody.position, interpolation does not occur

weak estuary
#

It's like this. Normally you're interpolating between your previous and current position (handled automatically by Unity). But when you go through the portal the "previous" position you should be interpolating from is an imaginary position near the portal exit that you never actually existed at.

So I think you will need to do some custom interpolation at the threshold of the portal here, or at least after teleporting

versed laurel
#

I did a little more research and custom interpolation is the only way

#

Which isn't super hard anyways so I'm not too mad about that

analog obsidian
#

ah, so you still want to have smooth interpolation as you go through the portal

#

that makes sense (and it makes things harder!)

#

doing your own interpolation should not be that bad, fortunately

versed laurel
#

Yea exactly

#

Not too bad

versed laurel
#

@weak estuary @analog obsidian I got it working!

I have a script attached to my camera with some key parts:

private void Update()
{
    // Normalized time since last fixed update tick
    var t = Mathf.Clamp01((Time.time - Time.fixedTime) / Time.fixedDeltaTime);
    // Interpolates between previous and current transformations given the normalized delta time
    this.transform.position = Vector3.Lerp(previousPosition, currentPosition, t) + this.cameraPositionOffset;
}```

and when the player teleports:
```cs
public void Teleport(Vector3 position)
{
    var offset = position - this.RigidbodyPosition;
    
    this.rigidbody.position = position + this.rigidbody.linearVelocity * Time.fixedDeltaTime;
    
    // Update interpolation to keep consistency
    this.currentPosition = position;
    this.previousPosition += offset;
}```
#

The teleport method is kind of interesting because what I didn't realize was that I have to set the rigidbody's position to what it will be in two update ticks, not one

analog obsidian
#

nice!

versed laurel
#

because if I'm halfway between tick 1 and 2 and call this method, the rigidbody position will be set in tick two and then won't update again until tick 3, which causes the camera's position to hang for a few frames

#

Thank you!

versed laurel
#

Small update if anyone comes across this

#

I ended up having an incorrect implementation of lerping that I just found out about

#

My initial assumption was thinking that I could teleport the camera instantenously, but that's not possible since the camera's interpolation by definition runs behind the Rigidbody, so you have to delay the camera by one physics tick