Spherical coordinates for camera offset

Spherical coordinates are based on positional offset relative to a sphere’s center point, and seem well suited to this task. On the side I happened to be working on a game that makes heavy use of spherical coordinates, so when doing this section and assigning the second stick to camera movement, I wanted to try taking a mathematical approach.

I used the formula for converting between spherical coordinates and cartesian (x, y, z) coordinates on Wikipedia.

Note: the Y and Z are switched to compensate for Y being “up” in Unity

Here is my solution, with the Polar class borrowed from my other game.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraManager : MonoBehaviour
{
	public GameObject followTarget;
	public float distance = 10f;
	public float speed = 1f;
	private Polar polarOffset;

	private void Awake()
	{
		polarOffset = new Polar(distance, 90f, 90f);
	}

	private void LateUpdate()
	{
		// The angle from the "north pole" (polar angle)
		float targetInclination = polarOffset.inclination + (Input.GetAxis("RightVertical") * speed * Time.deltaTime);
		// Clamping inclination prevents rotational weirdness when at/beyond the poles
		polarOffset.inclination = Mathf.Clamp(targetInclination, 1f, 179f);

		// The angle around the "equator"
		polarOffset.azimuth = polarOffset.azimuth + Input.GetAxis("RightHorizontal") * speed * Time.deltaTime;

		Vector3 offset = polarOffset.ToCartesian();
		transform.position = followTarget.transform.position + offset;
		transform.LookAt(followTarget.transform);
	}
}

public class Polar
{
	public float radius, inclination, azimuth;
	
	public static Vector3 ToCartesian(float radius, float inclination, float azimuth)
	{
		float x = radius * Mathf.Sin(inclination * Mathf.Deg2Rad) * Mathf.Cos(azimuth * Mathf.Deg2Rad);
		float y = radius * Mathf.Cos(inclination * Mathf.Deg2Rad);
		float z = radius * Mathf.Sin(inclination * Mathf.Deg2Rad) * Mathf.Sin(azimuth * Mathf.Deg2Rad);
		return new Vector3(x, y, z);
	}

	public Polar(float radius, float inclination, float azimuth)
	{
		this.radius = radius;
		this.inclination = inclination;
		this.azimuth = azimuth;
	}

	public Vector3 ToCartesian()
	{
		return Polar.ToCartesian(radius, inclination, azimuth);
	}
}

I just figured I’d post this method, as it can be handy to have different solutions to pull from later.

1 Like

Privacy & Terms