Building an Orbit Camera
with Spherical Coordinates

If you ever used 3D software you’ve probably used an orbit camera. It’s the control scheme where you drag the mouse to rotate around the target. It feels simple: just rotate around a point. But once you try to implement it yourself, the details of 3D rotations quickly get in the way.

When I first got into graphics I spent a lot of time building small demos to learn the basics of the pipeline. An orbit camera quickly rose to the top of my list because it made navigating those experiments so much easier. But back then, the explanations I found were either incomplete or jumped straight to quaternions. Some even tossed in a mysterious “clamp” to stop the camera from flipping upside down without ever explaining why it was necessary.

In this article, I’ll revisit the problem the way I wish it had been explained to me back then. I’ll show how to build an orbit camera using spherical coordinates: what they are, why they’re a natural fit, and the quirks that come with them. By the end, you’ll have a working implementation. You’ll also see why spherical coordinates aren’t the final word, and how their limits point toward more general solutions.


From Cartesian to polar coordinates

One of the simplest ways to implement orbit controls is with spherical coordinates, and it’s also the most common approach in model viewers. When I first came across them, they seemed like a somewhat abstract way of describing positions in space, but they turned out to be more intuitive than I expected. Spending a little time on spherical coordinates is worth it because they map directly to camera movement and appear throughout graphics. The easiest way to understand the math is to start with polar coordinates in 2D.

I’ll assume you’re familiar with vectors. In graphics, we often picture them as arrows in space that represent displacement: direction and magnitude. We usually represent vectors with scalar values for each axis (e.g., ), and compute direction and magnitude using various operations. But that’s not the only way to describe vectors. In fact, it may not even be the most natural way, especially when we’re dealing with directions and rotations.

Like Cartesian coordinates, polar coordinates in 2D space are also described by two scalars: a radius and an angle . The radius represents the distance from the origin, and the angle is measured from the positive -axis. In this system, the idea of vectors as direction and magnitude maps directly onto how we describe them. In fact, we use polar coordinates in the real world all the time, for example, giving someone a direction and a distance to walk: “go 10 meters at 45°,” or in everyday terms, “head southwest for 10 meters.”

Converting between Cartesian and polar coordinates is straightforward. To go from Cartesian to polar, we use the same operations we already know for computing a vector’s magnitude and direction. The magnitude gives us the radius , and the direction as an angle1 gives us :

To go the other way, we resolve the vector into its and components using sine and cosine. The radius scales the unit vector defined by the angle :

This shows that Cartesian and polar coordinates are simply two different ways of describing the same vector. One emphasizes components along axes, the other emphasizes distance and direction. If you’re new to polar coordinates, you might be wondering why we don’t use them everywhere in graphics.

In graphics we rely heavily on linear transformations like translation, rotation, scaling, and projection. These are neatly expressed as matrix–vector multiplications in Cartesian space. In polar space, the same operations quickly become messy. For example, translating a point isn’t as simple as just adding to or , both usually change together. Cartesian coordinates also map directly to pixel grids, memory layouts, and hardware pipelines, which makes them even more convenient. But polar has another issue that’s important to understand before we move on to spherical coordinates.

Polar coordinates have a couple of quirks. At the origin (), the angle is undefined since every angle points to the same place. Away from the origin, a single point can be represented by infinitely many coordinate pairs, since angles wrap around every (and negative radii add even more redundancy). To make polar coordinates practical, we have to normalize2 values into a chosen range. These issues are minor in 2D, but they become more pronounced in 3D. Still, there are times when the benefits outweigh the drawbacks.

Polar coordinates are very common in game development3. Any time you want to implement a tracking or chasing mechanic where one object follows a target, it’s often easier to work in polar space. But a much more common use case that’s relevant to us is moving around a sphere. But before we can get there, we need to move from polar coordinates in 2D to spherical coordinates in 3D.

Extending to spherical coordinates

Like Cartesian coordinates, extending polar coordinates into 3D requires one more value. We add a second angle, which gives us an extra degree of freedom and leads to spherical coordinates4. A point is then represented by three values: the radius, a horizontal angle (azimuth), and a vertical angle (polar). Together, describe a position in 3D space relative to an origin.

Most resources use the symbols for the angles, but there isn’t universal agreement on which is horizontal and which is vertical. In this article, will be the vertical angle and the horizontal angle. By analogy with Euler angles, behaves like pitch and like yaw.

In mathematics and physics, the horizontal angle is often measured in the plane, starting at (to the right), and the vertical angle is measured from downward toward the equator. In computer graphics, we prefer a convention that maps more cleanly to world axes: the horizontal angle starts at (forward) and increases counter-clockwise in the plane, while the vertical angle is zero in the horizontal plane, positive when tilted upward toward , and negative when tilted downward toward .

Footnotes

  1. Most languages provide atan2(y, x) to compute the angle. Prefer atan2 over atan(y/x) because it uses the signs of and to pick the correct quadrant and handles .

  2. In 2D graphics, angles are typically normalized to the range . When the radius is , the angle is undefined, so it’s common to set by convention.

  3. The first time I ran into polar coordinates in 2D was while reading an old article in the early 2000s called Sin & Cos: The Programmer’s Pals!. It described the usefulness of polar coordinates in the context of a top-down racing game like Micro Machines.

  4. The reason we give this system a new name rather than calling it “3D polar coordinates” is that there is another way to generalize polar into three dimensions: Instead of adding an angle, we could add another length value, giving us cylindrical coordinates.