计算网格细节的降低级别

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