Skip to content

SoftBody3D: process set_mesh() changes directly #108061

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

simpkins
Copy link
Contributor

@simpkins simpkins commented Jun 27, 2025

This updates MeshInstance3D::set_mesh() to be a virtual method, so that SoftBody3D can override it.

The SoftBody3D code always wants to replace the input mesh with a new unique mesh that is created with the Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE flag enabled, allowing it to dynamically modify the mesh and without affecting other users of the original resource. (However, it does not create a dynamic mesh in the editor, because it does want the original input mesh saved in the scene.)

Previously, SoftBody3D did not override set_mesh(), and instead simply periodically checked to see if the mesh property had been modified and was different from the old value it remembered. It did this check at various points in time. Precisely when it would check the mesh depends on the object settings, whether the code is running in the editor or not, and these checks have moved around over time. In past releases it normally checked in a frame_pre_draw callback, but the recent physics interpolation logic changed it to check in NOTIFICATION_INTERNAL_PHYSICS_PROCESS instead.

This behavior made it rather confusing to reason about when a SoftBody3D object would resync the physics state with the MeshInstance3D mesh, and when it would be out-of-date. Often in the editor it would not notice changes to the mesh, resulting in confusing behavior and bugs.

This commit updates SoftBody3D to process set_mesh() calls directly, so it can never be in a state where it can no longer be out-of-sync with the parent MeshInstance3D state.

This also fixes the code to check that the mesh is actually supported before allowing it to be set, and to correctly update editor warnings after the mesh is changed.

This updates `MeshInstance3D::set_mesh()` to be a virtual method, so that
`SoftBody3D` can override it.

The `SoftBody3D` code always wants to replace the input mesh with a new unique
mesh that is created with the `Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE` flag
enabled, allowing it to dynamically modify the mesh and without affecting other
users of the original resource.  (However, it does not create a dynamic mesh in
the editor, because it does want the original input mesh saved in the scene.)

Previously, `SoftBody3D` did not override `set_mesh()`, and instead simply
periodically checked to see if the `mesh` property had been modified and was
different from the old value it remembered.  It did this check at various
points in time.  Precisely when it would check the mesh depends on the object
settings, whether the code is running in the editor or not, and these checks
have moved around over time.  In past releases it normally checked in a
`frame_pre_draw` callback, but the recent physics interpolation logic changed
it to check in `NOTIFICATION_INTERNAL_PHYSICS_PROCESS` instead.

This behavior made it rather confusing to reason about when a `SoftBody3D`
object would resync the physics state with the MeshInstance3D mesh, and when it
would be out-of-date.  Often in the editor it would not notice changes to the
`mesh`, resulting in confusing behavior and bugs.

This commit updates `SoftBody3D` to process `set_mesh()` calls directly, so it
can never be in a state where it can no longer be out-of-sync with the parent
MeshInstance3D state.

This also fixes the code to check that the mesh is actually supported
before allowing it to be set, and to correctly update editor warnings
after the mesh is changed.

Fixes godotengine#108036 and godotengine#108059.
@simpkins simpkins force-pushed the soft_body_set_mesh branch from 191e789 to 05738d8 Compare June 27, 2025 23:18
Comment on lines +595 to +599
// The soft body physics simulation does not run in the editor,
// so we do not create a dynamically modifiable mesh in this case.
MeshInstance3D::set_mesh(p_mesh);
update_configuration_warnings();
return;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is one behavior change that I think is worth calling out here, in case anyone thinks it I should keep the old behavior:

After this commit, the code no longer calls PhysicsServer3D::get_singleton()->soft_body_set_mesh() in the editor. The old code would call soft_body_set_mesh() in the editor when processing NOTIFICATION_ENTER_WORLD (although it would not update the physics server if the mesh changed in the future). The old code would pass in the original non-dynamic mesh as-is when running in the editor.

If desired I could update this code to still call soft_body_set_mesh() when running in the editor here. As best as I can tell though, I don't believe this matters.

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

Successfully merging this pull request may close these issues.

Out of bounds errors when pinning SoftBody3D vertices in the editor SoftBody3D crashes when given a non-triangle mesh
2 participants