Introduction
Welcome back! In our last lesson, we took our first step into the world of game physics by implementing an Axis-Aligned Bounding Box (AABB) intersection test. This provided us with a fast, efficient way to perform broad-phase collision detection for box-shaped objects.
However, AABBs are not always the best choice. For objects that are roughly spherical, like balls, planets, or even characters that can be approximated by a sphere, an AABB can be a very poor fit, leading to many "false positive" collisions where the boxes touch but the models don't. Furthermore, if a non-spherical object rotates, its AABB must be recalculated and can grow much larger than the object itself, while a sphere's boundary remains the same regardless of rotation.
Today, we will address this by implementing another fundamental collision primitive. Your goal for this lesson is to implement a Sphere vs. Sphere intersection test. This test is even simpler and faster than the AABB test and is perfectly suited for round objects or as a rotation-invariant bounding volume.
1. The Sphere Bounding Volume
Just like an AABB, a bounding sphere is a simple geometric shape used to enclose a more complex 3D model for fast, approximate collision checks.
A sphere is defined by two simple properties:
- A center point in 3D space.
- A radius.
Let's add a struct for this to our physics_types.h file, alongside the AABB we created previously.
// In physics_types.h
#ifndef PHYSICS_TYPES_H
#define PHYSICS_TYPES_H
#include <cglm/cglm.h>
typedef struct {
vec3 min;
vec3 max;
} AABB;
// Add the new Sphere struct
typedef struct {
vec3 center;
float radius;
} Sphere;
#endif // PHYSICS_TYPES_H
This simple structure gives us everything we need to represent a sphere in our game world.
2. The Logic of Sphere Intersection
The mathematical principle for detecting if two spheres have collided is one of the most elegant in collision detection.
Two spheres intersect if the distance between their centers is less than the sum of their radii.
That's it. It's an intuitive and powerful concept.

