Sphere
This post is part of a course on geometric modeling at the Summer Liberal Arts Institute for Computer Science held at Carleton College in 2021.
Consider the sphere. How are spheres made in nature? There are several ways. The sphere we live on was formed by gravity pulling masses together into a ball. Rocks smooth to spheres when forces erode them on all sides equally. Nature’s sphere-making processes take eons. We humans don’t have that kind of time, so we use math to speed things. In this exercise, we’ll make a sphere as surface of revolution.
Draw
On your paper, draw a semi-circle that forms the right side of a sphere, starting at the south pole and ending at the north. Label the south pole as -90 degrees. What is that in radians? Label the north pole as 90 degrees. What is that in radians?
Draw five or more points between the poles of the semi-circle, distributed evenly. Do not include the poles for reasons we’ll discuss later. The points you did draw represent a set of seed points, which are the starting points along the first line of longitude. To generate the other lines of longitude, you will rotate this first line around the y-axis.
Function
Write a function named generateSphere
. Have it accept these parameters:
- An integer
nlatitudes
that specifies the number of lines of latitude that the sphere has. The higher the number, the more spherical it will be. - An integer
nlongitudes
that specifies the number of lines of longitude that the sphere has. The higher the number, the more spherical it will be. - The
radius
of the sphere.
Create an empty positions and triangle arrays and return them in an object.
Seed Positions
Before generating the big list of vertex of positions all across the sphere, write code to generate just the single line of longitude that you drew earlier. Follow these steps:
- All told, the semicircle is $pi$ radians, and you want to break it up into
nlatitudes
slices. Compute the number of radians per slice and store it inradiansPerSlice
. - Create an empty array of seed points. Call it
seeds
perhaps. - Loop through all the latitude indices.
- Inside the loop, range-map the latitude index from its interval to the interval of possible radians of the lines of latitude. The bottom-most line of latitude, which sits just above the south pole, sits at $-\frac{\pi}{2} + \mathrm{radiansPerSlice}$. The top-most line of latitude, which sits just below the north pole, sits at $\frac{\pi}{2} – \mathrm{radiansPerSlice}$.
- Convert the radians to a seed point’s xy-coordinates.
- Assume the z-coordinate is 0.
- Turn the coordinates into a vector with this code: If the points are in vector form, they are easier to rotate.
const seed = new THREE.Vector3(x, y, z);
- Push the seed into the array of seed points.
Test that your seed points appear along a semicircle on the right side of the sphere by rendering as points and changing your return
statement to this:
return {positions: seeds.flatMap(seed => seed.toArray()), triangles};
If that worked, great! If not, let’s talk.
Vertex Positions
The next task is to rotate the line of seed points all around the sphere to form the lines of longitude. Follow these steps to produce the full array of vertex positions:
- Add a loop that visits each longitude index.
- Inside the loop, calculate the longitude’s angle around the sphere in radians by range-mapping the longitude index to $[0, 2\pi]$.
- Create a matrix that rotates a position around the y-axis by the longitude’s angle with code like this:
const matrix = new THREE.Matrix4().makeRotationY(radians);
- Add an inner loop that visits each latitude index.
- Inside the inner loop, use the latitude index to look up the seed.
- Clone and multiply the seed with code like this: Adapt the names of variables accordingly. The call to
const rotatedPosition = seed.clone().applyMatrix4(matrix);
clone
makes an independent copy of the seed position. If you don’t make an independent copy, you will rotate the original seed point, which would interfere with subsequent lines of longitude. TheapplyMatrix4
method performs a matrix-vector multiplication. Most movement in computer graphics is accomplished by multiplying matrices and vectors. - Push the rotated position into your positions array with code like this:
positions.push(rotatedPosition.x, rotatedPosition.y, rotatedPosition.z);
- After the loops are all finished, push the coordinates of the south and north poles into the array. What will their indices be?
When you restore the return statement and render as points, you should see the entire sphere covered.
Triangles
Stitching together the vertices of the sphere is just like stitching together the vertices of the cylinder, though the winding order may need to be adjusted. The poles are treated like the caps of the cylinder.