-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(/wiki/raycasting): dda algorithm impl
It *should* be correct now.
- Loading branch information
1 parent
f1a943f
commit 9df37ee
Showing
1 changed file
with
73 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,82 @@ | ||
bool DDATraversal(vec3 origin, vec3 dir, out vec3 o_hitPos, out vec3 o_hitNormal) | ||
{ | ||
dir = normalize(dir); | ||
#define MAX_RAY_STEPS 64 | ||
|
||
bool raycast( | ||
// Inputs | ||
vec3 ray_origin, | ||
vec3 ray_direction, | ||
|
||
// Outputs | ||
// out bool RETURN, // was any voxel hit at all? | ||
out bvec3 o_hit_axis, // Which axis did the hit occur on. | ||
out float o_hit_dist, // Distance to the hit position. | ||
out ivec3 o_hit_vox, // Which voxel was hit. | ||
out vec3 o_hit_pos, // Position of the hit, globally. | ||
out vec3 o_hit_uvw, // Position of the hit, on voxel. | ||
out vec3 o_hit_nor // Normal of the face that was hit. | ||
) { | ||
ray_direction = normalize(ray_direction); | ||
|
||
// We don't want to deal with this in the loop... | ||
if (rayDir.x == 0) | ||
rayDir.x = 0.001; | ||
if (rayDir.y == 0) | ||
rayDir.y = 0.001; | ||
if (rayDir.z == 0) | ||
rayDir.z = 0.001; | ||
|
||
ivec3 raySign = ivec3(sign(dir)); | ||
ivec3 rayPositivity = (1 + raySign) >> 1; | ||
vec3 rayInverse = 1 / dir; | ||
|
||
ivec3 gridCoords = ivec3(origin); | ||
vec3 withinVoxelCoords = origin - gridCoords; | ||
|
||
while (true) | ||
{ | ||
if (!isCoordInBounds(gridCoords)) | ||
return false; | ||
if(ray_direction.x == 0.0) | ||
ray_direction.x = 0.0001; | ||
if(ray_direction.y == 0.0) | ||
ray_direction.y = 0.0001; | ||
if(ray_direction.z == 0.0) | ||
ray_direction.z = 0.0001; | ||
|
||
vec3 ray_signf = sign(ray_direction); // only for init | ||
ivec3 ray_sign = ivec3(ray_signf); // used in loop | ||
vec3 ray_step = 1.0 / ray_direction; | ||
|
||
vec3 ray_origin_grid = floor(ray_origin); | ||
ivec3 voxel_coords = ivec3(ray_origin_grid); | ||
|
||
vec3 side_distance = ray_origin_grid - ray_origin; | ||
side_distance += 0.5; | ||
side_distance += ray_signf * 0.5; | ||
side_distance *= ray_step; | ||
|
||
bvec3 mask; // of side_distance's largest axis | ||
|
||
for (int i = 0; i < MAX_RAY_STEPS; i++) { | ||
|
||
if (isVoxelFilled(gridCoords)) | ||
{ | ||
o_hitPos = gridCoords + withinVoxelCoords; | ||
vec3 normal = vec3(0); | ||
normal[minIdx] = -raySign[minIdx]; | ||
o_hitNormal = normal; | ||
if(is_voxel_filled(voxel_coords)) { | ||
o_hit_axis = mask; | ||
|
||
// Determine final hit position in global space. | ||
o_hit_pos = side_distance - ray_origin; | ||
o_hit_pos += 0.5; | ||
o_hit_pos -= ray_signf * 0.5; // MINUS= | ||
o_hit_pos *= ray_step; | ||
//o_hit_pos = ray_origin + ray_direction * o_hit_dist; | ||
|
||
// The voxel that was hit. | ||
o_hit_vox = voxel_coords; | ||
|
||
// The distance to the hit. | ||
o_hit_dist = max(o_hit_pos.x, max(o_hit_pos.y, o_hit_pos.z)); | ||
//o_hit_dist = length(vec3(mask) * (side_distance - ray_step)); | ||
|
||
// The normal of the face that was hit. | ||
o_hit_nor = vec3(mask) * -ray_sign; | ||
|
||
// The position of the hit on the voxel. | ||
o_hit_uvw = o_hit_pos - o_hit_vox; | ||
|
||
return true; // We hit a voxel! | ||
} | ||
|
||
// Do a step... | ||
vec3 t = (rayPositivity - withinVoxelCoords) * rayInverse; | ||
int minIdx = t.x < t.y ? (t.x < t.z ? 0 : 2) : (t.y < t.z ? 1 : 2); | ||
// Determine the mask without branching... | ||
// (Idea by https://www.shadertoy.com/user/kzy) | ||
mask = lessThanEqual(side_distance.xyz, min(side_distance.yzx, side_distance.zxy)); | ||
|
||
gridCoords[minIdx] += raySign[minIdx]; | ||
withinVoxelCoords += rayDir * t[minIdx]; | ||
withinVoxelCoords[minIdx] = 1 - rayPositivity[minIdx]; | ||
// All components of `mask` are false, | ||
// EXCEPT for the corresponding largest component of sideDist, | ||
// which is the axis along which the ray should be incremented. | ||
|
||
side_distance += vec3(mask) * ray_step; | ||
voxel_coords += ivec(vec3(mask)) * ray_sign; | ||
} | ||
|
||
return false; | ||
} |