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

Fix user changes handling #803

Merged
merged 7 commits into from
Mar 28, 2025
Merged

Fix user changes handling #803

merged 7 commits into from
Mar 28, 2025

Conversation

Vrixyz
Copy link
Contributor

@Vrixyz Vrixyz commented Mar 5, 2025

Fix #802

Note: Fixing those + adding tests is a good first step but we should thrive for making those mistakes more difficult to make altogether.

Vrixyz added 3 commits March 5, 2025 09:33

Verified

This commit was signed with the committer’s verified signature.
olegbespalov Oleg Bespalov
@@ -972,7 +972,7 @@ impl RigidBodyColliders {

// Set the modification flag so we can benefit from the modification-tracking
// when updating the narrow-phase/broad-phase afterwards.
co.changes |= ColliderChanges::POSITION;
co.changes |= ColliderChanges::MODIFIED | ColliderChanges::POSITION;
Copy link
Contributor Author

@Vrixyz Vrixyz Mar 5, 2025

Choose a reason for hiding this comment

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

This makes me wonder if we should change ColliderChanges::POSITION (and the likes) from:
const POSITION = 1 << 3
to
const POSITION = 1 << 3 | 1 << 0; (adding ColliderChanges::MODIFIED to it)

This would clarify their relation and make mistakes harder to make.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This change is probably not possible because MODIFIED is used to check if a collider is part of the modified_colliders list. This seems difficult to maintain, I imagine searching for modified_colliders.push should be able to lead to a MODIFIED bit to be added to that collider, but it's sometimes tricky to assess.

I imagine changing modified_colliders to a Hashmap may be less performant than storing that in the bitfield, but I'm throwing the idea.

@@ -66,6 +66,7 @@ impl ColliderSet {
self.modified_colliders.clear();
let modified_colliders = &mut self.modified_colliders;
self.colliders.iter_mut().map(move |(h, b)| {
b.changes |= ColliderChanges::MODIFIED;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure this is correct ; the fix may be more around https://github.com/Vrixyz/rapier/blob/607f0988596d346b6afa70e5cfbc8f0f3519e02c/src/geometry/collider.rs#L271 ; to set ColliderChanges::MODIFIED flag too (see https://github.com/dimforge/rapier/pull/803/files#r1980964215 comment for a longer term fix maybe ?)

And then add then refill self.modified_colliders only when applicable (check changes flag)

// ball_body.set_rotation(nalgebra::UnitComplex::new(1.0), true);
ball_body.set_enabled(false);
}
}
Copy link
Contributor

@Johannes0021 Johannes0021 Mar 5, 2025

Choose a reason for hiding this comment

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

This might be a better test because it covers both RigidBodyChanges::POSITION with enable and disable, and it doesn't run for 200 iterations.
What do you think?

use rapier2d::prelude::*;

fn main() {
    // Create other structures necessary for the simulation.
    let mut rigid_body_set = RigidBodySet::new();
    let mut collider_set = ColliderSet::new();
    let gravity = vector![0.0, -9.81];
    let integration_parameters = IntegrationParameters::default();
    let mut physics_pipeline = PhysicsPipeline::new();
    let mut island_manager = IslandManager::new();
    let mut broad_phase = DefaultBroadPhase::new();
    let mut narrow_phase = NarrowPhase::new();
    let mut impulse_joint_set = ImpulseJointSet::new();
    let mut multibody_joint_set = MultibodyJointSet::new();
    let mut ccd_solver = CCDSolver::new();
    let mut query_pipeline = QueryPipeline::new();
    let physics_hooks = ();
    let event_handler = ();


    // Create the ball with default values for translation, position and enabled state
    let rigid_body = RigidBodyBuilder::dynamic()
        .translation(vector![0.0, 0.0])
        .rotation(0.0)
        .build();
    let collider = ColliderBuilder::ball(0.5)
        .enabled(true)
        .build();
    let ball_body_handle = rigid_body_set.insert(rigid_body);
    collider_set.insert_with_parent(collider, ball_body_handle, &mut rigid_body_set);


    physics_pipeline.step(
        &gravity,
        &integration_parameters,
        &mut island_manager,
        &mut broad_phase,
        &mut narrow_phase,
        &mut rigid_body_set,
        &mut collider_set,
        &mut impulse_joint_set,
        &mut multibody_joint_set,
        &mut ccd_solver,
        Some(&mut query_pipeline),
        &physics_hooks,
        &event_handler,
    );


    // This causes the error:

    // Test RigidBodyChanges::POSITION and disable
    {
        let ball_body = &mut rigid_body_set[ball_body_handle];

        // Also, change the translation and rotation to different values
        ball_body.set_translation(vector![1.0, 1.0], true);
        ball_body.set_rotation(nalgebra::UnitComplex::new(1.0), true);

        ball_body.set_enabled(false);
    }

    physics_pipeline.step(
        &gravity,
        &integration_parameters,
        &mut island_manager,
        &mut broad_phase,
        &mut narrow_phase,
        &mut rigid_body_set,
        &mut collider_set,
        &mut impulse_joint_set,
        &mut multibody_joint_set,
        &mut ccd_solver,
        Some(&mut query_pipeline),
        &physics_hooks,
        &event_handler,
    );


    // Test RigidBodyChanges::POSITION and enable
    {
        let ball_body = &mut rigid_body_set[ball_body_handle];

        // Also, change the translation and rotation to different values
        ball_body.set_translation(vector![0.0, 0.0], true);
        ball_body.set_rotation(nalgebra::UnitComplex::new(0.0), true);

        ball_body.set_enabled(true);
    }

    physics_pipeline.step(
        &gravity,
        &integration_parameters,
        &mut island_manager,
        &mut broad_phase,
        &mut narrow_phase,
        &mut rigid_body_set,
        &mut collider_set,
        &mut impulse_joint_set,
        &mut multibody_joint_set,
        &mut ccd_solver,
        Some(&mut query_pipeline),
        &physics_hooks,
        &event_handler,
    );
}

Copy link
Contributor

Choose a reason for hiding this comment

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

I rewrote it again, set default values at the beginning, and ensured that the values change.

@Vrixyz Vrixyz requested a review from sebcrozet March 7, 2025 14:14
Copy link
Member

@sebcrozet sebcrozet left a comment

Choose a reason for hiding this comment

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

Looking good, thanks! I took it one step further by defining a wrapper around the modified handle Vec. That way we can avoid future mistakes without having to introduce the overhead of a HashSet.

@sebcrozet sebcrozet merged commit 176c3ba into dimforge:master Mar 28, 2025
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Assertion failure: position change, enabled state change, and missing MODIFIED flag
3 participants