Uniform Sampling on Sphere Surface
2023-6-15 16:10:37
When generating uniform spheres on a sphere surface in Unity, I found an interesting solution. This algorithm generates uniform points on the sphere surface by using golden angle.
The Unity code of generating spheres in C#:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SphereGen : MonoBehaviour
{
private GameObject Spheres;
void Start()
{
float scaling = 50;
Vector3[] pts = PointsOnSphere(1000);
List<GameObject> uspheres = new List<GameObject>();
Spheres = new GameObject("Spheres");
Spheres.transform.position = transform.position;
int i = 0;
foreach (Vector3 value in pts)
{
uspheres.Add(GameObject.CreatePrimitive(PrimitiveType.Sphere));
uspheres[i].transform.SetParent(Spheres.transform);
uspheres[i].transform.position = transform.position + value * scaling;// local position
i++;
}
}
Vector3[] PointsOnSphere(int n)
{
List<Vector3> upts = new List<Vector3>();
float inc = Mathf.PI * (3 - Mathf.Sqrt(5));
//float inc = Mathf.PI * (Mathf.Sqrt(5) - 1);//golden ratio
float off = 2.0f / n;
float x, y, z, r, phi = 0;
for (var k = 0; k < n; k++)
{
y = k * off - 1 + (off / 2);
r = Mathf.Sqrt(1 - y*y);
phi = k * inc;
x = Mathf.Cos(phi) * r;
z = Mathf.Sin(phi) * r;
upts.Add(new Vector3(x, y, z));
}
Vector3[] pts = upts.ToArray();
return pts;
}
// Update is called once per frame
void Update()
{
//If you change the position of center before running,
//the script will still keeps the inital position.
//Therefore we need to update the current transform.
Spheres.transform.position = transform.position;
}
}
The key point is in function PointsOnSphere()
, where firstly calculate inc
, which is the radian of golden angle:
i n c = π ( 3 − 5 ) \begin {align*} & inc = \pi(3-\sqrt5) \end {align*} inc=π(3−5)
the variable off
divides the whole height of a sphere whose radius equals to 1 into n n n parts. The height of each point then can be calculated:
y = 2 k + 1 n − 1 \begin {align*} & y = \frac{2k+1}{n}-1 \end {align*} y=n2k+1−1
At each height, the related radius plane can be calculated, according to the triangle in the figure.
r = 1 − y 2 \begin {align*} & r = \sqrt{1-y^2} \end {align*} r=1−y2
Then how to get the uniformly distributed x x x and y y y coordinates? The golden angle. This angle is used orderly, generated sequence of points at different heights, or at different angles if they are at the same plane. The angle difference is the golden angle. The generated grid is also called Fibonacci grid. As shown in this figure(source):
After that, the x x x and y y y coordinates can be calculated(in Unity using left-hand coordinates):
ϕ = k ∗ i n c x = r cos ( ϕ ) z = r sin ( ϕ ) \begin {align*} & \phi = k*inc\\ & x=r\cos(\phi)\\ & z=r\sin(\phi) \end {align*} ϕ=k∗incx=rcos(ϕ)z=rsin(ϕ)
The generated result in Unity:
I want to illustrate more about the transfer between golden angle and golden ration. Assume a round with radius equasl to 1. We know the golden ratio:
φ = 1 + 5 2 = 1.618 \begin {align*} & \varphi = \frac{1+\sqrt5}{2} = 1.618 \end {align*} φ=21+5=1.618
Then for in the round, the part of the golden angle could be:
2 π ∗ 1 φ = − π ( 1 − 5 ) 2 \begin {align*} & 2\pi*\frac{1}{\varphi} = -\pi\frac{(1-\sqrt5)}{2} \end {align*} 2π∗φ1=−π2(1−5)
Also, the other part of the round can also be defined as golden angle:
2 π − 2 π 1 φ = 2 π ( 1 + 1 − 5 2 ) = π ( 3 − 5 ) \begin {align*} & 2\pi-2\pi\frac{1}{\varphi} = 2\pi(1+ \frac{1-\sqrt5}{2})=\pi(3-\sqrt5) \end {align*} 2π−2πφ1=2π(1+21−5)=π(3−5)