Raytracing: Intersection between a line and a sphere

Raytracing is a way to precisely compute how the light will hit an object. It consists of sending a ray to an object (imagine a sort of laser) and see if it hit and where it hits. At the era of RTX cards, this word might seem quite familiar.

We will try to compute the intersection between a line that represents our ray and a sphere that is our object.

Consider that our sphere is at the center of our 3D plan and that it's raduis is given.

Also consider that our line is a ray represented as two vectors, the first called pos which is the "start position" of our ray in our 3D plan, and the second vec which it the vector representing the direction of our ray.

At this point, our code may look like this:

radius = 2.0
pos = (4.0, 0.0, 0.0)
vec = (-2.0, 0.0, 1.0)

First, to simplify calculations, we need to normalize our vector and make it an unit vector, with each axis varying between 0 and 1.

To do that, we need to know the magnitude of our vector. The magnitude of a vector is the distance between its origin (0, 0, 0) and its direction (-2, 0, 1). We can compute it like this:

def v3magnitude(vec):
    x, y, z = vec
    return sqrt(x*x + y*y + z*z)

Once we got our magnitude, we can compute the normalized version of our vector:

def v3normalized(vec):
    x, y, z = vec
    magnitude = v3magnitude(vec)

    return (
        x / magnitude,
        y / magnitude,
        z / magnitude
    )

We can then normalize our vector:

radius = 2.0
pos = (4.0, 0.0, 0.0)
vec = (-2.0, 0.0, 1.0)

vec = v3normalized(vec)

Once we got our normalized vector, we can start our computations.

We need to resolve the quadratic equation for x² + y² + z² = radius², corresponding to the cases where our ray intersects with our sphere.

px, py, pz = pos
vx, vy, vz = vec

b = 2 * (px*vx + py*vy + pz*vz)
c = (px*px + py*py + pz*pz) - radius*radius

delta = b*b - 4*c

You may wonder why there is no a in this quadratic formula. It's simply because a = 1.

We've got three cases:

  • if delta < 0, our ray will never intersect with our sphere.
  • if delta == 0, our ray intersects only once with our sphere surface and never go through it, only brushing against it.
  • if delta > 0, our ray will go through our sphere and intersect twice its surface.

The result of our equation will give us the distance of the intersections relatively to our start position.

near_distance = (-b + sqrt(delta)) / 2
far_distance = (-b - sqrt(delta)) / 2

The near distance is the distance where the ray enters the sphere and far distance is the position where the ray will exit the sphere if it goes through it.

Okay, now that we know the start position, the direction and the two distances at which it will intersect, we can compute the positions where our ray will intersect with our sphere.

near_intersect_pos = (
    px + vx * near_distance,
    py + vy * near_distance,
    pz + vz * near_distance
)

far_intersect_pos = (
    px + vx * far_distance,
    py + vy * far_distance,
    pz + vz * far_distance
)

And that's it! We now know where our line collides with our sphere in our 3D plan!

Posted in Geometry, Python on Dec 29, 2020.