-
-
Notifications
You must be signed in to change notification settings - Fork 21.3k
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
Add state sync after call to _integrate_forces
in _body_state_changed
#79977
Conversation
scene/3d/physics_body_3d.cpp
Outdated
set_global_transform(p_state->get_transform()); | ||
|
||
linear_velocity = p_state->get_linear_velocity(); | ||
angular_velocity = p_state->get_angular_velocity(); | ||
|
||
inverse_inertia_tensor = p_state->get_inverse_inertia_tensor(); | ||
|
||
if (sleeping != p_state->is_sleeping()) { | ||
sleeping = p_state->is_sleeping(); | ||
emit_signal(SceneStringNames::get_singleton()->sleeping_state_changed); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be a good idea to move all this to a new private method instead, like a void _sync_body_state(PhysicsDirectBodyState3D *p_state)
, so that you can't accidentally miss one or the other when adding to it. Same goes for the other classes as well.
scene/3d/physics_body_3d.cpp
Outdated
@@ -2925,6 +2937,9 @@ void PhysicalBone3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { | |||
|
|||
GDVIRTUAL_CALL(_integrate_forces, p_state); | |||
|
|||
linear_velocity = p_state->get_linear_velocity(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realize you copied the code from above the _integrate_forces
call, but this looks odd to me. I don't see why this shouldn't synchronize as much mutable state as possible both before and after _integrate_forces
, meaning velocities, sleep state and transform.
As it is right now, it looks like PhysicalBone3D::_integrate_forces
doesn't actually get an up-to-date transform like it should be getting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was also confused as to why the transform and sleeping were not synced here, should I sync them too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, PhysicalBone3D
doesn't seem to have sleeping
or inverse_inertia_tensor
, we need to only sync transform or am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, there is no sleeping
(or inverse_inertia_tensor
) in PhysicalBone3D
, despite there being a can_sleep
, so that simplifies things a bit I guess, since it's only the cached state we're interested in syncing.
I can't see a reason why the transform shouldn't be synced, and the set_ignore_transform_notification
"scope" should probably span across the _integrate_forces
call as well, similar to how it's done in RigidBody3D
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, I'll do that
9bf784f
to
1dbfd2a
Compare
I can't seem to add a comment to these lines, since they're not in proximity of the actual changes, but these lines in |
scene/3d/physics_body_3d.cpp
Outdated
|
||
set_ignore_transform_notification(true); | ||
set_global_transform(global_transform); | ||
set_ignore_transform_notification(false); | ||
_on_transform_changed(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I can nitpick one last thing it would be to move this _on_transform_changed()
in PhysicalBone3D::_body_state_changed
up to right below set_ignore_transform_notification(false)
, similar to how it was before, since they go hand-in-hand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just gave the ragdoll from GDQuest's godot-4-new-features
repo a try, and I can confirm that the transform for PhysicalBone3D
was indeed stale in _integrate_forces
before these changes, and is now as expected.
So this all looks good to me.
(I assume someone in a more official capacity will need to also look over these changes though.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense to me, and fixes the bug.
The behavior change should be mentioned in the release notes. To get the old behavior back (which probably nobody really wants) you would have to do your own caching.
Note that the force integration callback is currently only called using
godot/scene/3d/physics_body_3d.cpp
Line 503 in dcd187d
GDVIRTUAL_CALL(_integrate_forces, p_state); |
in the scene/
code here, and it doesn't go through the physics server, i.e. body_set_force_integration_callback
is currently never called from scene/
code, and even if it were, the callback is never used (at least in Godot Physics). I documented this when I noticed it, but I think this should be fixed as well (in another PR), so that bodies created in the physics server can have a force integration callback too.
_integrate_forces
in _body_state_changed
@rburing Could you quickly summarize what kind of behavior is affected? |
@rburing Not to derail this PR too much, but this is not correct. I can't speak for 2D, but the code looks very similar to the 3D one, where the callback that's set using The Godot Physics implementation does however only invoke the callback if you provide a piece of userdata along with the callback, as seen in the link there, which is likely a bug and might be why you thought it wasn't used. The documentation for However, your overall point about these custom integration callbacks being left out of the synchronization that this PR improves upon is a good one. I'm not sure how you would fix this to be honest, since the custom integration callback is invoked before the |
Thanks! |
A physics body node has state (of the corresponding body in the physics server) and properties (on the node). The order of processing in one physics tick used to be: (1) the equivalent of So it affects the behavior of physics body scripts overriding both By the way, writing the above explanation makes me think @mihe Sorry, I got mixed up when writing that doc, I'll fix it (plus the other documentation errors you mentioned). The callback that can be set using
The custom integration callback takes the physics server body's state as input, so I don't think there's an issue with stale state there. |
Maybe I'm misunderstanding your frame numbering, but So a frame used to be:
Meaning if Now instead a frame is:
I guess if one considers
I guess the scenario I had in mind was if somebody used this together with a |
in issue #79835 , the root cause is that
_physics_process
is called after_integrate_forces
(called from RigidBody3D::_body_state_changed) while_integrate_forces
modifiesGodotBody3D
's linear_velocity,_physics_process
reads from now obsoleteRigidBody3D::linear_velocity
and when we update it usingRigidBody3D::set_linear_velocity
which also updatesGodotBody3D::linear_velocity
.This can be prevented by updating
RigidBody3D
's mutable state as soon as we return from_integrate_forces
, which is what I have added.