Let's formalize this. Given two spheres, A and B:
- Sphere A has center and radius .
- Sphere B has center and radius .
We first calculate the distance between their centers:
This is just the standard Euclidean distance formula, which you can also express using vector operations as the length of the vector between the two points:
Then, we simply compare this distance to the sum of their radii. A collision occurs if:
Physics - Collision Detection (Sphere/Sphere Collisions)
The following document provides a concise explanation of this theory. It's a great reference for the core mathematical concept.
Read the first section titled 'Sphere / Sphere Collisions'. It covers the main theory with clear diagrams and also introduces the concepts of the collision normal and penetration distance, which will be important later when we implement collision response.
3. An Important Optimization: Avoiding the Square Root
In game development, especially in physics engines, we are always looking for performance gains. The distance calculation involves a sqrt function, which is computationally more expensive than basic arithmetic like addition or multiplication. While modern CPUs are very fast, these collision checks happen many times per frame for many objects, and the costs add up.
We can eliminate the square root by working with squared distances.
If we square both sides of our inequality, the relationship still holds:
The squared distance, , is simply the dot product of the vector between the centers with itself:
This calculation involves only subtractions and multiplications, which is significantly faster than taking a square root. This is a standard and crucial optimization in game physics programming.
Particle Collision // Game Dev Physics #2
This video provides a great walkthrough of the sphere collision algorithm, including the squared-distance optimization. While it refers to 'particles', the concept is identical for any sphere.
Watch from 01:57 to 03:53. The first part (until 02:33) covers the basic theory, and the second part (starting at 02:33) explains the optimization of using squared length (length2) to avoid the square root.
4. Implementing the Sphere vs. Sphere Test in C
Now we have all the pieces to write our C function. We'll add it to our physics.c and physics.h files.
First, the function prototype in physics.h:
// In physics.h
#include <stdbool.h>
#include "physics_types.h"
bool aabb_intersect(const AABB* a, const AABB* b);
// Add the new function prototype
bool sphere_intersect(const Sphere* a, const Sphere* b);
Next, the implementation in physics.c. We'll follow the optimized logic we just discussed.
// In physics.c
#include "physics.h"
// ... (aabb_intersect function is here) ...
/**
* Checks if two Spheres are intersecting.
* @param a Pointer to the first Sphere.
* @param b Pointer to the second Sphere.
* @return true if they intersect, false otherwise.
*/
bool sphere_intersect(const Sphere* a, const Sphere* b) {
// Calculate the vector from the center of sphere a to sphere b
vec3 delta;
glm_vec3_sub(b->center, a->center, delta);
// Calculate the squared distance between the centers
float dist_sq = glm_vec3_norm2(delta);
// Calculate the sum of the radii
float radii_sum = a->radius + b->radius;
// Compare the squared distance to the squared sum of radii
// This avoids the expensive square root operation.
return dist_sq < (radii_sum * radii_sum);
}
A quick note on the code:
glm_vec3_sub(b->center, a->center, delta);calculatesdelta = b->center - a->center.glm_vec3_norm2(delta);calculates the squared length (or squared norm) of thedeltavector, which is exactly the squared distance we need.- We compare this to
radii_sum * radii_sum, completing our optimized check. We use<to define intersection as any overlap. If we used<=, spheres that are just touching would also be counted. For most physics,<is sufficient.
5. Testing Your Implementation
As with the AABB test, we can create simple test cases in main() to ensure our function works correctly before integrating it with our game objects.
// In main.c, after your includes:
#include <stdio.h>
#include "physics.h"
int main() {
// ...
// --- AABB Tests from previous lesson ---
// ...
printf("\n--- Sphere Intersection Tests ---\n");
// Case 1: Overlapping spheres
Sphere s1 = { .center = {0.0f, 0.0f, 0.0f}, .radius = 1.0f };
Sphere s2 = { .center = {1.5f, 0.0f, 0.0f}, .radius = 1.0f };
if (sphere_intersect(&s1, &s2)) {
printf("Case 1: Spheres are intersecting (Correct!)\n");
} else {
printf("Case 1: Spheres are NOT intersecting (Incorrect!)\n");
}
// Case 2: Non-overlapping spheres
Sphere s3 = { .center = {0.0f, 0.0f, 0.0f}, .radius = 1.0f };
Sphere s4 = { .center = {3.0f, 0.0f, 0.0f}, .radius = 1.0f };
if (sphere_intersect(&s3, &s4)) {
printf("Case 2: Spheres are intersecting (Incorrect!)\n");
} else {
printf("Case 2: Spheres are NOT intersecting (Correct!)\n");
}
// Case 3: Touching spheres (should not count as intersection with '<')
Sphere s5 = { .center = {0.0f, 0.0f, 0.0f}, .radius = 1.0f };
Sphere s6 = { .center = {2.0f, 0.0f, 0.0f}, .radius = 1.0f };
if (sphere_intersect(&s5, &s6)) {
printf("Case 3: Spheres are touching (Incorrect for '<' check)\n");
} else {
printf("Case 3: Spheres are NOT intersecting (Correct for '<' check)\n");
}
// ... rest of your main function
}
Compile and run your program. Your output should confirm that the function is correctly identifying intersections.
Conclusion
Excellent work! You've now added a second fundamental collision primitive to your engine's toolbox. The sphere-sphere intersection test is simple, extremely fast, and rotation-invariant, making it an ideal choice for many types of game objects.
Key Takeaways:
- Bounding spheres are defined by a
centerand aradius. They are ideal for round objects and are unaffected by rotation. - Two spheres intersect if the distance between their centers is less than the sum of their radii.
- A crucial optimization is to compare the squared distance to the squared sum of radii to avoid using the computationally expensive
sqrtfunction. - The C implementation requires only a vector subtraction, a squared norm (dot product), and a single comparison.
Preview of the Next Lesson:
So far, we have written functions to test for AABB and Sphere intersections, but these tests are disconnected from the actual objects in our game. In the next lesson, we will bridge this gap by learning how to attach collider components (like AABB or Sphere) to our game entities, setting the stage for a system that can check for collisions between all relevant objects in our scene.