godotengine / godot

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

Collision Normals are not being accurately reported from move_and_collide() on non CSG meshes #67550

Open Gamepro5 opened 2 years ago

Gamepro5 commented 2 years ago

Godot version

4.0 Beta 3

System information

Windows 10; AMD Ryzen 7 3700X 8-Core Processor

Issue description

This issue is a bit hard to describe. Essentially, When colliding on corners or shapes, the surface normal does not get reported by move_and_collide() accurately. Let me give some examples.

Chapter One:

If the player's collision hull is a rectangle (stretched square), the following normals are reported:

Cube collision hull on StaticBody3D Corner

image Notice how, despite colliding at a corner, only one of the two normals is reported. (two collisions are detected but only one normal is logged) This behavior is inconsistent with the same shape but as a csg. (It works correctly on CSGs)

Cube collision hull on CSGBox3D Corner:

image

If the player's collision hull is a cylinder, the following normals are reported:

Normals are correctly reported on cylinder shapes, but not from the side (I will get to that in chapter 2).

Cylinder shape on a StaticBody3D Corner:

image Correctly detects it here for some reason. It correctly detects them on both the Static body and the CSG.

Cylinder shape on a CSGBox3D Corner:

image

If the player's collision hull is a capsule, the following normals are reported:

Capsules have the same issues as the square, but the round shape of the capsule prevents the player from actually moving because the wrong collision normal causes the next move_and_collide() to return a collision and therefore stop.

Capsule shape on StaticBody3D Corner:

image

Capsule shape on CSGBox3D Corner:

image

Chapter 2

Presumably for the same reason as the capsule collision on StaticBody3D corner from chapter 1, a similar issue can occur on walls. This only happens with cylinder shapes. image As you can see, we are on the corner of a wall. The collision normal reports suggest that we are not on a wall because they all report the floor. However, we cannot move. We can't move because move_and_collide() detected a collision for some reason. Move and collide often suffers from issues of detecting collisions and stopping even if the direction of motion would not cause a collision. In this example, the collision is presumably detected instantly because the player is intersecting the corner of this wall, so it stops motion. However, a wall collision normal isn't reported so there isn't much I can do about it.

I made this video that shows these issues in action

Steps to reproduce

  1. Download the project.
  2. Change the collision shape at will to test each condition.
  3. Click run and walk up slopes to test.

Minimal reproduction project

https://github.com/Gamepro5/Custom_CharacterBody3D_Movement_System/tree/1be17d8578a6975d9f35d317cdff8b30553d82df

rburing commented 2 years ago

The corner issues are probably due to incorrect use of non-uniform scaling in your project.

To reproduce what you are seeing more minimally (see the project attached below):

Start a new empty Godot project. Create a new 3D scene. To the 3D scene add a CharacterBody3D with a CollisionShape3D child with its shape set to a BoxShape3D. Add a script to the CharacterBody3D that moves downward using move_and_collide (setting max_collisions to at least 2) and prints all collisions. To the 3D scene add a StaticBody3D with a CollisionShape3D child with its shape set to a BoxShape3D. Rotate the StaticBody3D by 45 degrees on the z-axis and scale it by (5, 0.1, 5). Position the CharacterBody3D so that it lands on the top corner of the StaticBody3D. This results in two collisions being reported, both (0.707108, 0.707105, 0), similar to your report.

To fix this setup, remove the non-uniform scaling (5, 0.1, 5) from the StaticBody3D by resetting it to (1, 1, 1), and instead: in its CollisionShape3D, set the BoxShape3D resource's size property to (5, 0.1, 5). Visually it will look the same as before, but now the setup is such that the physics engine can work with it correctly. When running the scene with this setup, two collisions are reported, both (0, 1, 0), as desired.

Both scenes are included in the attached minimal project normals_on_corners.zip (enable Debug -> Visible Collision Shapes if you want to see something when running the scenes).

Basically, the rule is: don't scale CollisionShape3D nodes non-uniformly (and that includes scaling the parent body non-uniformly), set the size of the shape resource instead. (Note that the shape resource might be shared; in that case right click and press Make Unique if you don't want to change the size of the other collision shapes using the same resource.) Please let us know what issues remain after fixing your project to respect this rule.

Probably we should add more warnings in the documentation and in the editor, regarding non-uniform scaling of collision shapes.

(The CSG nodes' collision is a ConcavePolygonShape3D; those are probably more forgiving of transformations, since they are just a collection of faces.)

Gamepro5 commented 2 years ago

I think I understand. This would make creating maps a lot harder though: Not only do I have to change the size of box shape 3d, I also then have to change the mesh instance so it matches the shape. This means I can't drag to scale on the preview anymore, unless I'm missing something.

Zireael07 commented 2 years ago

Your meshes seem to be just boxes though? Or close enough? Just use their AABB as the size of the box shape 3d, or note down your current size*scale and hand enter the correct values.

Yes, we definitely need more warnings about scaling collision shapes, people keep running into these kind of problems.

yosoyfreeman commented 2 years ago

If scaling collision shapes almost always lead to problems and have no benefits, why the engine allow it? There is some specific user case for it? It could not be fixed to 1?

In the other hand, drawing prefabs and scaling them is a common approach it most engines, so I'm quite curious about what is the Devs perspective about this.

Nice day!

Gamepro5 commented 2 years ago

@yosoyfreeman, @rburing told me that improving this is something they are working on because most people don't know that scaling is a bad idea. Until they do, however, a warning in the editor would be a good start.