Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent execution order of _integrate_forces #11925

Open
Tracked by #45334
vpellen opened this issue Oct 7, 2017 · 6 comments
Open
Tracked by #45334

Inconsistent execution order of _integrate_forces #11925

vpellen opened this issue Oct 7, 2017 · 6 comments

Comments

@vpellen
Copy link

vpellen commented Oct 7, 2017

Operating system or device, Godot version, GPU Model and driver (if graphics related):
v2.1.4 stable

Issue description:
The standard 2d physics step performs force integration before velocity integration. Rigid Bodies have a method binding called _integrate_forces that's designed to replace force integration with custom logic. However, within a standard step, the _integrate_forces method executes after the velocity integration stage, rather than before.

This is mainly a consistency issue. It can partially be worked around by inserting integration code into the _fixed_process method, but this can result in minor race conditions if other nodes attempt to modify a rigid body's physics parameters during the fixed physics stage.

@groud groud added this to the 2.1 milestone Oct 9, 2017
@bojidar-bg
Copy link
Contributor

Not sure if I understand the issue correctly, but can't it be worked around by turning "Custom Integrator" on, and calling state.integrate_forces() manually?

@vpellen
Copy link
Author

vpellen commented Oct 19, 2017

In spite of its name, state.integrate_forces() does not actually integrate forces. At least it doesn't integrate all the forces that the default integration does. But that's a separate issue entirely.

The problem is execution order.

By default, each physics cycle, the engine will integrate forces (i.e. calculate rigid body velocities from their respective forces) and then integrate velocities (i.e. calculate the displacement of rigid bodies based on their respective velocities). This is all fine and dandy.

There's a virtual method for rigid bodies called _integrate_forces(). It's designed to replace the built-in force integration code with your own code. Theoretically, you should be able to call state.integrate_forces() within the _integrate_forces() method, and the program should run exactly like default.

It does not.

The problem is that _integrate_forces() is called after the engine integrates velocities, whereas the default force integration is called before. This seems minor, and it is, but it still throws off the physics simulation slightly.

This is something I may have to dig into myself and I'm likely one of the only people unreasonable enough to care about it honestly.

@bojidar-bg
Copy link
Contributor

Ok, makes sense, looking at the code also confirms your theory.
Basically, there are a few steps the physics engine goes through:

  • integrate_forces() - detects all area2Ds overlapping the body, does some integration of applied_force-es.
  • Generate, constraint and solve islands - checks for collisions
  • integrate_velocities() - calls _direct_state_changed on the RigidBody2D, which then calls _integrate_forces and then checks the various collisions. This shouldn't happen before the islands are solved, as then the RigidBody2D would have outdated/invalid data about its collisions and velocity.

@akien-mga akien-mga removed this from the 2.1 milestone Sep 17, 2018
@akien-mga
Copy link
Member

Is this still valid in the current master branch?

@KoBeWi
Copy link
Member

KoBeWi commented Jun 13, 2019

This is the code I used for testing (in 2.1.5):

extends RigidBody2D

func _ready():
	print("ready ", get_pos())
	set_fixed_process(true)

func _fixed_process(delta):
	print("process ", get_pos())

func _integrate_forces(state):
	print("integrate ", get_pos())

If I understand the issue correctly, these 3 should output the same position at the start. b2b06dd with equivalent code behaves the same, so I guess it's not fixed.

Unless I tested wrongly.

@ghost
Copy link

ghost commented Aug 6, 2020

I think my problem might be related to this issue but I'm not sure.

I have the following scenario: two RigidBody2Ds (player and the ball). Player's velocity is controlled by the keyboard in _integrate_forces, collisions with the ball work as expected.

I wanted to implement a kick - player can kick the ball which means setting its velocity right after the collision. For that purpose I use body_entered player's signal to detect the collision, calculate the target velocity of the ball and then set it in _integrate_forces next time when it's called. I put some print functions in ball's script to see how it goes:

_integrate_forces
_physics_process: velocity = (0, 1219.997925)
kick: current velocity: (0, 1219.997925), target: (1191.503906, -911.218201)
_integrate_forces
_integrate_forces: collision with Player1
_integrate_forces: setting velocity
_integrate_forces: before: (2537.907959, -1889.9375)
_integrate_forces: after: (1191.503906, -911.218201)
_physics_process: velocity = (2537.907959, -1889.9375)
_integrate_forces
_physics_process: velocity = (1189.518066, -893.032837)
_integrate_forces
_physics_process: velocity = (1187.535522, -874.877747)
_integrate_forces
_physics_process: velocity = (1185.556274, -856.75293)

I can't apply new velocity right after the collision because by the time I want do that, physics engine calculates its own velocity after collision and instantly applies it to the object. This results in a noticeable jitter when the initial ball's velocity is high but the target velocity is small.

Let me know if this could be an engine thing or me doing things in a wrong way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants