【问题标题】:procedurally generate a sphere mesh程序生成球体网格
【发布时间】:2010-11-02 20:40:38
【问题描述】:

我正在寻找一种算法(在伪代码中),它可以像这样生成球体网格的 3d 坐标:

水平和横向切片的数量应该是可配置的

【问题讨论】:

  • 不,不是。这是一个个人项目。
  • 据我所知,这被称为球体上点的迪斯科球配置。这是最简单的配置。

标签: 3d mesh


【解决方案1】:

如果有 M 条纬线(水平)和 N 条经线(垂直),则将点放在

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

对于 { 0, ..., M } 中的每个 m 和 { 0, ..., N-1 } 中的每个 m 并相应地在点之间绘制线段。

编辑:可以根据需要将 M 调整 1 或 2,因为您应该决定是否计算两极处的“纬度线”

【讨论】:

  • +1,因为这适用于任何图形库。另一个问题:有没有办法同时控制球体的半径?
  • @kiltek :这给出了从 0 到 1 的 (x, y, z) 值。要将其缩放到任何半径,只需将每个点乘以所需的半径。
【解决方案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);
        }
    }
}

【讨论】:

【解决方案3】:

未经测试,这只是我的想法。这可能是一个很好的起点。

如果您使用双精度,这将为您提供最准确和最可定制的结果。

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. 

}

【讨论】:

    【解决方案4】:

    只是一个猜测,您可能会使用以 (0,0,0) 为中心的球体的公式

    x²+y²+z²=1
    

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

    【讨论】:

    • 不确定这是一个好主意,具体取决于相关项目的性能要求,因为这种方法肯定涉及sqrt(),我认为这很昂贵。
    • 如果有人决定他们真的想尝试这种方法,他们可能还需要被定向到Marching Cubes上的一篇文章...
    【解决方案5】:

    FWIW,您可以使用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"
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-29
      • 1970-01-01
      相关资源
      最近更新 更多