Adding a Sphere

Adding a Sphere

One commonly employed object in ray tracing is the sphere due to its straightforward ray intersection calculations.

Ray-Sphere Intersection

For a sphere centered at the origin with a radius of R, the equation representing the sphere is x^2 + y^2 + z^2 = R^2. This equation states that if a given point (x, y, z) lies on the sphere, its coordinates satisfy the equation x^2 + y^2 + z^2 = R^2. If a point (x, y, z) is inside the sphere, then its coordinates will result in x^2 + y^2 + z^2 being less than R^2. On the other hand, if a point (x, y, z) is outside the sphere, then x^2 + y^2 + z^2 will be greater than R^2.

The equation becomes more complex when the center of the sphere is at (Cx, Cy, Cz). In this case, the equation for the sphere is (x - Cx)^2 + (y - Cy)^2 + (z - Cz)^2 = r^2, where r represents the radius of the sphere. This equation shows that if a given point (x, y, z) lies on the sphere, the squared distance between the point and the center of the sphere (Cx, Cy, Cz) will be equal to the squared radius (r^2).

In computer graphics, it is common to use vector formulas to represent geometric calculations. To achieve this, we can express the equation of a sphere in terms of vectors.

Consider the vector from the center C = (Cx, Cy, Cz) to a point P = (x, y, z), denoted as (P - C). Using the dot product, we can compute the squared distance between these points:

(P - C) · (P - C) = (x - Cx)^2 + (y - Cy)^2 + (z - Cz)^2.

This equation can be further simplified to:

(P - C) · (P - C) = r^2,

where r represents the squared radius of the sphere. We interpret this equation as follows: any point P that satisfies this equation is on the sphere.

Now, let's consider a ray P(t) = A + tb, where A is the origin of the ray and b is the direction vector. We want to determine if the ray intersects the sphere at any point. For an intersection to occur, there must exist a parameter t such that the point P(t) satisfies the sphere equation.

Substituting the ray equation into the sphere equation, we have:

(P(t) - C) · (P(t) - C) = r^2.

Expanding this equation, we get:

(A + tb - C) · (A + tb - C) = r^2.

Rearranging the terms, we obtain:

t^2 b · b + 2t b · (A - C) + (A - C) · (A - C) - r^2 = 0

The vectors and r in that equation are all constant and known. The unknown is t, and the equation is a quadratic, like you probably saw in your high school math class. You can solve for t and there is a square root part that is either positive (meaning two real solutions), negative (meaning no real solutions), or zero (meaning one real solution). In graphics, the algebra almost always relates very directly to the geometry. What we have is:

Figure 1: Ray-sphere intersection results

Creating Our First Raytraced Image

By implementing the mathematical equations into our program as code, we can validate its correctness by visually verifying the ray-sphere intersection. As a test scenario, we can place a small sphere at the position -1 on the z-axis. If a ray intersects with this sphere, we can mark the corresponding pixel by coloring it red. This way, we can visually confirm if the ray tracing calculations are functioning accurately.

//This function determines whether a given ray intersects with a sphere.

bool hit_sphere(const point3& center, double radius, const ray& r) {
    vec3 oc = r.origin() - center;
    auto a = dot(r.direction(), r.direction());
    auto b = 2.0 * dot(oc, r.direction());
    auto c = dot(oc, oc) - radius*radius;
    auto discriminant = b*b - 4*a*c;
    return (discriminant > 0);
}

color ray_color(const ray& r) {
    if (hit_sphere(point3(0,0,-1), 0.5, r))
        return color(1, 0, 0);
    vec3 unit_direction = unit_vector(r.direction());
    auto t = 0.5*(unit_direction.y() + 1.0);
    return (1.0-t)*color(1.0, 1.0, 1.0) + t*color(0.5, 0.7, 1.0);
}

What we get is this:

Figure 2: A simple red sphere

Although the current implementation lacks several important features such as shading, reflection rays, and support for multiple objects, we have made significant progress and are closer to the halfway point. It is important to address some limitations in our current code.

One aspect to consider is that we tested whether the ray hits the sphere without considering cases where t<0, which can lead to erroneous results. Interestingly, if we modify the sphere center to have a z-coordinate of +1, we would obtain the exact same picture. However, this behavior is not desirable, as it implies seeing objects located behind the viewer. We will address these issues in the upcoming improvements to our ray tracer.