Sherical coordinates

The basics of spherical coordinates for creative coding

Sherical coordinates

I'm playing around with the idea of creating a music visualiser in the shape of an Orb. I figured if I could generate a mesh of a sphere it would be a great start, and hopefully give me a reusable function which I could add to my library.

Let's build a function that'll generate Cartesian coordinates of a sphere. Our starting point for this is the Spherical Coordinates Wikipedia Article, on which I can find the following formula:

Since we have 2 variables (theta & phi), this will translate in code to a double loop to iterate through all the angle combinations. Similar to polar coordinates but with an extra level to account for the 3rd dimension.

It looks something like this:

/**
 * Generates a set of spherical coordinates around a given center point.
 * 
 * @param {number} radius - The radius of the sphere.
 * @param {number} [resolution=100] - The number of points per full rotation. Higher values result in more detailed spheres.
 * @param {number} [x=0] - The x-coordinate of the sphere's center.
 * @param {number} [y=0] - The y-coordinate of the sphere's center.
 * @param {number} [z=0] - The z-coordinate of the sphere's center.
 * @returns {Array<Object>} data - A nested array of points on the sphere. Each point is an object with x, y, and z properties.
 */
function sphericalCoordinates(
  radius,
  resolution = 50,
  x = 0,
  y = 0,
  z = 0
) {
  const twoPi = Math.PI * 2;

  // The angular distance between each point
  const angleStep = twoPi / resolution;

  // Initialize the array that will store the generated points
  const data = [];

  for (let theta = 0; theta < twoPi; theta += angleStep) {
    const layer = [];

    for (let phi = 0; phi < twoPi; phi += angleStep) {
      // Convert spherical coordinates (radius, theta, phi) to Cartesian coordinates (x, y, z)
      layer.push({
        x: x + radius * Math.sin(theta) * Math.cos(phi),
        y: y + radius * Math.cos(theta),
        z: z + radius * Math.sin(theta) * Math.sin(phi)
      });
    }

    // Add this layer to the overall data array
    data.push(layer);
  }
  return data;
}

Once you have the points to draw, you can simply iterate over them and place them on the screen as such:

beginShape(POINTS);
for (const row of sphereData) {
  for (const item of row) {
    vertex(item.x, item.y, item.z)
  }
}
p5.endShape();

Here's an example of it in action: