Diamond-Square算法的平滑问题

Fro*_*bot 4 algorithm height procedural-programming map procedural-generation

我使用菱形平方算法生成随机地形.它工作得很好,除了我将这些大锥形状伸出或伸入地形.问题似乎是每时不时地设置一个点太高或太低.

这是问题的图片
截图

当我将平滑度设置得非常高时,可以更好地看到它
截图特写

这是我的代码 -

private void CreateHeights()
    {
        if (cbUseLand.Checked == false) 
            return;
        int
            Size = Convert.ToInt32(System.Math.Pow(2, int.Parse(tbDetail.Text)) + 1),
            SideLength = Size - 1,
            d = 1025 / (Size - 1),
            HalfSide;
        Heights = new Point3D[Size, Size];
        float
            r = float.Parse(tbHeight.Text),
            Roughness = float.Parse(RoughnessBox.Text);

        //seeding all the points
        for (int x = 0; x < Size; x++)
            for (int y = 0; y < Size; y++)
                Heights[x, y] = Make3DPoint(x * d, 740, y * d);

        while (SideLength >= 2)
        {
            HalfSide = SideLength / 2;

            for (int x = 0; x < Size - 1; x = x + SideLength)
            {
                for (int y = 0; y < Size - 1; y = y + SideLength)
                {
                    Heights[x + HalfSide, y + HalfSide].y =
                      (Heights[x, y].y +
                      Heights[x + SideLength, y].y +
                      Heights[x, y + SideLength].y +
                      Heights[x + SideLength, y + SideLength].y) / 4 - r + ((float)(random.NextDouble() * r) * 2);
                }
            }

            for (int x = 0; x < Size - 1; x = x + SideLength)
            {
                for (int y = 0; y < Size - 1; y = y + SideLength)
                {
                    if (y != 0)
                        Heights[x + HalfSide, y].y = (Heights[x, y].y + Heights[x + SideLength, y].y + Heights[x + HalfSide, y + HalfSide].y + Heights[x + HalfSide, y - HalfSide].y) / 4 - r + ((float)(random.NextDouble() * r) * 2); 
                    if (x != 0)
                        Heights[x, y + HalfSide].y = (Heights[x, y].y + Heights[x, y + SideLength].y + Heights[x + HalfSide, y + HalfSide].y + Heights[x - HalfSide, y + HalfSide].y) / 4 - r + ((float)(random.NextDouble() * r) * 2);
                }
            }
            SideLength = SideLength / 2;
            r = r / Roughness;
        }
    }
Run Code Online (Sandbox Code Playgroud)

Eng*_*eer 6

Gavin SP Miller给出了SIGGRAPH '86关于Fournier,Fussel和Carpenter原始算法如何从根本上存在缺陷的讨论.因此,您所看到的对于Diamond Square算法的任何天真实现都是正常的.您将需要一个单独的平滑方法,或者发布每个Diamond-Square复合步骤,或者作为后处理到所有菱形平方迭代(或两者).米勒解决了这个问题.加权和盒式或高斯滤波是一种选择; 将初始数组播种到比初始4个点更大的程度(即,手动或使用一些内置智能复制菱形方块的前几个步骤的结果集,而是提供无偏值); 在使用菱形方块增加细节之前,您为阵列提供的初始信息越多,结果就越好.

原因似乎在于如何执行Square步骤.在Diamond步骤中,我们采用了正方形四角的平均值来生成该正方形的中心.然后,在随后的Square步骤中,我们取四个正交相邻的邻居的平均值,其中一个是我们刚刚生成的正方形中心点.你能看到问题吗?那些原始角高值对后续的菱形平方迭代贡献过多,因为它们通过它们自己的影响和通过它们创建的中点来贡献.这会导致尖顶(突出和侵入),因为局部衍生点更倾向于那些早期点...并且因为(通常3)其他点也会这样做,这会在迭代时围绕这些点产生"循环"影响钻石广场使用更高的深度.因此,只有当数组的初始状态未指定时,才会出现这些"混叠"问题; 实际上,发生的伪像可以看作是仅使用4个点开始的直接几何结果.

您可以执行以下操作之一:

  • 做局部过滤 - 通常很贵.
  • 更彻底地预先播种初始阵列 - 需要一些智能.
  • 永远不要从给定的一组初始点平滑过多的步骤 - 即使你对初始数组进行种子处理也是如此,这只是相对深度和你自己的最大位移参数的关系.