# How Godot's 2D and 3D Physics Servers Manage Collision Detection

> Explore how Godot's 2D and 3D physics servers manage collision detection via the PhysicsServer and PhysicsDirectSpaceState APIs, supporting GodotPhysics and Jolt backends for efficient queries.

- Repository: [Godot Engine/godot](https://github.com/godotengine/godot)
- Tags: internals
- Published: 2026-02-26

---

**Godot isolates low-level collision detection behind the PhysicsServer abstraction, exposing ray-casting, point-queries, and shape-queries through the PhysicsDirectSpaceState API that delegates to backend implementations such as GodotPhysics or Jolt.**

Godot’s collision detection system is decoupled from the scene graph through the **PhysicsServer** architecture. According to the godotengine/godot source code, the engine maintains separate singleton servers for 2D and 3D worlds that manage broad-phase and narrow-phase collision tests behind a unified query interface. This design allows game logic to perform complex spatial queries without direct dependency on the underlying physics backend.

## Architecture of Godot Collision Detection

The collision detection stack is organized into distinct layers that separate the scripting API from the physics implementation.

### The PhysicsServer Singletons

Godot instantiates **PhysicsServer2D** and **PhysicsServer3D** as singletons (`PhysicsServer2D::singleton` and `PhysicsServer3D::singleton`) during engine startup. These singletons manage the physics world, create bodies and areas, and store collision layers and masks. High-level scene nodes such as `PhysicsBody2D` and `CollisionObject3D` internally reference these servers to synchronize their state.

### Direct Space State Interface

Query methods are exposed through **PhysicsDirectSpaceState2D** and **PhysicsDirectSpaceState3D**. These classes provide the primary interface for runtime collision detection via methods like `intersect_ray`, `intersect_point`, and `intersect_shape`. When a script calls one of these methods, the space state forwards the request to the concrete physics server implementation.

### Backend Delegation

The actual collision calculations occur in pluggable backends (GodotPhysics, Jolt, or custom implementations). Each backend overrides the virtual query functions declared in [`physics_server_2d.h`](https://github.com/godotengine/godot/blob/main/physics_server_2d.h) and [`physics_server_3d.h`](https://github.com/godotengine/godot/blob/main/physics_server_3d.h), executing broad-phase spatial hashing or BVH traversal followed by narrow-phase shape intersection tests.

## 2D Collision Query Flow

The 2D query pipeline demonstrates how Godot collision detection marshals data between script and engine internals.

A typical ray-cast begins with a script call to `space_state.intersect_ray()`. This invokes `PhysicsDirectSpaceState2D::_intersect_ray` in [`servers/physics_2d/physics_server_2d.cpp`](https://github.com/godotengine/godot/blob/main/servers/physics_2d/physics_server_2d.cpp) (lines 340–357), which constructs a `RayResult` struct and calls the pure virtual `intersect_ray` method:

```cpp
// servers/physics_2d/physics_server_2d.cpp
Dictionary PhysicsDirectSpaceState2D::_intersect_ray(RequiredParam<PhysicsRayQueryParameters2D> rp_ray_query) {
    EXTRACT_PARAM_OR_FAIL_V(p_ray_query, rp_ray_query, Dictionary());
    RayResult result;
    bool res = intersect_ray(p_ray_query->get_parameters(), result);
    if (!res) return Dictionary();
    Dictionary d;
    d["position"] = result.position;
    d["normal"]   = result.normal;
    …
    return d;
}

```

The backend implementation performs spatial queries against the 2D broad-phase structure, tests candidate shapes using narrow-phase algorithms, and fills the `RayResult` with collision data including position, normal, and collider ID. The wrapper then converts this struct into a `Dictionary` for GDScript consumption.

## 3D Collision Query Flow

The 3D pipeline mirrors the 2D architecture with dimension-specific data types (`Vector3`, `Transform3D`). The entry point is `PhysicsDirectSpaceState3D::_intersect_ray` in [`servers/physics_3d/physics_server_3d.cpp`](https://github.com/godotengine/godot/blob/main/servers/physics_3d/physics_server_3d.cpp) (lines 363–381):

```cpp
// servers/physics_3d/physics_server_3d.cpp
Dictionary PhysicsDirectSpaceState3D::_intersect_ray(RequiredParam<PhysicsRayQueryParameters3D> rp_ray_query) {
    EXTRACT_PARAM_OR_FAIL_V(p_ray_query, rp_ray_query, Dictionary());
    RayResult result;
    bool res = intersect_ray(p_ray_query->get_parameters(), result);
    if (!res) return Dictionary();
    Dictionary d;
    d["position"] = result.position;
    d["normal"]   = result.normal;
    d["face_index"] = result.face_index;
    …
    return d;
}

```

The virtual `intersect_ray` declared in [`physics_server_3d.h`](https://github.com/godotengine/godot/blob/main/physics_server_3d.h) (line 129) is overridden by the active 3D backend to execute the actual collision test against the spatial partitioning structure.

## Thread Safety and Command Queuing

Both physics servers support multi-threaded operation through the **wrap-mt** classes (`PhysicsServer2DWrapMT` and `PhysicsServer3DWrapMT`). When running on a dedicated physics thread, these wrappers enqueue commands (e.g., `step`, `sync`, `flush_queries`) into a thread-safe command queue.

In [`servers/physics_2d/physics_server_2d_wrap_mt.cpp`](https://github.com/godotengine/godot/blob/main/servers/physics_2d/physics_server_2d_wrap_mt.cpp) (lines 58–63), the `step` method pushes simulation updates to the queue:

```cpp
// servers/physics_2d/physics_server_2d_wrap_mt.cpp
void PhysicsServer2DWrapMT::step(real_t p_step) {
    if (create_thread) {
        command_queue.push(this, &PhysicsServer2DWrapMT::step, p_step);
    } else {
        physics_server_2d->step(p_step);
    }
}

```

Query calls from the main thread are synchronized automatically; if the physics thread is active, the wrapper ensures safe access to the space state data structures.

## Collision Filtering with Layers and Masks

Every physics body and area stores a **collision layer** (defining which groups it belongs to) and a **collision mask** (defining which groups it can interact with). Query parameters include a `collision_mask` field that is bitwise AND-ed against each candidate object’s layer during the broad-phase test. This filtering occurs before expensive narrow-phase calculations, optimizing performance for complex scenes.

## Extension API for Custom Physics Backends

Godot supports **PhysicsServer2DExtension** and **PhysicsServer3DExtension** for developers implementing custom physics engines. These extension classes mirror the core API, exposing virtual methods like `_intersect_ray`, `_intersect_shape`, and `_intersect_point` that external libraries can implement. The extension interface ensures that custom backends integrate seamlessly with the existing `PhysicsDirectSpaceState` query system.

## Practical Collision Detection Examples

### 2D Ray Casting in GDScript

This example queries the 2D space for obstacles along a line segment:

```gdscript
var space_state = get_world_2d().direct_space_state
var from = Vector2(10, 10)
var to   = Vector2(200, 200)

var result = space_state.intersect_ray(
    PhysicsRayQueryParameters2D.create(
        from,
        to,
        collision_mask = 1,          # only layer 1

        exclude = []))
if result:
    print("Hit at ", result.position, " normal ", result.normal)

```

Behind the scenes, this calls `PhysicsDirectSpaceState2D::_intersect_ray` → `PhysicsServer2D::intersect_ray`.

### 3D Shape Sweeping in GDScript

To detect collisions along a moving shape (sweep test):

```gdscript
var space_state = get_world_3d().direct_space_state
var shape = SphereShape3D.new()
shape.radius = 1.0

var params = PhysicsShapeQueryParameters3D.new()
params.shape = shape
params.transform = Transform3D(Basis(), Vector3(0, 5, 0))
params.motion = Vector3(0, -10, 0)   # sweep downwards

var collisions = space_state.intersect_shape(params, 10)
for hit in collisions:
    print("Collided with body ", hit.collider, " at shape ", hit.shape)

```

This invokes `PhysicsDirectSpaceState3D::_intersect_shape` → `PhysicsServer3D::intersect_shape`.

### Direct C++ Server Access

For engine module development, access the server directly:

```cpp
// Assume PhysicsServer3D* server = PhysicsServer3D::get_singleton();
PhysicsRayQueryParameters3D *q = memnew(PhysicsRayQueryParameters3D);
q->set_from(Vector3(0, 10, 0));
q->set_to(Vector3(0, -10, 0));
q->set_collision_mask(0xFFFFFFFF);

Dictionary hit = server->space_get_direct_state(space_rid)
                     ->intersect_ray(q);
if (!hit.is_empty()) {
    Vector3 pos = hit["position"];
    Vector3 normal = hit["normal"];
    // process hit …
}

```

## Summary

- **PhysicsServer2D** and **PhysicsServer3D** are singletons that abstract the physics engine implementation from the game logic.
- **PhysicsDirectSpaceState** provides the scripting API for collision queries including `intersect_ray`, `intersect_point`, and `intersect_shape`.
- Query implementations reside in [`physics_server_2d.cpp`](https://github.com/godotengine/godot/blob/main/physics_server_2d.cpp) (line 340) and [`physics_server_3d.cpp`](https://github.com/godotengine/godot/blob/main/physics_server_3d.cpp) (line 363), delegating to backend-specific broad-phase and narrow-phase algorithms.
- **Collision layers and masks** filter queries during the broad-phase to avoid unnecessary calculations.
- **PhysicsServer2DWrapMT** and **PhysicsServer3DWrapMT** handle thread synchronization via command queues when physics runs on a separate thread.
- The extension API allows custom physics backends to integrate with Godot’s collision detection system by implementing the same virtual query methods.

## Frequently Asked Questions

### How do I access the direct space state for collision queries in Godot?

Obtain the space state from the current world using `get_world_2d().direct_space_state` for 2D scenes or `get_world_3d().direct_space_state` for 3D scenes. This returns a **PhysicsDirectSpaceState** object that exposes query methods like `intersect_ray()` and `intersect_shape()`.

### What is the difference between intersect_ray and intersect_shape?

**intersect_ray** performs a line segment query returning the first collision along the path, while **intersect_shape** performs a volume query (or sweep test) returning all bodies overlapping a specified shape. Ray queries optimize for single-hit detection, whereas shape queries support collision masks and can return multiple results for overlap detection.

### Are collision queries thread-safe in Godot?

Yes, when using the multi-threaded physics mode, the **PhysicsServer2DWrapMT** and **PhysicsServer3DWrapMT** classes ensure thread safety by queuing physics commands and synchronizing space state access. However, you should only call queries from the main thread or use appropriate synchronization primitives, as the space state data changes during the physics step.

### How do collision layers and masks affect query results?

The `collision_mask` parameter in query structs (such as `PhysicsRayQueryParameters2D`) is compared against each physics object’s **collision_layer** using bitwise AND. If the result is zero, the object is skipped during the broad-phase, preventing it from appearing in the final results regardless of geometric intersection.