具有统一面的程序圆形网格
Procedural circle mesh with uniform faces
我正在尝试用这样的统一面程序创建一个二维圆。
通常,我会 create it with a triangle fan structure,但我需要面孔大致相同。我查找示例,但只能找到 "cube to sphere" 个示例。妥协可能与此类似:
你能帮我想办法画出这个结构吗?我想用 C# 来做,但是 js 甚至伪代码都可以!
非常感谢
你让我对你的问题产生了兴趣,我想我已经找到了你正在寻找的解决方案。以下是我们如何创建您想要的拓扑:
1) 我们从六边形开始。为什么是六边形而不是其他形状?因为六边形是唯一半径等于边长的魔法形状。我们将此半径称为 R。我们现在将尝试创建一个类似于圆形的形状,由边长约为 R.
的三角形组成
2) 现在想象一些同心圆,半径为R、2R、3R等等——越多,分辨率越高。
3) 圆号 1 的半径为 R。我们现在将用半径为 R.
的六边形替换该圆
4) 我们现在将在第二个圆上添加更多节点以扩展我们的六边形。圆数N的周长是多少?是2PiRN。现在我们要将它分成 X 条边,长度约为 R。因此 X=2PiN,约等于 6N。所以我们将第一个圆分成 6 条边(六边形),第二个分成 12 条,然后是 18 条、24 条等等。
5) 现在我们有很多被分成边的圆。我们现在需要将边连接成三角形。我们如何在圆 N(外部)和 N-1(内部)之间构建三角形?外圈比内圈多 6 条边。如果它们有相同数量的顶点,我们可以用四边形连接它们。但他们没有。所以,我们仍然会尝试构建四边形,但是对于我们构建的每 N 个四边形,我们需要添加 1 个三角形。每个四边形使用来自内圆的 2 个顶点和来自外圆的 2 个顶点。每个三角形使用外圈的2个顶点和内圈的1个顶点,从而补偿多余的顶点。
6) 现在终于有一些经过测试的示例代码可以满足您的需求。它将生成一个拓扑统一的圆,圆心在原点,半径为1,分成*resolution子圆。它可以使用一些小的性能优化(现在超出范围),但总的来说它应该完成这项工作。
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;
}
}
最终结果:
我正在尝试用这样的统一面程序创建一个二维圆。
通常,我会 create it with a triangle fan structure,但我需要面孔大致相同。我查找示例,但只能找到 "cube to sphere" 个示例。妥协可能与此类似:
你能帮我想办法画出这个结构吗?我想用 C# 来做,但是 js 甚至伪代码都可以!
非常感谢
你让我对你的问题产生了兴趣,我想我已经找到了你正在寻找的解决方案。以下是我们如何创建您想要的拓扑:
1) 我们从六边形开始。为什么是六边形而不是其他形状?因为六边形是唯一半径等于边长的魔法形状。我们将此半径称为 R。我们现在将尝试创建一个类似于圆形的形状,由边长约为 R.
的三角形组成2) 现在想象一些同心圆,半径为R、2R、3R等等——越多,分辨率越高。
3) 圆号 1 的半径为 R。我们现在将用半径为 R.
的六边形替换该圆4) 我们现在将在第二个圆上添加更多节点以扩展我们的六边形。圆数N的周长是多少?是2PiRN。现在我们要将它分成 X 条边,长度约为 R。因此 X=2PiN,约等于 6N。所以我们将第一个圆分成 6 条边(六边形),第二个分成 12 条,然后是 18 条、24 条等等。
5) 现在我们有很多被分成边的圆。我们现在需要将边连接成三角形。我们如何在圆 N(外部)和 N-1(内部)之间构建三角形?外圈比内圈多 6 条边。如果它们有相同数量的顶点,我们可以用四边形连接它们。但他们没有。所以,我们仍然会尝试构建四边形,但是对于我们构建的每 N 个四边形,我们需要添加 1 个三角形。每个四边形使用来自内圆的 2 个顶点和来自外圆的 2 个顶点。每个三角形使用外圈的2个顶点和内圈的1个顶点,从而补偿多余的顶点。
6) 现在终于有一些经过测试的示例代码可以满足您的需求。它将生成一个拓扑统一的圆,圆心在原点,半径为1,分成*resolution子圆。它可以使用一些小的性能优化(现在超出范围),但总的来说它应该完成这项工作。
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;
}
}
最终结果: