Skip to content

Instantly share code, notes, and snippets.

@hasenbanck
Last active October 28, 2024 11:04
Show Gist options
  • Save hasenbanck/d2304aa683aff82b11c88b78cc9183b7 to your computer and use it in GitHub Desktop.
Save hasenbanck/d2304aa683aff82b11c88b78cc9183b7 to your computer and use it in GitHub Desktop.
very fast cone / sphere intersection test
/// While implementing a tile based light culling shader, I stumbled uppon the bachelor thesis from Jonathan W. Hale:
/// "Dual-Cone View Culling for Virtual Reality Applications" (2018). While lookin at his final version, I
/// realized that his code could be even further simplified, if the cone's tip is the origin of the coordinate system.
/// By creating a "world to cone view space" transformation matrix, that aligns the code to the positive +Z axis and
/// also set's the cone's tip as the origin, this matrix can then be used to transform the world coordinates into the
/// "cone view space". The following code uses a left handed coordinate system.
/// The test itself only uses 10 instructions:
///
/// - 2 scalar multiplications
/// - 2 additions
/// - 2 comparisons
/// - 1 negation
/// - 1 square root
/// - 1 logical AND
/// - 1 MAX operation
/// Tests if a sphere intersects with a cone that is aligned to the +Z axis with its tip at the origin.
/// The spheres we test must be inside the cone's view space. This is an optimized version that takes
/// advantage of the special case where the cone is Z-aligned.
///
/// # How it works
///
/// The test is split into two parts:
///
/// 1. `extends_past_cone_tip`: Checks if any part of the sphere extends past z=0 (the cone's tip)
/// - A sphere extends past z=0 if its closest point to the XY plane is at or behind z=0
/// - This occurs when: sphere_center.z > -sphere_radius
///
/// 2. `intersects_cone`: Tests if the sphere intersects the cone's surface at the sphere's Z position
/// - At any Z position, the cone forms a circular cross-section
/// - The radius of this cross-section is: max(cone_angle_tan * sphere_center.z, 0.0)
/// - length(sphere_center.xy) gives the distance from sphere center to cone's axis
/// - For intersection, this distance must be <= cone_radius + sphere_radius
///
/// Based on an original idea from Jonathan W. Hale's bachelor thesis
/// "Dual-Cone View Culling for Virtual Reality Applications" (2018).
fn intersect_cone_sphere_aligned(
sphere_center: vec3<f32>,
sphere_radius: f32,
cone_angle_tan: f32
) -> bool {
let cone_radius = max(cone_angle_tan * sphere_center.z, 0.0);
let extends_past_cone_tip = sphere_center.z > -sphere_radius;
let intersects_cone = length(sphere_center.xy) <= cone_radius + sphere_radius;
return extends_past_cone_tip && intersects_cone;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment