按程序生成球体网格

33

我正在寻找一种算法(伪代码)来生成像这样的球体网格的三维坐标:

alt text

水平和垂直切片的数量应可配置。


4
不是的,这是为了一个个人项目。 - clamp
据我所知,这被称为球面上点的迪斯科球配置。这是最简单的配置。 - bandybabboon
5个回答

47
如果有M条纬线(水平)和N条经线(垂直),则在每个m∈{0,...,M}和n∈{0,...,N-1}处放置点(x,y,z)=(sin(Pi * m/M) cos(2Pi * n/N), sin(Pi * m/M) sin(2Pi * n/N), cos(Pi * m/M)),并相应地在点之间绘制连线段。 编辑:根据需要调整M的值,因为你应该决定是否计算极点处的“纬线”。

2
+1,因为这适用于任何图形库。另一个问题:有没有办法同时控制球体的半径? - kiltek
6
这段话的意思是:这些值给出了(x, y, z)在0到1之间的范围。要将其缩放到任何半径,只需将每个点乘以所需的半径即可。 - Carrotman42

4

顺便提一句,你可以使用 meshzoo(我开发的一个项目)非常容易地生成球面网格。

如果需要进一步优化,您还可以选择使用optimesh(我另外一个项目)。

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


2

这只是我随意想到的,没有经过测试。它可以成为一个很好的起点。

如果您使用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. 

}

2
这是一个适用于上述答案的 C# 工作代码:

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);
        }
    }
}

1
我已在Unity中测试过,它可以正常工作。但是我的编辑 https://stackoverflow.com/review/suggested-edits/24704133 被拒绝了。为什么?@yshahak 你能添加我的更改吗? - Clemens Tolboom

1

仅仅是猜测,你可能可以使用以(0,0,0)为中心的球体公式

x²+y²+z²=1

解决x的问题,然后循环遍历一组y和z的值,并使用计算出的x绘制它们的图表。

1
不确定这是否是一个好主意,取决于所涉及项目的性能要求,因为这种方法肯定涉及到 sqrt(),我认为这是很昂贵的。 - Victor Zamanian
如果有人决定尝试这种方法,他们可能还需要被引导到一篇关于“Marching Cubes”的文章(https://en.wikipedia.org/wiki/Marching_cubes)... - porglezomp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接