Skip to content

Instantly share code, notes, and snippets.

@enbugger
Last active August 3, 2025 18:49
Show Gist options
  • Save enbugger/d4ddb9c267f5a1a7e17a0617c269e396 to your computer and use it in GitHub Desktop.
Save enbugger/d4ddb9c267f5a1a7e17a0617c269e396 to your computer and use it in GitHub Desktop.
#voxel #raycasting #unity #burst
using static Unity.Mathematics.math;
using Unity.Mathematics;
namespace Game
{
public interface IVoxelStore<T> where T : struct
{
// Should return null if the guess value is not in boundaries of any voxel
// Otherwise return arbitrary voxel data
T? GetVoxel(float3 guess);
}
public struct RayCasting
{
public static T? Cast<T, TR>(TR store,
float3 origin, float3 direction, float maxDistance,
out float3 hitPos, out float3 hitNorm)
where T : struct
where TR: struct, IVoxelStore<T>
{
if (distance(origin, direction) == 0)
{
hitPos = 0;
hitNorm = 0;
return null;
}
direction = normalize(direction);
var t = 0f;
var i = floor(origin);
var step = sign(direction);
var tDelta = abs(1 / direction);
float3 dist;
dist.x = step.x > 0 ? i.x + 1 - origin.x : origin.x - i.x;
dist.y = step.y > 0 ? i.y + 1 - origin.y : origin.y - i.y;
dist.z = step.z > 0 ? i.z + 1 - origin.z : origin.z - i.z;
float3 tMax;
tMax.x = tDelta.x < float.PositiveInfinity ? tDelta.x * dist.x : float.PositiveInfinity;
tMax.y = tDelta.y < float.PositiveInfinity ? tDelta.y * dist.y : float.PositiveInfinity;
tMax.z = tDelta.z < float.PositiveInfinity ? tDelta.z * dist.z : float.PositiveInfinity;
var steppedIndex = -1;
while (t <= maxDistance)
{
var b = store.GetVoxel(i);
if (b != null)
{
hitPos = origin + t * direction;
hitNorm = 0;
if (steppedIndex >= 0)
hitNorm[steppedIndex] = -step[steppedIndex];
return b;
}
// Advance t to next nearest voxel boundary
if (tMax.x < tMax.y)
{
if (tMax.x < tMax.z)
{
i.x += step.x;
t = tMax.x;
tMax.x += tDelta.x;
steppedIndex = 0;
}
else
{
i.z += step.z;
t = tMax.z;
tMax.z += tDelta.z;
steppedIndex = 2;
}
}
else
{
if (tMax.y < tMax.z)
{
i.y += step.y;
t = tMax.y;
tMax.y += tDelta.y;
steppedIndex = 1;
}
else
{
i.z += step.z;
t = tMax.z;
tMax.z += tDelta.z;
steppedIndex = 2;
}
}
}
// No voxel hit found
hitPos = origin + t * direction;
hitNorm = 0;
return null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment