4

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

这是问题的图片
截屏

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

这是我的代码 -

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

4 回答 4

6

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

原因似乎在于 Square 步骤的执行方式。在菱形步骤中,我们取正方形四个角的平均值来生成该正方形的中心。然后,在随后的 Square 步骤中,我们取四个正交相邻邻居的平均值,其中一个是我们刚刚生成的正方形的中心点. 你能看出问题吗?那些原始的角高度值对随后的菱形正方形迭代贡献太大,因为它们通过它们自己的影响和它们创建的中点都做出了贡献。这会导致尖顶(突出和侵入),因为本地派生的点更倾向于那些早期点......并且因为(通常 3 个)其他点也是如此,这会在您迭代时在这些点周围产生“圆形”影响使用 Diamond-Square 到更高的深度。因此,这些“混叠”问题仅在未指定数组的初始状态时出现;事实上,发生的伪影可以看作是仅使用 4 个点开始的直接几何结果。

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

  • 做本地过滤——通常很昂贵。
  • 更彻底地预先播种初始阵列 - 需要一些智能。
  • 永远不要从给定的一组初始点平滑太多的步骤 - 即使您确实为初始数组播种,这也适用于您自己的最大位移参数的相对深度问题。
于 2012-10-17T12:44:51.153 回答
0

我相信每次迭代中位移 r 的大小应该与当前矩形的大小成正比。这背后的逻辑是分形表面是尺度不变的,因此任何矩形的高度变化都应该与该矩形的大小成正比。

在您的代码中,高度的变化与 r 成正比,因此您应该保持它与当前网格大小的大小成正比。换句话说:将 r 乘以循环前的粗糙度,然后在每次迭代中将 r 除以 2。

所以,而不是

r = r / Roughness;

你应该写

r = r / 2;
于 2011-09-26T02:06:22.380 回答
0

上述算法的实际缺陷是概念化和实现上的错误。Diamond square 作为一种算法有一些伪影,但这是基于范围的伪影。因此,某些像素的技术最大值高于其他一些像素。一些像素通过随机性直接给出值,而另一些像素通过菱形和平方中点插值过程获得它们的值。

这里的错误是你从零开始。并反复将该值添加到当前值。这导致菱形平方的范围从零开始并向上延伸。它实际上必须从零开始,并根据随机性上下波动。所以顶级的东西并不重要。但是,如果您没有意识到这一点,并且天真地实现了所有添加到值的内容,而不是从零开始并从那里波动,您将暴露隐藏的工件。

米勒的笔记是正确的,但缺陷通常隐藏在噪音中。此实现显示了这些问题。这正常。并且可以通过几种不同的方式进行修复。这就是为什么在我扩展该算法以消除所有内存限制和大小限制并使其无限和确定性1之后,我仍然放弃这里的核心思想(将其扩展到 3d 并针对 GPU 进行优化的问题)的原因之一也发挥了作用。2

钻石平方文物

于 2016-05-05T01:34:13.183 回答
0

您可以使用 2-D中值滤波器去除极端值,而不是仅使用平均值进行平滑处理。它实现起来很简单,并且通常会产生具有大量噪声的所需效果。

于 2016-05-05T01:58:40.927 回答