Ray Cast 3D

Godot C# cast ray forward


Introduction

Ray cast is projecting a line from one point to the other, it returns information about the closest object along its path. This page will focus on how to cast a 3D ray, how to cast a 3D ray forward from a 3D camera and how to read the ray’s result information.

3D Space

Every 3D component in godot is automatically assigned to the World3D class.
Before casting a ray we need to reference this class:

public override void _PhysicsProcess(double delta)
{
    var spaceState = GetWorld3D().DirectSpaceState;
}

spaceState represents the interactions of objects and their state in our World3D.


Ray Query

To represent the ray and its properties we will use a PhysicsRayQueryParameters3D:

public override void _PhysicsProcess(double delta)
{
    var spaceState = GetWorld3D().DirectSpaceState;
    var query = PhysicsRayQueryParameters3D.Create(Vector3.Zero, new Vector3(0,0,50));
}


Result

Now we can finally cast the ray query inside our spaceState:

public override void _PhysicsProcess(double delta)
{
    var spaceState = GetWorld3D().DirectSpaceState;
    var query = PhysicsRayQueryParameters3D.Create(Vector3.Zero, new Vector3(0,0,50));
    var result = spaceState.IntersectRay(query);
}

The result is a dictionary which contains information about the collider it collided with.
If the ray didn’t collide with anything the result will be empty.

if (result.Count > 0)
    GD.Print("Hit at point: ", result["position"]);

Result Information:

Type Information Description
Vector3 position the position where the ray collided.
Vector3 normal which side the collided object’s surface(face) is facing.
Object collider the object the ray collided with.
ObjectID collider_id object’s id
RID rid object’s rid.
int shape object’s shape index.
int face_index object’s face index.


Exclude Collision

When shooting a ray from inside an object the ray will detect its collision.
To avoid this issue we can use the Exclude property of our ray query:

public override void _PhysicsProcess(double delta)
{
    var spaceState = GetWorld3D().DirectSpaceState;
    var query = PhysicsRayQueryParameters3D.Create(Vector3.Zero, new Vector3(0,0,50));
    query.Exclude = new Godot.Collections.Array<Rid> { GetRid() };
    var result = spaceState.IntersectRay(query);
}

The exceptions array can contain objects or RIDs.
Note: the ‘GetRid()’ method only works in classes that inherit from classes like CharacterBody3D, StaticBody3D and more.


Collision Mask

In some cases using the Exception property could become inconvenient when excluding a lot of objects, so instead we can use collision masks.
In this example we ignore layer 2:

public override void _PhysicsProcess(double delta)
{
    var spaceState = GetWorld3D().DirectSpaceState;
    var query = PhysicsRayQueryParameters3D.Create(Vector3.Zero, new Vector3(0,0,50));
    query.CollisionMask = 4294967295 - 2;
}


Calculate Collision Masks and Layers

Our documentation on how to calculate collision masks and collision layers.


Cast a ray forward from Camera3D

using Godot;

public partial class RayCast : CharacterBody3D
{
    [Export] Camera3D camera;
    float rayLength = 1000f;

    public override void _PhysicsProcess(double delta)
    {
        var spaceState = GetWorld3D().DirectSpaceState;
        Vector3 cameraPosition = camera.GlobalPosition;
        Vector3 cameraDirection = -camera.GlobalBasis.Z.Normalized();
        var query = PhysicsRayQueryParameters3D.Create(cameraPosition, cameraPosition + cameraDirection * rayLength);
        var result = spaceState.IntersectRay(query);
    }
}

Don’t forget to set the exception property so your ray won’t intersect with your CharacterBody3D’s collision.


Get the ray’s intersected object

To get the object that the ray hit we will do:

Node obj = (Node)result["collider"];

To Get a specific type we can change ‘Node’ to something else:

GD.Print(((StaticBody3D)result["collider"]).Name);

BUT in this case if the object isn’t a StaticBody3D, this will throw an exception.
So instead of directly converting the type we can use the ‘as’ operator:

StaticBody3D staticObject = (Node)result["collider"] as StaticBody3D;

if (staticObject != null)
	GD.Print(staticObject.Name);

The ‘as’ operator is a safer method, it produces a null if the object cannot be converted.
Note: to check if an object can be converted you can use the ‘is’ operator.


Issues and Fixes


Extra references

Godot Ray-Casting
Godot RayCast3D
Godot Collision Physics


Last updated on: 08/03/2024. This page is up to date with Godot 4.2.2.
Please report any errors over to the relevant GitHub repository.
Documentation maintained by 000Daniel.