---
title: "Raycast a 3D physics world in C#"
url: https://recursiveai.org/onegame/cookbook/raycast-3d-world/
description: "Raycast a 3D physics world in C# with onegame: a runnable .NET 10 console example using the published physics package, with real output and a download."
version: "1.26.0"
---

# Raycast a 3D physics world in C#

**onegame** is a free, open-source game engine for .NET from Recursive AI. MIT or Apache-2.0, no editor required.

[NuGet](https://www.nuget.org/packages/RecursiveAI.OneGame.Physics) · [GitHub](https://github.com/recursive-ai-oss/onegame) · [Docs](https://recursiveai.org/onegame/docs/) · [Download example (.zip)](https://recursiveai.org/onegame/cookbook/raycast-3d-world/raycast-3d-world.zip)

A raycast finds the nearest collision shape along a line. Use it for physics hit tests, not for selecting rendered triangles.

```shell
dotnet add package RecursiveAI.OneGame.Physics
```

Requires [.NET 10](https://dotnet.microsoft.com/download/dotnet/10.0) (net10.0); .NET 9 and earlier aren’t supported.

```csharp
using OneGame.Core;
using OneGame.Physics;

var space = new PhysicsSpace3D();
space.AddBox(size: new FVec3(2, 2, 2),
    at: new FVec3(0, 0, 5),
    options: new BodyOptions3D { Kind = BodyKind.Static, Layer = 2 });
if (space.Raycast(FVec3.Zero, new FVec3(0, 0, 1),
    Fixed.FromInt(10), out var hit, layers: 1u << 2))
{
    Console.WriteLine($"Point: {hit.Point}");
    Console.WriteLine($"Normal: {hit.Normal}");
    Console.WriteLine($"Distance: {hit.Distance}");
}
```

Unzip [the example](https://recursiveai.org/onegame/cookbook/raycast-3d-world/raycast-3d-world.zip), then `dotnet run`.

```text
Point: (0, 0, 4)
Normal: (0, 0, -1)
Distance: 4
```

`Fixed` and `FVec3` are deterministic fixed-point scalar and 3D vector types: use `Fixed.FromInt(2)` or `new FVec3(2, 0, 0)` for integers, and convert a float with `Fixed.FromDouble(value)` outside sim code.

## Variations

**Exclude the target’s layer.** Replace `layers: 1u << 2` in the program with:

```csharp
layers: 1u << 1
```

This mask excludes the box, so the program prints nothing.

## Related recipes

[Add 3D rigid body physics in C#](https://recursiveai.org/onegame/cookbook/3d-rigid-body-physics/) · [Move a 3D character controller in C#](https://recursiveai.org/onegame/cookbook/3d-character-controller/) · [Drive a 3D vehicle physics controller in C#](https://recursiveai.org/onegame/cookbook/drive-3d-vehicle/)

---

## The short answer

Call `PhysicsSpace3D.Raycast` with an origin, direction, maximum distance and optional layer mask. Test its Boolean result before reading `RayHit3D`. A successful result contains the body reference, local hit point, surface normal and distance along the cast.

The example puts a static box on layer 2, centered five units along +Z. The box is two units deep, so the forward ray reaches its near face at Z = 4. Its outward-facing normal is −Z. The mask includes only layer 2, and no simulation tick is needed for this static setup.

## How do I get the position and normal of a raycast hit?

Read `hit.Point` and `hit.Normal` inside the successful branch, as the snippet does. `hit.Distance` is the distance along the cast, while `hit.Body` identifies the collision body. A miss returns `false` and a default hit value. Don’t interpret that default point as a collision at the origin.

Use a deliberate direction and a finite distance. The example’s `(0, 0, 1)` is a unit direction, not an endpoint. Its maximum distance is ten simulation units. Changing the target position without extending the ray can correctly turn a hit into a miss.

Points are local to the physics space’s origin. If your game rebases a large world through `ShiftOrigin`, the global hit position is `space.Origin + hit.Point`. Keep local and global coordinates distinct when displaying markers or passing positions between systems. The [3D physics guide](https://recursiveai.org/onegame/docs/physics/#3d-spaces) describes the saved origin and rebasing rules.

## How do I filter a physics raycast by layer?

The `layers` argument is a bit mask, not a layer number. `1u << 2` includes layer 2. Passing the integer 2 as a mask would instead include bit 1. Combine bits with bitwise OR when several layers should be visible to the ray. The default mask includes all layers.

Set the body’s layer with `BodyOptions3D.Layer` when adding it. Query filtering decides which bodies the ray can see; it does not change their positions, materials or displayed appearance. The variation above selects layer 1 instead, so the layer-2 box is excluded and the program prints nothing.

When a ray misses, first check the mask, origin, direction and maximum distance against the actual physics geometry. A visible mesh alone is not a collider. Conversely, an invisible static box can be hit because rendering and physics are separate.

## Is a physics raycast the same as picking a rendered object?

No. This API searches physics shapes registered in `PhysicsSpace3D`. It does not intersect rendered mesh triangles or convert a mouse coordinate into a camera ray. Use a world-space ray for the physics question you want to ask, then associate the returned body reference with your game entity if needed.

For a query with thickness, the wrapper also exposes `SphereCast`; for checking a sphere-shaped occupied region, it exposes `OverlapSphere`. Those are separate queries, not options that make a ray wider.
