godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.93k stars 21.15k forks source link

[Bullet] Convex Collision Sibling wrong margin with Bullet #27427

Open rogeriodec opened 5 years ago

rogeriodec commented 5 years ago

Godot version: 3.1

OS/device including version: Windows 10 x64 / NVIDIA GeForce GTX 1060 6GB / Intel Core i7 4790K

Issue description: When a CollisionShape is created from a mesh using "Create Convex Collision Sibling", it's being it is getting away from the bottom cube by the "collision margin" distance (0.04):

image

This only happens with ConvexPolygonShape.

With ConcavePolygonShape or even a BoxShape or other native collision shapes, this does not occur.

image

Steps to reproduce: 1) Run the attached project. It's with a CollisionShape as ConvexPolygonShape and you'll see the margin. 2) Change the red cube CollisionShape to BoxShape or generate a ConcavePolygonShape and the margin is not there.

Minimal reproduction project: testes.zip

akien-mga commented 4 years ago

This is still reproducible in 3.2.2 RC 2 with the above project.

It only affects the Bullet backend, GodotPhysics doesn't have this margin.

CC @AndreaCatania @madmiraal

AndreaCatania commented 4 years ago

It's how bullet handles the margin. Depending the shape type, it may add or remove the specified amount of margin; this because each algorithm perform better with positive or negative margin.

Try to lower the 0.04 margin to something smaller or increase the mesh size.

Make the engine to automatically mask this margin is not a good idea IMO.

akien-mga commented 4 years ago

Maybe this should be documented in the ConvexPolygonShape class reference?

And/or it might be worth having a doc page about differences between GodotPhysics and Bullet, like we have for GLES2 vs GLES3.

AndreaCatania commented 4 years ago

Yes, I think that would be useful have the list of the various differences. Document this behaviour would be really useful too, but I would add somewhere globally, because it's true for all the shapes.

madmiraal commented 4 years ago

I would still consider this a bug, because the type of Shape used shouldn't change it's behaviour.

It brings up the debate on why collision masks are required and how they are used. As @AndreaCatania points out, the margin makes the GJK distance algorithm an efficient way of determining collisions by terminating if the distance is known to be less than the margin.

In Bullet physics Spheres and Capsules are all margin around a point or a line respectively, whereas Boxes become rounded as shown beautifully here. To make sure a BoxShape is not bigger than expected, the size can be adjusted proportionally. However, this is not happening with the ConvexPolygonShape; hence the gap presented in this issue.

Godot uses collision margins differently. I've described this in detail here, but the short, over-simplified version is: it uses the margin to push objects apart and then allows them to come back together again.

AndreaCatania commented 4 years ago

The reason why I would not mark this as bug is because try to mask this issue by making the shape bigger or smaller than the mesh, when generating the collision shape is not a good option: Each physics engine has its own way to handle the margins and just mask this issue will just invert the problem, that will be then present with Godot Physics.

However, this is not all; because someone may add another physics engine (even if not supported by the Godot community, or just privately for their game).

In any case, the differences between physics engines exists (otherwise would not even make sense integrate a new one), and all the features of the Game Engine should just do the "right" thing. So is better document instead of mask the various differences between physics engines.

Of course, this is not always true, but for this case I think that is better document the difference and allow the developer choose how to deal with it:

madmiraal commented 4 years ago

I don't know what the solution is. I haven't looked into it. I'm definitely not suggesting the issue is masked; for all the reasons stated and more. But not knowing what the solution is doesn't stop it from being a bug. Whether the issue lies within Bullet or within Godot's implementation of Bullet doesn't stop it from being a bug. In the meantime, I agree that, as long as there isn't a solution, the known issue should be documented.

jitspoe commented 4 years ago

I think the best solution at the moment is to make the margin very small and use double precision in bullet. The 4cm margin (8cm total between 2 objects) is pretty massive, and not only does it create gaps, but it creates potentially undesired behavior along edges (unexpected normals).

hoontee commented 4 years ago

The issue isn't easily fixable for CollisionPolygons due to the lack of a margin property. You'd have to create new ConvexPolygonShapes with the mesh data and corrected margins:

if parent is PhysicsBody and child is CollisionPolygon:
    var body = parent.get_rid()
    for i in PhysicsServer.body_get_shape_count(body):
        var shape = PhysicsServer.body_get_shape(body, i)
        if PhysicsServer.shape_get_type(shape) == PhysicsServer.SHAPE_CONVEX_POLYGON:
            var new_convex_polygon_shape = ConvexPolygonShape.new()
            new_convex_polygon_shape.margin = 0
            new_convex_polygon_shape.set_points(PhysicsServer.shape_get_data(shape))
            var new_collision_shape = CollisionShape.new()
            new_collision_shape.shape = new_convex_polygon_shape
            new_collision_shape.transform = child.transform
            parent.add_child(new_collision_shape)
    child.free()