godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
88.96k stars 20.17k forks source link

Bullet PR: Gravity applied to body automatically despite manual integration #12171

Closed kubecz3k closed 6 years ago

kubecz3k commented 6 years ago

Operating system or device, Godot version, GPU Model and driver (if graphics related): This issue is relate to Bullet pr: https://github.com/godotengine/godot/pull/10013/commits/59ac2999ea4af77cc36c65c9da904616d9eb832b Tested on ubuntu 17.04 release_debug build

Issue description: backstory: Since the beginning of testing bullet, I noticed and had problem with very strong gravitational force that are applied to my bodies. I thought it's just because bullet do some calculations differently and that I will need to recalibrate physics in my game to cope with this.

It turns out bullet is applying gravity automatically for bodies with manual integration. I think this still should be applied manually by the programmer in case of manual force integration. In my case it's quite common for bodies to have slightly different gravity depending on their state or type. quick vid: https://youtu.be/hgDtXq-XVDk

Steps to reproduce:

  1. Download sample project
  2. Run ManualGravityIntegrationTest.tscn

manual way:

  1. Create rigid body in character mode.
  2. Turn manual integration to on, and canSleep to off
  3. Attach this script to the body:
    func _integrate_forces(state):
    var delta = state.get_step();
    var lv = state.get_linear_velocity();
    #lv += state.get_total_gravity()*delta; <- not applying gravity for this body
    state.set_linear_velocity(lv);
  4. Set body in empty scene and run it
  5. Observe that it will fall on bullet physics.

Link to minimal example project: ManualIntegrationGravity.zip

kubecz3k commented 6 years ago

@AndreaCatania I'm so much sorry!

AndreaCatania commented 6 years ago

Bullet always apply all forces to the body in order to move it.

So the gravity is always present. However there's a method that can be used in _integrated_forces that allow you to clear all forces applied to the body. The problem is that I need to add this new method into the body direct state class in order to allow you to use it. I'll updated you.

Alternativly you can change the body gravity.

However I don't know what is your main objective with it but probably the rigid body is not the best way to do what you need.

kubecz3k commented 6 years ago

Oh I see, in my use case I will not apply gravity at all (since bullet is doing it), or just apply negative one (since in some cases I was using more weak gravity). This will need to be documented in our 2.x to 3.x conversion guide document (since this apply to all dynamic characters made before bullet). Also thank you for additional method, think it might be handy in the future.

kubecz3k commented 6 years ago

I have one case where this simple workaround is not working. I sometimes need to neglect gravity force in _integrate_forces, so in bullet I need to do something like this:

var g = state.get_total_gravity();
var lv = state.get_linear_velocity();
lv += -g*state.get_step()*1.0; #bullet
state.set_linear_velocity(lv);

The problem is this is not working for time_scale above 1.0 (set via Engine.set_time_scale()). In that case body is starting to move in negative gravity direction. Any ideas?

AndreaCatania commented 6 years ago

You should wait this: https://github.com/godotengine/godot/pull/12185

kubecz3k commented 6 years ago

@AndreaCatania So when clear_forces api will be merged, I will need to fetch forces (linear and angular velocity), apply them to my own custom gravity, clear all state forces, and then put back my custom ones? Will it be ok (performance wise) to do this in each integrate_forces() tick? (mean, I'm asking if clearing everything with clear forces will not be too dramatic for physic engine, and will not deal any kind of, I dont know... lock problems?)

kubecz3k commented 6 years ago

I actually want to do some very frequent scenario in dynamic character control. Basing on physic state I'm deciding if body is on the slope, and if yes then I'm disabling/decreasing gravity.

AndreaCatania commented 6 years ago

You should call clear_forces bofore all functions in the _integrate_forces.

E.G.

state.clear_forces();
var g = state.get_total_gravity();
var lv = state.get_linear_velocity();
state.set_linear_velocity(lv);

For the performance you don't have to worry about. clear_forces is a simple function.

I actually want to do some very frequent scenario in dynamic character control. Basing on physic state I'm deciding if body is on the slope, and if yes then I'm disabling/decreasing gravity.

Now i'm sure that you are doing it wrong, you have to use the kinematic body. The dynamic character does calculations that you don't need, either in Godot physics.

To control the dynamic character you have to do some hacks, like change gravity

kubecz3k commented 6 years ago

So in short my use case is not plausible? :P

AndreaCatania commented 6 years ago

Yes it could be, but use a kinematic character is way better. Why you think the opposite?

kubecz3k commented 6 years ago

Well when I was starting my project I was using rigid bodies, because I did some benchmarks on old godot and RigidBodies well performing a lot better than Kinematic bodies on mobile. To have ~full~ nice physics simulation I needed to write a lot of inefficient gdscript code, vs cuple lines in Character which, had real influence on performance on mobile (not sure now, but I could increase amount of enemies significantly). Now when I'm no longer targeting mobile, I still want to use character exactly because I don't have full control of the body and visual site of my game evolved around that performance limitation from times when production was targeting mobile devices. + now I have a lot of features that are connected with rest of the world indirectly, via physics interactions, end enemies are also interacting with each other in a very clumsy and funny way, which would be hard for me to mimic manually.

kubecz3k commented 6 years ago

Also a lot of the code of characters in my game were based on our platformer 3d demo, which in the past was using only dynamic character controller.

AndreaCatania commented 6 years ago

@kubecz3k each game has its implementation with its benefit / malefit so if you have checked it and it's more comfortable / performant for you, it's ok. (but do it another check).

So if you want use dynamic character, remember that use state.clear_forces(); in the first row of _integrated_forces or remove completelly the gravity on the character and apply it at runtime with set_velocity as you did.

kubecz3k commented 6 years ago

Thank you :) Not sure how clear_forces() works exactly. After using it, state will still still hold for me some valid linear_velocity for example? Will need to give it a test after it gets merge :) In mean time, I will need to check that second option: I will set body gravity_scale to 0 in editor and apply gravity manually (in a fashion of godot 2.x :)).

