29
votes

i am looking for an algorithm ( in pseudo code) that generates the 3d coordinates of a sphere mesh like this:

alt text

the number of horizontal and lateral slices should be configurable

5
no, it's not. it's for a personal project.clamp
that's called a disco ball configuration of points on a sphere as far as i know. its the easiest configuration.LifeInTheTrees

5 Answers

43
votes

If there are M lines of latitude (horizontal) and N lines of longitude (vertical), then put dots at

(x, y, z) = (sin(Pi * m/M) cos(2Pi * n/N), sin(Pi * m/M) sin(2Pi * n/N), cos(Pi * m/M))

for each m in { 0, ..., M } and n in { 0, ..., N-1 } and draw the line segments between the dots, accordingly.

edit: maybe adjust M by 1 or 2 as required, because you should decide whether or not to count "latitude lines" at the poles

2
votes

This is a working C# code for the above answer:

using UnityEngine;

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class ProcSphere : MonoBehaviour
{

    private Mesh mesh;
    private Vector3[] vertices;

    public int horizontalLines, verticalLines;
    public int radius;

    private void Awake()
    {
        GetComponent<MeshFilter>().mesh = mesh = new Mesh();
        mesh.name = "sphere";
        vertices = new Vector3[horizontalLines * verticalLines];
        int index = 0;
        for (int m = 0; m < horizontalLines; m++)
        {
            for (int n = 0; n < verticalLines - 1; n++)
            {
                float x = Mathf.Sin(Mathf.PI * m/horizontalLines) * Mathf.Cos(2 * Mathf.PI * n/verticalLines);
                float y = Mathf.Sin(Mathf.PI * m/horizontalLines) * Mathf.Sin(2 * Mathf.PI * n/verticalLines);
                float z = Mathf.Cos(Mathf.PI * m / horizontalLines);
                vertices[index++] = new Vector3(x, y, z) * radius;
            }
        }
        mesh.vertices = vertices;
    }

    private void OnDrawGizmos()
    {
        if (vertices == null) {
            return;
        }
        for (int i = 0; i < vertices.Length; i++) {
            Gizmos.color = Color.black;
            Gizmos.DrawSphere(transform.TransformPoint(vertices[i]), 0.1f);
        }
    }
}
2
votes

This is just off the top of my head without testing. It could be a good starting point.

This will give you the most accurate and customizable results with the most degree of precision if you use double.

public void generateSphere(3DPoint center, 3DPoint northPoint
                          , int longNum, int latNum){

     // Find radius using simple length equation
        (distance between center and northPoint)

     // Find southPoint using radius.

     // Cut the line segment from northPoint to southPoint
        into the latitudinal number

     // These will be the number of horizontal slices (ie. equator)

     // Then divide 360 degrees by the longitudinal number
        to find the number of vertical slices.

     // Use trigonometry to determine the angle and then the
        circumference point for each circle starting from the top.

    // Stores these points in however format you want
       and return the data structure. 

}
1
votes

just a guess, you could probably use the formula for a sphere centered at (0,0,0)

x²+y²+z²=1

solve this for x, then loop throuh a set of values for y and z and plot them with your calculated x.

0
votes

FWIW, you can use meshzoo (a project of mine) to generate meshes on spheres very easily.

You can optionally use optimesh (another one out of my stash) to optimize even further.

import meshzoo
import optimesh

points, cells = meshzoo.icosa_sphere(10)


class Sphere:
    def f(self, x):
        return (x[0] ** 2 + x[1] ** 2 + x[2] ** 2) - 1.0

    def grad(self, x):
        return 2 * x

points, cells = optimesh.cvt.quasi_newton_uniform_full(
    points, cells, 1.0e-2, 100, verbose=False,
    implicit_surface=Sphere(),
    # step_filename_format="out{:03d}.vtk"
)

enter image description here