Skip to content

Instantly share code, notes, and snippets.

@rbnelr
Last active April 13, 2021 00:03
Show Gist options
  • Save rbnelr/3e3beb36a1d7528c5f114ac4b6a8e409 to your computer and use it in GitHub Desktop.
Save rbnelr/3e3beb36a1d7528c5f114ac4b6a8e409 to your computer and use it in GitHub Desktop.
bool trace_ray (vec3 pos, vec3 dir, float max_dist, out Hit hit, bool sunray) {
// make ray relative to world texture and bring coordinates into [1.0, 2.0] float space
// for float mantissa optimization (avoid int -> float conversion for projection)
// basially treat float mantissa like integer for stepping but use the whole float for projection calculations
vec3 coord = pos + WORLD_SIZE_HALF;
coord = coord * INV_WORLD_SIZEf + 1.0; // to [1.0, 2.0]
coord = clamp(coord, 1.0, 2.0);
// flip coordinate space such that ray is always positive (simplifies stepping logic)
// keep track of flip via flipmask
bvec3 ray_neg = lessThan(dir, vec3(0.0));
coord = mix(coord, 3.0 - coord, ray_neg);
uvec3 flipmask = mix(uvec3(0u), uvec3(MANTISSA_MASK), ray_neg);
// precompute part of plane projection equation
// prefer 'pos * inv_dir + bias' over 'inv_dir * (pos - ray_pos)'
// due to mad instruction
// multiply in WORLD_SIZEf to make distances be in world space
vec3 inv_dir = mix(1.0 / abs(dir), vec3(INF), equal(dir, vec3(0.0))) * WORLD_SIZEf;
vec3 bias = inv_dir * -coord;
// starting cell is where ray is
// start at some level of octree
// -best to start at 0 if camera on surface
// -best at higher levels if camera were in a large empty region
uint mip = 0;
//uint mip = uint(OCTREE_MIPS-1);
// round down to start cell of octree
coord = TOFLOAT(TOUINT(coord) & (ROUND_MASK << mip));
bvec3 axismask = bvec3(false);
float dist = 0.0;
for (;;) {
// get current original coordinate space
int bits = OCTREE_MIPS - int(mip);
int offs = MANTISSA_BITS - bits;
uvec3 flipped = bitfieldExtract(TOUINT(coord) ^ flipmask, offs, bits);
// read octree cell
uint childmask = texelFetch(octree, ivec3(flipped >> 1u), int(mip)).r;
//flipped &= 1u;
//uint i = flipped.z*4u + (flipped.y*2u + flipped.x);
uint i = flipped.x & 1u;
i = bitfieldInsert(i, flipped.y, 1, 1);
i = bitfieldInsert(i, flipped.z, 2, 1);
if ((childmask & (1u << i)) != 0) {
// non-air octree cell
if (mip == 0u)
break; // found solid leaf voxel
// decend octree
mip--;
vec3 next_coord = TOFLOAT(TOUINT(coord) + (FLOAT_OCTREE_SIZE << mip));
// upate coord by determining which child octant is entered first
// by comparing ray hit against middle plane hits
vec3 tmidv = inv_dir * next_coord + bias;
coord = mix(coord, next_coord, lessThan(tmidv, vec3(dist)));
} else {
// air octree cell, continue stepping
vec3 next_coord = TOFLOAT(TOUINT(coord) + (FLOAT_OCTREE_SIZE << mip));
// calculate entry distances of next octree cell
vec3 t0v = inv_dir * next_coord + bias;
dist = min(min(t0v.x, t0v.y), t0v.z);
// step into next cell via relevant axis
axismask.x = t0v.x == dist;
axismask.y = t0v.y == dist && !axismask.x;
axismask.z = !axismask.x && !axismask.y;
coord = mix(coord, next_coord, axismask);
uint stepcoord = axismask.x ? TOUINT(coord.x) : TOUINT(coord.z);
stepcoord = axismask.y ? TOUINT(coord.y) : stepcoord;
mip = findLSB(stepcoord) - MANTISSA_SHIFT;
coord = TOFLOAT(TOUINT(coord) & (ROUND_MASK << mip));
if (mip >= uint(OCTREE_MIPS) || dist >= max_dist)
return false;
}
}
if (!sunray) {
int bits = OCTREE_MIPS - int(mip);
int offs = MANTISSA_BITS - bits;
uvec3 flipped = bitfieldExtract(TOUINT(coord) ^ flipmask, offs, bits);
// arrived at solid leaf voxel, read block id from seperate data structure
hit.bid = read_bid(flipped);
hit.prev_bid = 0; // don't know, could read
// calcualte surface hit info
hit.dist = dist;
hit.pos = pos + dir * dist;
hit.normal = mix(vec3(0.0), -sign(dir), axismask);
uint entry_face = get_step_face(axismask, dir);
vec2 uv = calc_uv(fract(hit.pos), axismask, entry_face);
float texid = float(block_tiles[hit.bid].sides[entry_face]);
hit.col = texture(tile_textures, vec3(uv, texid)).rgb;
hit.emiss = hit.col * get_emmisive(hit.bid);
}
return true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment