Math foundations: sphere equation, vector dot-product, and solving intersection with a ray.
Added a function that returns whether the ray hit the sphere.
Added a function that returns the color red if the sphere was hit, and the blue-white background gradient otherwise.
The last chapter introduced a ray class. Now it's time to let the ray hit something: a sphere.
Note
The following math is probably much more verbose than it needs to be. I added these step-by-step details
in case I need a refresher, and also to practice math typesetting at the same time. In future chapters
I'll probably provide details for math I found particularly important and/or difficult to follow.
The equation of a sphere centered at the origin is (1)
x2+y2+z2=R2​​
which is essentially derived from Pythagoras' Theorem extended to three dimensions.
(2)
For any (x,y,z), if x2+y2+z2=R2, then (x,y,z)
is on the sphere, otherwise it's not.
The more general equation of a sphere centered at a point (x0​,y0​,z0​) is
For center C=(x0​,y0​,z0​) and a point P=(x,y,z), we can also write:
(P−C​)⋅(P−C​)=R2​​
The ray p(t)=A+t∗B intersects the sphere where p(t)=P.
If the ray hits the sphere, there is a t for which p(t) satisfies the sphere equation.
(p(t)−C​)⋅(p(t)−C​)=R2​​
(A+t∗B−C​)⋅(A+t∗B−C​)=R2​​
I'm looking for t, and A, B, C and R are constants. I can rearrange the equation as follows:
(t∗B+(A−C)​)⋅(t∗B+(A−C)​)=R2​​
Let oc=(A−C) and rearrange:
t2∗(B⋅B)+2∗t∗(B⋅oc)+(oc⋅oc)=R2​​
Now let a=(BcdotB) and rearrange:
a∗t2+2∗t∗(B⋅oc)+oc⋅oc−R2=0​​
Let b=2∗(B⋅oc):
a∗t2+b∗t+oc⋅oc−R2=0​​
Then, let c=(occdotoc)−R2 to arrive at the normal form:
a∗t2+b∗t+c=0​​
This is a quadratic equation that can be solved for $t$ with the
Quadratic Formula:
t=2a−b±b2−4ac​​​​
The square root portion of this equation can either be positive (meaning there are two real
solutions), or zero (meaning there's one real solution), or negative (meaning there are no real
solutions).
This relates directly to the geometry. If there are two real solutions, the ray intersects the
squere at two points. If there's exactly one real solution, it touches the sphere at one point on
the surface. If there are no real solutions, then the ray doesn't touch the sphere at all.
The new function hit_sphere() implements the math derived in this chapter. The only difference is
that I only care about the root and whether it's greater than 0. I don't need a precise solution
here. All rays that miss the sphere will result in the background gradient of the previous chapter.
The sphere is located in the center of the screen with a radius of 0.5. If the ray intersects this
sphere, the color function will just return the color red for now.
Click to view C++ source code
// sphere-example.cpp
[HL]
bool hit_sphere(const vec3& center, float radius, const ray& r) {
vec3 oc = r.origin() - center;
float a = dot(r.direction(), r.direction());
float b = 2.0 * dot(oc, r.direction());
float c = dot(oc, oc) - radius * radius;
// for quadratic equation
float discriminant = b*b - 4*a*c;
// all we care about is whether the root is not 0
return (discriminant > 0);
}
[/HL]
vec3 color(const ray& r) {
[HL]
// just return red if sphere was hit
if (hit_sphere(vec3(0,0,-1), 0.5, r)) return vec3(1,0,0);
[/HL]
vec3 unit_direction = unit_vector(r.direction());
float t = 0.5f * (unit_direction.y() + 1.0f);
return (1.0f - t) * vec3(1.0f, 1.0f, 1.0f) + t * vec3(0.5f, 0.7f, 1.0f);
}
Javascript and Canvas
Here's the example in Javascript.
Loading...
Figure RT005: Simple canvas image rendered with Javascript