计算网格细节的降低级别
calculating reduced level of details of a mesh
我正在尝试创建随机地形网格,正如我在下面的屏幕截图中所做的那样:
但是,我面临的问题是在尝试减少三角形和顶点(细节级别)的数量时。
我知道为此我可以跳过顶点。
例如:
上面的网格是完整的细节,因为顶点是这样生成的:
0->1->2->3->4->5->6->7->8->9->...
为了生成较低级别的细节,我可以跳过顶点,只要跳过的顶点不超过顶点的长度,这样我就可以进行后续生成以降低细节:
0->2->4->6->8->10->12->14->16->...
或:
0->4->8->12->16->20->24->28->32->...
使用二维数组和嵌套循环使这变得微不足道,因为二维坐标 x/y 上的每次迭代都可以增加增量:1、2、4、8,但是,我正在处理二维数组一维格式。
我有以下代码执行并几乎正确地生成上面屏幕截图中的上述网格。
不幸的是,它似乎确实缺少左上角(3d z 轴)的一行顶点,如下所示:
下面对 Execute(int, int) 方法的一个警告是,如果数组正在访问其批量大小之外的索引,则对未标记为 [ReadOnly] 的 NativeArray 的任何访问都将引发异常。
public struct int6
{
public int a, b, c, d, e, f;
public int6(int a, int b, int c, int d, int e, int f) { this.a = a; this.b = b; this.c = c; this.d = d; this.e = e; this.f = f; }
}
public class MeshGeneratorJob2
{
[ReadOnly] public static int width = 241;
[ReadOnly] public static int height = 241;
[ReadOnly] public static float topLeftX = (width - 1) / -2f;
[ReadOnly] public static float topLeftZ = (height - 1) / 2f;
[ReadOnly] public static NativeArray<float> heightMap = new NativeArray<float>(width * height, Allocator.TempJob);
public static NativeArray<float> heightCurveSamples;
public static NativeArray<float3> vertices = new NativeArray<float3>(width * height, Allocator.TempJob);
public static NativeArray<int6> triangles = new NativeArray<int6>((width - 1) * (height - 1), Allocator.TempJob);
public static NativeArray<float2> uvs = new NativeArray<float2>(width * height, Allocator.TempJob);
public void Execute()
{
for (int i = 0; i < vertices.Length; i += 5)
{
Execute(i, 5);
}
}
private void Execute(int startIndex, int count)
{
for (int vertexIndex = startIndex; vertexIndex < startIndex + count; vertexIndex++)
{
int x = vertexIndex % width;
int y = vertexIndex / width;
vertices[vertexIndex] = new float3(topLeftX + x, heightMap[vertexIndex] * 16.67f, topLeftZ - y);
uvs[vertexIndex] = new float2(x / (float)width, y / (float)height);
if (vertexIndex < triangles.Length && x < width - 1 && y < height - 1)
{
triangles[vertexIndex] = new int6(vertexIndex, vertexIndex + width + 1, vertexIndex + width,
vertexIndex + width + 1, vertexIndex, vertexIndex + 1);
}
}
}
}
我想出了以下解决这个问题的方法:
我解决的第一个问题是使用嵌套的 for 循环 y, x,其中 y 始终从 startIndex 开始。
然而,这导致了一个问题,因为 vertexIndex 可能高于三角形的长度,所以我计算了提供的 startIndex 处的当前 vertexIndex,如下所示:
这里我引入了一个增量值,它增加了 x 和 y 循环而不是 y++,x++ 但是在这个例子中增量是 1,这本质上是一样的。
int vertexIndex = (int)(math.ceil((float)width / incrementer) * math.ceil((float)startIndex / incrementer));
但是计算 vertexIndex 导致了另一个问题,该问题再次导致设置顶点时出现越界异常。
这是由于 startIndex 按计数递增,其中计数与增量器不同。
为了解决这个问题,我在方法的开头添加了以下代码,以根据需要将 startIndex 舍入到下一个增量计数。
startIndex += startIndex % incrementer;
然后我总共得到以下代码:
public struct int6
{
public int a, b, c, d, e, f;
public int6(int a, int b, int c, int d, int e, int f) { this.a = a; this.b = b; this.c = c; this.d = d; this.e = e; this.f = f; }
}
public class MeshGeneratorJob2
{
public static int width = 241;
public static int height = 241;
public static float topLeftX = (width - 1) / -2f;
public static float topLeftZ = (height - 1) / 2f;
public static int increment = 1;
public static NativeArray<float> heightMap = new NativeArray<float>(width * height, Allocator.TempJob);
public static NativeArray<float> heightCurveSamples;
public static NativeArray<float3> vertices = new NativeArray<float3>(width * height, Allocator.TempJob);
public static NativeArray<int6> triangles = new NativeArray<int6>((width - 1) * (height - 1), Allocator.TempJob);
public static NativeArray<float2> uvs = new NativeArray<float2>(width * height, Allocator.TempJob);
public void Execute()
{
for (int i = 0; i < vertices.Length; i += 5)
{
Execute(i, 5);
}
}
private void Execute(int startIndex, int count)
{
startIndex += startIndex % increment;
int vertexIndex = (int)(math.ceil((float)width / increment) * math.ceil((float)startIndex / increment));
for (int y = startIndex; y < startIndex + count && y < height; y++)
{
for (int x = 0; x < width; x += increment)
{
vertices[vertexIndex] = new float3(topLeftX + x, heightMap[vertexIndex] * 16.67f, topLeftZ - y);
uvs[vertexIndex] = new float2(x / (float)width, y / (float)height);
if (vertexIndex < triangles.Length && x < width - 1 && y < height - 1)
{
triangles[vertexIndex] = new int6(vertexIndex, vertexIndex + width + 1, vertexIndex + width,
vertexIndex + width + 1, vertexIndex, vertexIndex + 1);
}
vertexIndex++;
}
}
}
}
我正在尝试创建随机地形网格,正如我在下面的屏幕截图中所做的那样:
但是,我面临的问题是在尝试减少三角形和顶点(细节级别)的数量时。
我知道为此我可以跳过顶点。 例如: 上面的网格是完整的细节,因为顶点是这样生成的:
0->1->2->3->4->5->6->7->8->9->...
为了生成较低级别的细节,我可以跳过顶点,只要跳过的顶点不超过顶点的长度,这样我就可以进行后续生成以降低细节:
0->2->4->6->8->10->12->14->16->...
或:
0->4->8->12->16->20->24->28->32->...
使用二维数组和嵌套循环使这变得微不足道,因为二维坐标 x/y 上的每次迭代都可以增加增量:1、2、4、8,但是,我正在处理二维数组一维格式。
我有以下代码执行并几乎正确地生成上面屏幕截图中的上述网格。
不幸的是,它似乎确实缺少左上角(3d z 轴)的一行顶点,如下所示:
下面对 Execute(int, int) 方法的一个警告是,如果数组正在访问其批量大小之外的索引,则对未标记为 [ReadOnly] 的 NativeArray 的任何访问都将引发异常。
public struct int6
{
public int a, b, c, d, e, f;
public int6(int a, int b, int c, int d, int e, int f) { this.a = a; this.b = b; this.c = c; this.d = d; this.e = e; this.f = f; }
}
public class MeshGeneratorJob2
{
[ReadOnly] public static int width = 241;
[ReadOnly] public static int height = 241;
[ReadOnly] public static float topLeftX = (width - 1) / -2f;
[ReadOnly] public static float topLeftZ = (height - 1) / 2f;
[ReadOnly] public static NativeArray<float> heightMap = new NativeArray<float>(width * height, Allocator.TempJob);
public static NativeArray<float> heightCurveSamples;
public static NativeArray<float3> vertices = new NativeArray<float3>(width * height, Allocator.TempJob);
public static NativeArray<int6> triangles = new NativeArray<int6>((width - 1) * (height - 1), Allocator.TempJob);
public static NativeArray<float2> uvs = new NativeArray<float2>(width * height, Allocator.TempJob);
public void Execute()
{
for (int i = 0; i < vertices.Length; i += 5)
{
Execute(i, 5);
}
}
private void Execute(int startIndex, int count)
{
for (int vertexIndex = startIndex; vertexIndex < startIndex + count; vertexIndex++)
{
int x = vertexIndex % width;
int y = vertexIndex / width;
vertices[vertexIndex] = new float3(topLeftX + x, heightMap[vertexIndex] * 16.67f, topLeftZ - y);
uvs[vertexIndex] = new float2(x / (float)width, y / (float)height);
if (vertexIndex < triangles.Length && x < width - 1 && y < height - 1)
{
triangles[vertexIndex] = new int6(vertexIndex, vertexIndex + width + 1, vertexIndex + width,
vertexIndex + width + 1, vertexIndex, vertexIndex + 1);
}
}
}
}
我想出了以下解决这个问题的方法:
我解决的第一个问题是使用嵌套的 for 循环 y, x,其中 y 始终从 startIndex 开始。
然而,这导致了一个问题,因为 vertexIndex 可能高于三角形的长度,所以我计算了提供的 startIndex 处的当前 vertexIndex,如下所示: 这里我引入了一个增量值,它增加了 x 和 y 循环而不是 y++,x++ 但是在这个例子中增量是 1,这本质上是一样的。
int vertexIndex = (int)(math.ceil((float)width / incrementer) * math.ceil((float)startIndex / incrementer));
但是计算 vertexIndex 导致了另一个问题,该问题再次导致设置顶点时出现越界异常。 这是由于 startIndex 按计数递增,其中计数与增量器不同。
为了解决这个问题,我在方法的开头添加了以下代码,以根据需要将 startIndex 舍入到下一个增量计数。
startIndex += startIndex % incrementer;
然后我总共得到以下代码:
public struct int6
{
public int a, b, c, d, e, f;
public int6(int a, int b, int c, int d, int e, int f) { this.a = a; this.b = b; this.c = c; this.d = d; this.e = e; this.f = f; }
}
public class MeshGeneratorJob2
{
public static int width = 241;
public static int height = 241;
public static float topLeftX = (width - 1) / -2f;
public static float topLeftZ = (height - 1) / 2f;
public static int increment = 1;
public static NativeArray<float> heightMap = new NativeArray<float>(width * height, Allocator.TempJob);
public static NativeArray<float> heightCurveSamples;
public static NativeArray<float3> vertices = new NativeArray<float3>(width * height, Allocator.TempJob);
public static NativeArray<int6> triangles = new NativeArray<int6>((width - 1) * (height - 1), Allocator.TempJob);
public static NativeArray<float2> uvs = new NativeArray<float2>(width * height, Allocator.TempJob);
public void Execute()
{
for (int i = 0; i < vertices.Length; i += 5)
{
Execute(i, 5);
}
}
private void Execute(int startIndex, int count)
{
startIndex += startIndex % increment;
int vertexIndex = (int)(math.ceil((float)width / increment) * math.ceil((float)startIndex / increment));
for (int y = startIndex; y < startIndex + count && y < height; y++)
{
for (int x = 0; x < width; x += increment)
{
vertices[vertexIndex] = new float3(topLeftX + x, heightMap[vertexIndex] * 16.67f, topLeftZ - y);
uvs[vertexIndex] = new float2(x / (float)width, y / (float)height);
if (vertexIndex < triangles.Length && x < width - 1 && y < height - 1)
{
triangles[vertexIndex] = new int6(vertexIndex, vertexIndex + width + 1, vertexIndex + width,
vertexIndex + width + 1, vertexIndex, vertexIndex + 1);
}
vertexIndex++;
}
}
}
}