【问题标题】:Procedural circle mesh with uniform faces具有均匀面的程序圆网格
【发布时间】:2018-11-22 07:47:04
【问题描述】:

我正在尝试通过程序创建一个像这样具有统一面孔的二维圆。

通常,我会create it with a triangle fan structure,但我需要面部大致相同。我找了一些例子,但我只能找到“立方体到球体”的例子。妥协可能与此类似:

你能帮我找到一种方法来绘制这个结构吗?我想用 C# 来做,但是 js 甚至伪代码都可以!

非常感谢

【问题讨论】:

标签: javascript c# unity3d mesh


【解决方案1】:

你的问题让我很感兴趣,我想我已经找到了你正在寻找的解决方案。以下是我们如何创建您想要的拓扑:

1) 我们从一个六边形开始。为什么是六边形而不是其他形状?因为六边形是唯一一个半径等于边长的魔法形状。我们将此半径称为R。我们现在将尝试创建一个类似于圆形的形状,由边长约为 R 的三角形组成。

2) 现在想象一些同心圆,半径为 R, 2R, 3R 等等 - 越多,分辨率越高。

3) 1 号圆的半径为 R。我们现在将用半径为 R 的六边形替换该圆。

4) 我们现在将在第二个圆圈上添加更多节点来扩展我们的六边形。圆数N的周长是多少?它是2PiRN。现在我们想把它分成长度约为RX条边。因此 X=2PiN,大​​约为 6N。所以我们将第一个圆分成 6 个边(六边形),第二个分成 12 个,然后是 18、24 等等。

5) 现在我们有很多被划分为边的圆。我们现在需要将边连接成三角形。我们如何在圆 N(外)和 N-1(内)之间构建三角形?外圈比内圈多 6 条边。如果它们有相同数量的顶点,我们可以用四边形连接它们。但他们没有。所以,我们仍然会尝试构建四边形,但是对于我们构建的每 N 个四边形,我们需要添加 1 个三角形。每个四边形使用内部圆的 2 个顶点和外部圆的 2 个顶点。每个三角形使用外圆的 2 个顶点,内圆仅使用 1 个顶点,从而补偿多余的顶点。

6) 现在终于有一些经过测试的示例代码可以满足您的需要。它将生成一个拓扑均匀的圆,圆心在原点,半径为1,分成*分辨率子圆。它可以使用一些小的性能优化(目前超出范围),但总的来说它应该可以完成这项工作。

using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(MeshFilter))]
public class UniformCirclePlane : MonoBehaviour {

    public int resolution = 4;

    // Use this for initialization
    void Start() {
        GetComponent<MeshFilter>().mesh = GenerateCircle(resolution);
    }

    // Update is called once per frame
    void Update() {

    }

    // Get the index of point number 'x' in circle number 'c'
    static int GetPointIndex(int c, int x) {
        if (c < 0) return 0; // In case of center point
        x = x % ((c + 1) * 6); // Make the point index circular
                               // Explanation: index = number of points in previous circles + central point + x
                               // hence: (0+1+2+...+c)*6+x+1 = ((c/2)*(c+1))*6+x+1 = 3*c*(c+1)+x+1

        return (3 * c * (c + 1) + x + 1);
    }

    public static Mesh GenerateCircle(int res) {

        float d = 1f / res;

        var vtc = new List<Vector3>();
        vtc.Add(Vector3.zero); // Start with only center point
        var tris = new List<int>();

        // First pass => build vertices
        for (int circ = 0; circ < res; ++circ) {
            float angleStep = (Mathf.PI * 2f) / ((circ + 1) * 6);
            for (int point = 0; point < (circ + 1) * 6; ++point) {
                vtc.Add(new Vector2(
                    Mathf.Cos(angleStep * point),
                    Mathf.Sin(angleStep * point)) * d * (circ + 1));
            }
        }

        // Second pass => connect vertices into triangles
        for (int circ = 0; circ < res; ++circ) {
            for (int point = 0, other = 0; point < (circ + 1) * 6; ++point) {
                if (point % (circ + 1) != 0) {
                    // Create 2 triangles
                    tris.Add(GetPointIndex(circ - 1, other + 1));
                    tris.Add(GetPointIndex(circ - 1, other));
                    tris.Add(GetPointIndex(circ, point));
                    tris.Add(GetPointIndex(circ, point));
                    tris.Add(GetPointIndex(circ, point + 1));
                    tris.Add(GetPointIndex(circ - 1, other + 1));
                    ++other;
                } else {
                    // Create 1 inverse triange
                    tris.Add(GetPointIndex(circ, point));
                    tris.Add(GetPointIndex(circ, point + 1));
                    tris.Add(GetPointIndex(circ - 1, other));
                    // Do not move to the next point in the smaller circle
                }
            }
        }

        // Create the mesh
        var m = new Mesh();
        m.SetVertices(vtc);
        m.SetTriangles(tris, 0);
        m.RecalculateNormals();
        m.UploadMeshData(true);

        return m;

    }
}

最终结果:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-21
    • 1970-01-01
    • 2015-02-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多