Fixed issue with incorrect raycasts by changing ray-box algorithm and applying normal offset

This commit is contained in:
Jarrod Doyle 2023-07-28 17:04:48 +01:00
parent 404c7875bf
commit 0f668084d3
Signed by: Jayrude
GPG Key ID: 38B57B16E7C0ADF7
1 changed files with 46 additions and 11 deletions

View File

@ -39,6 +39,7 @@ struct HitInfo {
struct AabbHitInfo { struct AabbHitInfo {
hit: bool, hit: bool,
distance: f32, distance: f32,
normal: vec3<f32>,
}; };
struct Feedback { struct Feedback {
@ -67,20 +68,54 @@ fn get_shading_offset(hit: HitInfo) -> u32 {
return (*brickmap).shading_table_offset + map_voxel_idx; return (*brickmap).shading_table_offset + map_voxel_idx;
} }
fn max_component(v: vec3<f32>) -> f32 {
return max(max(v.x, v.y), v.z);
}
fn less_than(a: vec2<f32>, b: vec2<f32>) -> vec2<bool> {
return vec2<bool>(a.x < b.x, a.y < b.y);
}
fn ray_intersect_aabb( fn ray_intersect_aabb(
ray_pos: vec3<f32>, orig_ray_pos: vec3<f32>,
ray_dir: vec3<f32>, ray_dir: vec3<f32>,
min: vec3<f32>, min: vec3<f32>,
max: vec3<f32> max: vec3<f32>
) -> AabbHitInfo { ) -> AabbHitInfo {
let ray_dir_inv = 1.0 / ray_dir; let radius = (max - min) * 0.5;
let t1 = (min - ray_pos) * ray_dir_inv; let center = min + radius;
let t2 = (max - ray_pos) * ray_dir_inv; let ray_pos = orig_ray_pos - center;
let t_min = min(t1, t2); var winding = 1.0;
let t_max = max(t1, t2); if (max_component(abs(ray_pos) * (1.0 / radius)) < 1.0) {
let tmin = max(max(t_min.x, 0.0), max(t_min.y, t_min.z)); winding = -1.0;
let tmax = min(t_max.x, min(t_max.y, t_max.z)); }
return AabbHitInfo(tmax > tmin, tmin); var sgn = -sign(ray_dir);
let d = (radius * winding * sgn - ray_pos) * (1.0 / ray_dir);
let test = vec3<bool>(
(d.x >= 0.0) && all(less_than(abs(ray_pos.yz + ray_dir.yz * d.x), radius.yz)),
(d.y >= 0.0) && all(less_than(abs(ray_pos.zx + ray_dir.zx * d.y), radius.zx)),
(d.z >= 0.0) && all(less_than(abs(ray_pos.xy + ray_dir.xy * d.z), radius.xy))
);
if (test.x) {
sgn = vec3<f32>(sgn.x, 0.0, 0.0);
} else if (test.y) {
sgn = vec3<f32>(0.0, sgn.y, 0.0);
} else if (test.z) {
sgn = vec3<f32>(0.0, 0.0, sgn.z);
} else {
sgn = vec3<f32>(0.0, 0.0, 0.0);
}
var distance = 0.0;
if (sgn.x != 0.0) {
distance = d.x;
} else if (sgn.y != 0.0) {
distance = d.y;
} else if (sgn.z != 0.0) {
distance = d.z;
}
return AabbHitInfo((sgn.x != 0.0) || (sgn.y != 0.0) || (sgn.z != 0.0), distance * winding, sgn);
} }
fn point_inside_aabb(p: vec3<i32>, min: vec3<i32>, max: vec3<i32>) -> bool { fn point_inside_aabb(p: vec3<i32>, min: vec3<i32>, max: vec3<i32>) -> bool {
@ -116,7 +151,7 @@ fn brick_ray_cast(
// tmin is greater than 0 if the ray is outside of the AABB, so we need to // tmin is greater than 0 if the ray is outside of the AABB, so we need to
// accelerate the ray to be on the edge of the AABB. // accelerate the ray to be on the edge of the AABB.
if (tmin > 0.0) { if (tmin > 0.0) {
ray_pos += ray_dir * (tmin + 0.0001); ray_pos += ray_dir * tmin - aabbHit.normal * 0.0001;
} }
// DDA setup // DDA setup
@ -174,7 +209,7 @@ fn grid_cast_ray(orig_ray_pos: vec3<f32>, ray_dir: vec3<f32>) -> HitInfo {
// tmin is greater than 0 if the ray is outside of the AABB, so we need to // tmin is greater than 0 if the ray is outside of the AABB, so we need to
// accelerate the ray to be on the edge of the AABB. // accelerate the ray to be on the edge of the AABB.
if (tmin > 0.0) { if (tmin > 0.0) {
ray_pos += ray_dir * (tmin + 0.0001); ray_pos += ray_dir * tmin - aabbHit.normal * 0.0001;
} }
// DDA setup // DDA setup