I thought this would be a simple matter of getting the mesh that defines the CollisionShape3D and checking if any of the triangles of the mesh intersect with the AABB, but that didn't work. Let me explain.

I'm doing some custom volumetric 3D pathfinding in Godot 4. For this, I need to loop over all the CollisionShape3Ds in a scene and check if they're in some region of space defined by an AABB.

I thought I'd loop over each CollisionShape3D, get its mesh, loop over each surface in the mesh, use MeshDataTool to loop over the faces in the surface, and then finally check each face for a collision with the AABB:

func check_for_colliders_in_aabb(colliders: Array[CollisionShape3D], box: AABB):
    for collider in colliders:
        var mesh = collider.shape.get_debug_mesh()
        for surface_idx in range(mesh.get_surface_count()):
            var mdt = MeshDataTool.new()
            mdt.create_from_surface(mesh, surface_idx)
            for face_idx in mdt.get_face_count():
                # Check if the face intersects with the AABB

But nothing happens. Specifically, I've figured out that mdt.get_edge_count() and mdt.get_face_count() both return zero. Also, while mesh.get_aabb() returns a correct-looking AABB, mesh.get_faces() returns an empty list.

I think this might be because the "primitive type" of the mesh is wrong. When I check mesh.surface_get_primitive_type(0), the primitive type I get back is 1 which corresponds to PRIMITIVE_LINES, so I guess the mesh doesn't have any triangles, and therefore no faces? Each CollisionShape3D is just using a BoxShape3D as it's shape, no other adjustments have been made from the default CollisionShape3D.

Note that checking if any of the vertices/edges are in the AABB is NOT an option, because the faces of the CollisionShape3Ds can be quite big, and my AABBs quite small so it's entirely possible that an AABB could be bisected by a face of a CollisionShape3D without any of the edges/vertices of that face actually intersecting with the AABB.

Is it possible to convert the mesh into one that does have triangles so that I can check each of the triangles for a collision with the AABB? If this is not possible, how would I check if some CollisionShape3D is intersecting/colliding with some AABB?


1 Answer 1


I'll suggest to check the collision using Godot physics below.

But first, about the mesh you are getting...

The Debug Mesh

It makes sense that you get lines from get_debug_mesh. The documentation says:

Returns the ArrayMesh used to draw the debug collision for this Shape3D.

Which, yes, it is a mesh, it does not have triangles. For reference, this is how a CollisionShape3D with a BoxShape3D is drawn in the engine:

CollisionShape3D with a BoxShape3D

No triangles. Yes, that is what you are getting.

On the conversion of a Shape to a Mesh

Is it possible to convert the mesh into one that does have triangles so that I can check each of the triangles for a collision with the AABB?

Not really. The primitive shapes are not meshes internally, which allows for some optimizations.

Consider, for example, an SphareShape3D... If it were a mesh internally physics would have to checks tons of faces for it, but being an sphere handled as an special case allows to check collision based on the distance to the center, which makes one of the fasters colliders, if not the fastest.

Of course, you could go into the trouble of approximating them with meshes. The easier way to go about is probably to check the type, and use one of the built-in mesh types (A BoxMesh for BoxShape3D, a SphereMesh for a SphareShape3D and so on).

Checking the collision from code

If this is not possible, how would I check if some CollisionShape3D is intersecting/colliding with some AABB?

I believe the easier way is to create a collider with a BoxShape3D for you AABB and orquestarte Godot to check the intersectation.

For this is better to avoid using Nodes (after all, if you drop a collider in the scene tree, other things might detect it, which might be problematic for the game).

Instead, let use PhysicsDirectSpaceState3D, which you can get from any Node3D like this:

var space := get_world_3d().direct_space_state

And now we have a few options for what we want:

  • collide_shape: Returns contact points.
  • intersect_shape: Returns a dictionary with collision information.
  • cast_motion: unlike the other two, this one tests if moving the shape will collide. In other words: It is a a shape cast.

It is unclear to me exactly what you need, so I'll refer you to the documentation of PhysicsDirectSpaceState3D.

Regardless, they are both used similarly, you need to pass an PhysicsShapeQueryParameters3D and the maximum number of results you want, as arguments, in that order.

You can create the PhysicsShapeQueryParameters3D like this (here I'm setting some properties to their default values for illustration purposes):

var query := PhysicsShapeQueryParameters3D.new()
query.collide_with_areas = false
query.collide_with_bodies = true
query.collision_mask = 4294967295

It is important that you set transform and shape, so let us get them from our AABB (I'm assuming the AABB is in global coordinates):

var box_shape := BoxShape3D.new()
box_shape.size = aabb.size
query.transform = Transform3D.IDENTITY.translated(aabb.get_center())
query.shape = box_shape

And we can query (collide_shape in this case):

var result := space.collide_shape(query, 32)
  • \$\begingroup\$ Thanks! Quick question: what is a "debug collision"? I'm going to read up about PhysicsDirectSpaceState3D and try implement this. I'll accept your answer if it works out (which I think it will) \$\endgroup\$
    – beyarkay
    Sep 3, 2023 at 9:01
  • \$\begingroup\$ @beyarkay Thinking about it "debug collision" is bad wording... But this is what they meant: When you enable visible collision shapes from the Debug menu you will get the colliders rendered in the game. The mesh used for that is the one you get with get_debug_mesh, and it is also used in the editor as in the screen capture I shown in the answer. \$\endgroup\$
    – Theraot
    Sep 3, 2023 at 13:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .