Unexpected collision normals near touching edges of adjacent collision meshes

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Jason N

I’ve been developing a 3D game where the maps are laid out using GridMap (including using StaticBody and CollisionShapes in the MeshLibrary). However, I’ve noticed that when placing cubes next to each other, the collision normals can become strange near edges where the cubes meet.

I’ve also noticed that this same thing happens when simply placing cubes with BoxShape collision shapes next to each other:

I think this has to do with how the collision normals are interpolated between faces with different normals - the two cubes seem to interfere with each other. This isn’t all that unexpected, but from a player’s point of view, it would be ridiculous for them to throw a ball on a seemingly flat surface only to have it change trajectory completely as if it had hit an edge.

Is there any way for me to change this behaviour so that the coplanar surfaces on connected cubes behave like a single face? My only idea right now is to create one ConvexPolygonShape in GDScript that joins up the faces, but that doesn’t seem like an optimal way of dealing with this. I’ve also tried adjusting CollisionShape margins, but nothing seems to totally solve the issue.

Any help would be greatly appreciated.

:bust_in_silhouette: Reply From: kidscancode

It’s likely that adjacent collision shapes aren’t merging because their vertices aren’t precisely aligned. Example: If your grid size is (1, 1, 1) then the vertices of your BoxShape collider must be whole numbers, not (0.9999, 1.00002, 0.982453), etc. GridMap tries to merge adjacent collision shapes, but if two aren’t exactly aligned, then it has to insert some edges to do so, and that can cause what you’re seeing.

Thanks for the fast answer. That makes sense, however, I have got whole numbers for the BoxShapes - I just typed (1, 1, 1) for all of them, and the same for the GridMap cell size. They certainly display as whole numbers in the editor, but the same issue still persists.

Is there any provision to allow for an amount of inaccuracy when merging vertices in the GridMap? I think that would solve my problem (even though as far as I know, everything should be exact).

Jason N | 2019-03-21 01:40

Well, that was the most likely culprit. If it’s not that, then we have to dig deeper. How are you testing the collision normals?

kidscancode | 2019-03-21 03:13

I’m testing the normals by casting a ray from the mouse position then using an ImmediateGeometry node called Line to show what the collision result is.

extends Spatial

export var ray_length = 10

func _ready():
	$Line.set_as_toplevel(true)

func _physics_process(delta):
	var viewport = self.get_viewport()
	var camera = viewport.get_camera()
	var mouse_position = viewport.get_mouse_position()
	
	var from = camera.project_ray_origin(mouse_position)
	var to = from + camera.project_ray_normal(mouse_position) * self.ray_length
	
	var space_state = self.get_world().direct_space_state
	var collision = space_state.intersect_ray(from, to)
	
	if collision:
		$Line.clear()
		$Line.begin(Mesh.PRIMITIVE_LINES)
		$Line.add_vertex(collision.position)
		$Line.add_vertex(collision.position + collision.normal)
		$Line.end()

In the actual game, I’m using a KinematicBody and using move_and_collide() and have noticed the same strange normals and hence strange bounce path using velocity.bounce(collision.normal)(where velocity is my linear velocity Vector3) near edges of the cells.

If it would be useful, I can upload the entire test project I’m using. Thanks for your help.

Jason N | 2019-03-21 03:33

Are we sure that GridMap tries to merge adjacent collision shapes? I can’t seem to find anything that looks like it does that in the Godot source (I’ve noticed that just placing adjacent BoxShapes as children of a normal StaticBody also gives exactly the same results as the GridMap).

I’m thinking that this is probably just how this works at the moment (I mean, it’s not really incorrect, it just behaves strange from a player’s perspective).

Jason N | 2019-03-21 23:49

Update: This doesn’t seem to be an issue when using ConcavePolygonShapes instead of BoxShapes. Although I can’t imagine why that would be the case, my issue seems to be solved by this (ConcavePolygonShapes don’t seem to interpolate the normals, which keeps everything exact).

Another update: Even though using ConcavePolygon shapes fixes the issue when casting rays on the surfaces, I was still having issues with getting my ball (SphereShape) to bounce with the correct normal near edges. I ended up just casting a ray from the centre of the ball to the contact position reported by move_and_collide - the normal given by the ray cast ends up being correct even though the one given by move_and_collide is wrong/unexpected.

Jason N | 2019-03-22 02:25

Yo @jason N thank you with your ConcavePolygonShape tip.

It looks to me like ConvexPolygonShape does not have this problem.

I worked on this problem for A VERY LONG TIME. And came up with several hack work arounds.

I wrote a mesh merger test scene and found out that removing interior faces fixes the problem when using a Rigid Body. But its pretty tough to do that.

Eventually I used move_and_collide and overrode the collision normals to be in increments of 90 degrees. That fixed it but felt really hacky.

Your solution of just using ConvexPolygonShape fixes it! WOW!

I’m like nearing release of my golf game and finally now I get a solution. Thank you so much.

00jknight | 2020-04-23 16:53