Skip to content

Instantly share code, notes, and snippets.

@Elabajaba
Created August 25, 2024 20:49
Show Gist options
  • Select an option

  • Save Elabajaba/d4a69ac814a610c786ad12e5a522b9c0 to your computer and use it in GitHub Desktop.

Select an option

Save Elabajaba/d4a69ac814a610c786ad12e5a522b9c0 to your computer and use it in GitHub Desktop.
/// Checks if 2 spheres intersects the frustum.
pub fn intersects_sphere(
&self,
sphere_a: &Sphere,
sphere_b: &Sphere,
intersect_far_a: bool,
intersect_far_b: bool,
) -> (bool, bool) {
let pos_a_xxxx = Vec4::splat(sphere_a.center.x);
let pos_a_yyyy = Vec4::splat(sphere_a.center.y);
let pos_a_zzzz = Vec4::splat(sphere_a.center.z);
// -radius so that we include objects who's center is outside the frustum,
// but who's bounding sphere intersects the frustum
let pos_a_rrrr = Vec4::splat(-sphere_a.radius);
// dot product 4 frustums at a time
let mut dot_a_0123 = pos_a_zzzz.mul_add(self.z0z1z2z3, self.w0w1w2w3);
dot_a_0123 = pos_a_yyyy.mul_add(self.y0y1y2y3, dot_a_0123);
dot_a_0123 = pos_a_xxxx.mul_add(self.x0x1x2x3, dot_a_0123);
let pos_b_xxxx = Vec4::splat(sphere_b.center.x);
let pos_b_yyyy = Vec4::splat(sphere_b.center.y);
let pos_b_zzzz = Vec4::splat(sphere_b.center.z);
// -radius so that we include objects who's center is outside the frustum,
// but who's bounding sphere intersects the frustum
let pos_b_rrrr = Vec4::splat(-sphere_b.radius);
// dot product 4 frustums at a time
let mut dot_b_0123 = pos_b_zzzz.mul_add(self.z0z1z2z3, self.w0w1w2w3);
dot_b_0123 = pos_b_yyyy.mul_add(self.y0y1y2y3, dot_b_0123);
dot_b_0123 = pos_b_xxxx.mul_add(self.x0x1x2x3, dot_b_0123);
let pos_axx_bxx = Vec4::new(
sphere_a.center.x,
sphere_a.center.x,
sphere_b.center.x,
sphere_b.center.x,
);
let pos_ayy_byy = Vec4::new(
sphere_a.center.y,
sphere_a.center.y,
sphere_b.center.y,
sphere_b.center.y,
);
let pos_azz_bzz = Vec4::new(
sphere_a.center.z,
sphere_a.center.z,
sphere_b.center.z,
sphere_b.center.z,
);
let pos_arr_brr = Vec4::new(
-sphere_a.radius,
-sphere_a.radius,
-sphere_b.radius,
-sphere_b.radius,
);
let mut dot_a45_b45 = pos_azz_bzz.mul_add(self.z4z5z4z5, self.w4w5w4w5);
dot_a45_b45 = pos_ayy_byy.mul_add(self.y4y5y4y5, dot_a45_b45);
dot_a45_b45 = pos_axx_bxx.mul_add(self.x4x5x4x5, dot_a45_b45);
if !intersect_far_a && !intersect_far_b {
// Swizzle to skip both far planes
dot_a45_b45 = dot_a45_b45.xxzz();
}
else if !intersect_far_a {
// Swizzle to skip the far plane
dot_a45_b45 = dot_a45_b45.xxzw();
} else if !intersect_far_b {
// Swizzle to skip the far plane
dot_a45_b45 = dot_a45_b45.xyzz();
}
let mask_a_0123 = dot_a_0123.cmpgt(pos_a_rrrr);
let mask_a45_b45 = dot_a45_b45.cmpgt(pos_arr_brr);
let mask_b_0123 = dot_b_0123.cmpgt(pos_b_rrrr);
// FFTT for MASK_A since we OR it then check if it's all 1s, so we only want
// the first 2 values and need to set the 2nd to to 1s to ignore them.
const MASK_A: BVec4A = BVec4A::from_array([false, false, true, true]);
const MASK_B: BVec4A = BVec4A::from_array([true, true, false, false]);
(
mask_a_0123.all() && (mask_a45_b45 | MASK_A).all(),
mask_b_0123.all() && (mask_a45_b45 | MASK_B).all(),
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment