Jondolf / avian

ECS-driven 2D and 3D physics engine for the Bevy game engine.
https://crates.io/crates/avian3d
Apache License 2.0
1.23k stars 100 forks source link

Clockwise triangle collider doesn't work #368

Open JonasAAA opened 1 month ago

JonasAAA commented 1 month ago

Versions

bevy 0.13.2 bevy_xpbd_2d 0.4.2

Description

It seems that the collider of a clockwise ordered Triangle2D doesn't register collisions with other polygons, such as triangles, rectangles, etc.

Example

Below code spawns a triangle with vertices in the clockwise direction and a square. The two shapes are overlapping at spawn, so that should be printed, and shapes should be moved to be disjoint. Neither of these happen.

However, if I swap the triangle vertices so that they are ordered anticlockwise, everything works as expected - I get a message about entities overlapping at spawn, and the shapes are flung out of view very quickly.

use bevy::{prelude::*, sprite::MaterialMesh2dBundle};
use bevy_xpbd_2d::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(PhysicsPlugins::default())
        .insert_resource(Gravity(Vec2::ZERO))
        .add_systems(Startup, (setup_camera, spawn_objects))
        .run();
}

fn setup_camera(mut commands: Commands) {
    commands.spawn(Camera2dBundle::default());
}

fn spawn_objects(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<ColorMaterial>>,
) {
    let shape = Triangle2d::new(
        Vec2::new(0.0, -100.0),
        Vec2::new(0.0, 100.0),
        Vec2::new(200.0, 0.0),
    );

    commands.spawn((
        MaterialMesh2dBundle {
            mesh: meshes.add(shape).into(),
            material: materials.add(Color::BLUE),
            transform: Transform::from_translation(Vec3::new(-75.0, 0.0, 0.0)),
            ..default()
        },
        RigidBody::Dynamic,
        shape.collider(),
    ));

    let shape = Rectangle::new(100.0, 100.0);
    commands.spawn((
        MaterialMesh2dBundle {
            mesh: meshes.add(shape).into(),
            material: materials.add(Color::YELLOW),
            transform: Transform::from_translation(Vec3::new(50.0, 0.0, 0.0)),
            ..default()
        },
        RigidBody::Dynamic,
        shape.collider(),
    ));
}
Jondolf commented 1 month ago

I've noticed this too, I think it's more of an issue for Parry (the collision detection library). What we could do on our side though is to detect the triangle winding order in the collider constructor and flip it if it's clockwise.

The main con of this approach is that the order of the triangle vertices would of course no longer match the given input in those cases, but I think a functional collider is still more important than that, and we can mention it in the documentation anyways. Alternatively, we could just log an error or have a debug assertion for clockwise triangles.

JonasAAA commented 1 month ago

What we could do on our side though is to detect the triangle winding order in the collider constructor and flip it if it's clockwise.

This seems the best approach to me. It could also be worth it to log an info message in case the vertices were swapped, just so the users are aware of this. Since I, for example, just call shape.collider() without reading the documentation for that particular shape and wouldn't be aware of that.