Oops I broke it: Massless characters!
Oops I broke it: Massless characters!
Why do all my issues here seem to involve me overcomplicating things and simultaneously horrendously breaking them?
I've had this issue for a while, but have been ignoring it as non-priority. Might have even posted about it somewhere and forgotten by now, it's been so long...
Anyway, so:
I wanted to implement character free-noclip-flight as a quick button press for cheats-enabled users. In short, they fly around without gravity, and also don't collide with anything.
Flight part is easy: Just spam teleport the player based on move key presses, with complete disregard for physics.
No-colliding is seemingly easy: Just set mass to 0, and collisions won't cause issues! Except if a player pushes something into a wall of course.
But... there's a problem.
Every once in a while, for reasons I have yet to specify any further than 'once in a while it just happens', the player will enter flight, go wherever, exit flight... and lose traction! IE, they have no consistent surface traction, and are unable to walk. They slip about on completely flat surfaces!
So the sequence of events, if unclear, is the following:
Character moves like normal
Character mass set to 0
Character repositioned
Character mass set to a standard ( greater than zero ) value
Character has no traction on any surface.
Now I already have an idea for fixing this:
Stop setting the mass to zero! Just be sure to update the position immediately after physics tick but before render, to ensure position is always correct. Also requires external tracking of position (by which I mean, separate from my usual 'just read it off the physics object')
But, if nothing else, I'd like to understand why this happens to ensure I don't end up with similar/related issues in the future.
I've had this issue for a while, but have been ignoring it as non-priority. Might have even posted about it somewhere and forgotten by now, it's been so long...
Anyway, so:
I wanted to implement character free-noclip-flight as a quick button press for cheats-enabled users. In short, they fly around without gravity, and also don't collide with anything.
Flight part is easy: Just spam teleport the player based on move key presses, with complete disregard for physics.
No-colliding is seemingly easy: Just set mass to 0, and collisions won't cause issues! Except if a player pushes something into a wall of course.
But... there's a problem.
Every once in a while, for reasons I have yet to specify any further than 'once in a while it just happens', the player will enter flight, go wherever, exit flight... and lose traction! IE, they have no consistent surface traction, and are unable to walk. They slip about on completely flat surfaces!
So the sequence of events, if unclear, is the following:
Character moves like normal
Character mass set to 0
Character repositioned
Character mass set to a standard ( greater than zero ) value
Character has no traction on any surface.
Now I already have an idea for fixing this:
Stop setting the mass to zero! Just be sure to update the position immediately after physics tick but before render, to ensure position is always correct. Also requires external tracking of position (by which I mean, separate from my usual 'just read it off the physics object')
But, if nothing else, I'd like to understand why this happens to ensure I don't end up with similar/related issues in the future.
Re: Oops I broke it: Massless characters!
When changing back to dynamic, do you ensure that the inertia tensor is locked? If not, the character will tend to fall over, which isn't the best position for walking.
To lock the inertia tensor:
To lock the inertia tensor:
Code: Select all
CharacterController.Body.LocalInertiaTensorInverse = new Matrix3x3();
Re: Oops I broke it: Massless characters!
So I tried that idea.
It didn't help much.
Then I ran with the idea a bit, and had this code:
and that didn't work.
But then I remembered, my world is exactly the way I was taught as standard for most mathematics: X/Y is length and width, Z is depth.
And ... BEPU, for whatever reason, does not like this model. BEPU has Y as depth for some reason.
So: I stored the preexisting quaternion rather than setting it to identity every time (on the guess that identity orientation would be sideways to my world)...
And it still loses traction and even support sometimes
So, I'm fresh out of tricks here.
It didn't help much.
Then I ran with the idea a bit, and had this code:
Code: Select all
CBody.Body.LocalInertiaTensorInverse = new Matrix3x3();
// Set mass to 0, or stored mass value here
CBody.Body.Orientation = Quaternion.Identity;
CBody.Body.AngularVelocity = Vector3.Zero;
CBody.Body.LocalInertiaTensorInverse = new Matrix3x3();
But then I remembered, my world is exactly the way I was taught as standard for most mathematics: X/Y is length and width, Z is depth.
And ... BEPU, for whatever reason, does not like this model. BEPU has Y as depth for some reason.
So: I stored the preexisting quaternion rather than setting it to identity every time (on the guess that identity orientation would be sideways to my world)...
And it still loses traction and even support sometimes
So, I'm fresh out of tricks here.
Re: Oops I broke it: Massless characters!
Oh also, if it helps: It seems to be relevant that the player is moving forward when they switch to dynamic (>0 mass).
If a player is perfectly still before hitting the disable-flight button, there's a much better chance of not having the traction loss.
If a player is perfectly still before hitting the disable-flight button, there's a much better chance of not having the traction loss.
Re: Oops I broke it: Massless characters!
I can't replicate the issue in the BEPUphysicsDemos when the inertia tensor is properly locked after switching back to dynamic. Is the inertia tensor being set only before making the object dynamic? If it's set before, the conversion to dynamic will overwrite the inertia tensor with a recomputed (and unlocked) one. (The code block you posted earlier suggests that you already tried this, but just making sure.)
If that's not it, could you try to recreate it in the demos so I can take a look?
If that's not it, could you try to recreate it in the demos so I can take a look?
Re: Oops I broke it: Massless characters!
This is magical... I actually replicated it in your demos! I've never broken something so hard it's replicable even in demos. Yay!
Here's a gif to show what's happening first: http://i.imgur.com/OHUaia7.gifv
Basically, I fly up, land, and walk into the spinny thing... at which point I get knocked right over and lose the ability to walk.
It looks like the character controller is losing it's "don't fall over ever" lock when I play with its mass like that.
Anyway, here's CharacterControllerInput.cs http://pastebin.com/xXjUeH5L
That's the only thing I had to modify. I remapped the controls to sanity (WASD and space to move), deleted unrelated scrap, and added the X key to toggle flight.
Here's a gif to show what's happening first: http://i.imgur.com/OHUaia7.gifv
Basically, I fly up, land, and walk into the spinny thing... at which point I get knocked right over and lose the ability to walk.
It looks like the character controller is losing it's "don't fall over ever" lock when I play with its mass like that.
Anyway, here's CharacterControllerInput.cs http://pastebin.com/xXjUeH5L
That's the only thing I had to modify. I remapped the controls to sanity (WASD and space to move), deleted unrelated scrap, and added the X key to toggle flight.
Re: Oops I broke it: Massless characters!
... Huh. I was entirely wrong to celebrate.
I figured it out.
Let's look at my code from earlier.
See anything?
...
I accidentally edited the Inverse.
Autocomplete, damn you to hell!
It works perfectly fine in both demos and my actual environment when I correct that typo.
And now I'm going to go hang my head in shame a while.
As always, thanks for the help, and the great work on BEPU in general!
I figured it out.
Let's look at my code from earlier.
Code: Select all
CBody.Body.LocalInertiaTensorInverse = new Matrix3x3();
// Set mass to 0, or stored mass value here
CBody.Body.Orientation = Quaternion.Identity;
CBody.Body.AngularVelocity = Vector3.Zero;
CBody.Body.LocalInertiaTensorInverse = new Matrix3x3();
Code: Select all
LocalInertiaTensorInverse
I accidentally edited the Inverse.
Autocomplete, damn you to hell!
It works perfectly fine in both demos and my actual environment when I correct that typo.
And now I'm going to go hang my head in shame a while.
As always, thanks for the help, and the great work on BEPU in general!
Re: Oops I broke it: Massless characters!
For reference, the inverse is actually the property most conceptually appropriate to set to all zeroes. The way to 'lock' rotation is to make it so no dynamic force can introduce any angular velocity, which means effectively infinite inertia. One over something-approaching-infinity approaches zero, so that's why I generally say set the local inverse to all zeroes. That said, setting the LocalInertiaTensor happens to work as well due to the way the adaptive invert works, it's just a bit of a happy accident.
If you have a situation where setting the LocalInertiaTensorInverse to all zeroes doesn't work and setting the LocalInertiaTensor to all zeroes does, that's weird and likely a bug.
The edited CharacterControllerInput, as posted, doesn't seem to have any references to the inertia tensor at all, which would be why it didn't work.
If you have a situation where setting the LocalInertiaTensorInverse to all zeroes doesn't work and setting the LocalInertiaTensor to all zeroes does, that's weird and likely a bug.
The edited CharacterControllerInput, as posted, doesn't seem to have any references to the inertia tensor at all, which would be why it didn't work.
Re: Oops I broke it: Massless characters!
I just realized your example used the Inverse too, I thought it was just a typo on my part.
... Huh.
Well, something's wrong, because setting the non-inverse tensor fixes the bug in quick testing and the inverse one doesn't.
You can easily add either one into the example code yourself to see it happen.
... Huh.
Well, something's wrong, because setting the non-inverse tensor fixes the bug in quick testing and the inverse one doesn't.
You can easily add either one into the example code yourself to see it happen.
Re: Oops I broke it: Massless characters!
Both the LocalInertiaTensorInverse and the LocalInertiaTensor appear to work as expected. Are you testing in an old version? Is something else overwriting the inertia tensors after they're being set to zero?
Re: Oops I broke it: Massless characters!
... Huh. Rather than fixing it, it /temporarily/ fixed it. I was wrong.
I'm not touching the inertia tensors by hand anywhere outside this code.
Is there anywhere else it'd be adjusted that might be relevant?
I'm not touching the inertia tensors by hand anywhere outside this code.
Is there anywhere else it'd be adjusted that might be relevant?
Re: Oops I broke it: Massless characters!
I seem to have unbroken it, by ENFORCING a correct orientation.
As orientation seems to be inherently linked to the inertia tensor, based on a quick glance at the code.
^ the setup
^ The usage
That seems to so far produce consistent not-fally-over results, if by no other reason than it fixes orientation every time it has potential to fall over!
As orientation seems to be inherently linked to the inertia tensor, based on a quick glance at the code.
Code: Select all
public static readonly Quaternion PreFlyOrient = Quaternion.CreateFromAxisAngle(Vector3.UnitX, Math.PI * 0.5);
Code: Select all
CBody.Body.LocalInertiaTensorInverse = new Matrix3x3();
CBody.Body.Orientation = PreFlyOrient;
That seems to so far produce consistent not-fally-over results, if by no other reason than it fixes orientation every time it has potential to fall over!
Re: Oops I broke it: Massless characters!
Notably, there is no way for it to fall down (or even begin to change orientation) between making it dynamic and setting the inertia to all zeroes unless a timestep occurs between the two, or if the velocity/orientation is manually set to fall-ish values.
Is the space being updated asynchronously with this modification? That would cause all kinds of problems. Is anything else modifying the angular velocity or orientation during previous transitions? Is it ever potentially dynamic while 'flying'?
Reproducing the behavior in the demos would be helpful, since I'm still just guessing.
Is the space being updated asynchronously with this modification? That would cause all kinds of problems. Is anything else modifying the angular velocity or orientation during previous transitions? Is it ever potentially dynamic while 'flying'?
Reproducing the behavior in the demos would be helpful, since I'm still just guessing.