AndreaCatania commented 6 years ago

clear_forces is just force = Vector3() so it's nothig particular.

Rethinking on that:

not sure now, but I could increase amount of enemies significantly

Dynamic body has the advantage that can sleep and save calculations proces so basically you can have more characters in the world.

I got an idea about how optimize a bit the "_integrate_forces" function

slapin commented 6 years ago

Well, when I implemented characters on slope in Urho3D (uses Bullet too) I controlled velocity, not forcres. Alternatively you can apply forces. Basically while character body was on slope I applied force which depends on slope angle. I really think you don't need to play with gravity in this case.

On Fri, Oct 20, 2017 at 9:38 PM, Andrea Catania notifications@github.com wrote:

clear_forces is just force = Vector3() so it's nothig particular.

Rethinking on that:

not sure now, but I could increase amount of enemies significantly

Dynamic body has the advantage that can sleep and save calculations proces so basically you can have more characters in the world.

I got an idea about how optimize a bit the "_integrate_forces" function

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/godotengine/godot/issues/12171#issuecomment-338289503, or mute the thread https://github.com/notifications/unsubscribe-auth/AAAX08hC4x8p4K-qWwQD07DbIqQtdgJvks5suOixgaJpZM4P70pj .

kubecz3k commented 6 years ago

@AndreaCatania in such case I can't see how clear_forces api can be usefull. I'm ovverring all state forces in each tick anyway. And it would remove important input information for me, since in each iterate_forces tick I'm taking incoming forces modyfying them somehow and then I'm applying them to the state. (unless I misunderstood how clear_forces would work) When it comes to second idea, with removing gravity on the body completely, it works very well, but has one serious flaw. When using it, gravity fields (aka areas that modify gravity) become quite unusable, since I'm not getting any input from them...

kubecz3k commented 6 years ago

But still, this function can be useful if it could clean the forces after I fetch informations which are interesting to me (so I could read angular/linear forces, gravity which is currently affecting the body, and then erase gravity applied by bullet -> in order to apply the modified one). (probably totally misunderstood what clear_forces is doing, sorry!)

AndreaCatania commented 6 years ago

I'm ovverring all state forces in each tick anyway. And it would remove important input information for me, since in each iterate_forces tick I'm taking incoming forces modyfying them somehow and then I'm applying them to the state.

The applied forces are always cleared after each step by Bullet (After all the force effect is transferred in the velocities) so the method clear_forces doesn't remove information.

Instead what you want is get the incoming forces, It is possible to get this information in bullet, but get_force is not the right place where you can find it, and I don't know if we can support it

slapin commented 6 years ago

btw, can't we have some "extended API" for Bullet usage, at least ability to get Bullet objects from Godot objects? That would make handling corner cases in game code easier (at least in C++)

On Sat, Oct 21, 2017 at 4:04 AM, Andrea Catania notifications@github.com wrote:

I'm ovverring all state forces in each tick anyway. And it would remove important input information for me, since in each iterate_forces tick I'm taking incoming forces modyfying them somehow and then I'm applying them to the state.

The applied forces are always cleared after each step by Bullet (After all the force effect is transferred in the velocities) so the method clear_forces doesn't remove information.

Instead what you want is get the incoming forces, It is possible to get this information in bullet, but get_force is not the right place where you can find it, and I don't know if we can support it

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/godotengine/godot/issues/12171#issuecomment-338353387, or mute the thread https://github.com/notifications/unsubscribe-auth/AAAX08Kxzstks2yi70FdzEmoDFSqlCYIks5suUMhgaJpZM4P70pj .

kubecz3k commented 6 years ago

@AndreaCatania my terminology is probably a little off, when I was telling about 'incoming forces' I just meant the forces that I can read from the state itself (angular/linear velocity and gravity).

kubecz3k commented 6 years ago

After some irc discussion it seems that the most elegant way to allow manual gravity integration would be just to set gravity_scale of the body to 0, and manage gravity in integrated_forces exactly the same way how it was done before 3.0. We also should have clear forces api (#12185). Further more @AndreaCatania is thinking on some improvements in this area, by allowing to define custom gravity per body.