Skip to content

Instantly share code, notes, and snippets.

@rbnelr
Last active April 18, 2021 08:29
Show Gist options
  • Save rbnelr/f3fe704b706c56048337b58c1ee44260 to your computer and use it in GitHub Desktop.
Save rbnelr/f3fe704b706c56048337b58c1ee44260 to your computer and use it in GitHub Desktop.
// flip coordinate space such that ray is always positive (simplifies stepping logic)
// keep track of flip via flipmask
bool3 ray_neg = dir < 0.0;
float3 flipped = ray_neg ? -pos : pos;
int3 flipmask = ray_neg ? -1 : 0;
float3 absDir = abs(dir);
float dist = 0.0;
int skipLOD = 0;
// get initial coordinate based on flipped coordinate
int3 mapPos = floor(flipped);
mapPos &= 0xffffffff << skipLOD;
for (;;) {
int3 unflipped = (mapPos ^ flipmask) >> skipLOD; // unflipped mapPos shifted down for texture indexing
// read octree cell at unflipped coord with current skipLOD
int voxel = texelFetch(octree, unflipped, skipLOD).r;
if (voxel != AIR) {
// non-air octree cell
if (skipLOD == 0)
break; // found solid leaf voxel
// decend octree
skipLOD--;
int3 mid_planes = mapPos + (1 << skipLOD);
// upate coord by determining which child octant is entered first
// by comparing ray hit against middle plane hits
float3 tmidv = ((float3)mid_planes - flipped) / absDir;
mapPos = tmidv < hitDistance.xxx ? mid_planes : mapPos;
// have decended one level of the octree, instead of stepping
// go back repeat outer loop until fully air cell is found or non-air leaf voxel is found
} else {
float3 exit_planes = mapPos + rayMoveIterations;
float3 exit_distances = (exit_planes - flipped) / absDir;
hitDistance = min(min(exit_distances.x, exit_distances.y), exit_distances.z);
// step on axis where exit distance is lowest
int stepcoord;
if (t0v.x == dist) {
mapPos.x = exit_planes.x;
stepcoord = mapPos.x;
} else if (t0v.y == dist) {
mapPos.y = exit_planes.y;
stepcoord = mapPos.y;
} else {
mapPos.z = exit_planes.z;
stepcoord = mapPos.z;
}
// step up to highest changed octree parent cell
mip = firstbitlow(stepcoord);
// round down mapPos to lower corner of (potential) parent cell
mapPos &= ROUNDMASK << mip;
rayDistance--;
//// exit when either stepped out of world or max ray dist reached
insideBounds = rayDistance > 0 &&
mapPos.x < (dir.x < 0 ? 0 : _WorldBounds.x) &&
mapPos.y < (dir.y < 0 ? 0 : _WorldBounds.y) &&
mapPos.z < (dir.z < 0 ? 0 : _WorldBounds.z);
}
}
// handle hit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment