中点位移算法


14

MDPMDP

在花了几个小时试图找出问题之后,这个问题主要是出于绝望

如果您将视线移到上面的图片,您应该会看到我的中点位移算法算法正在(某种程度上)成功运行;产生一些连贯的噪声模式。

但是,它在图像上留下了黑色的虚线网格,我不知道为什么。我可以预见这是数学上的问题,但是我看不到它。也没有在任何在线资源中指出这是一个可能的问题;因此,对解决此错误的任何帮助将不胜感激。

unsigned char** mdp(unsigned char** base, unsigned base_n, unsigned char r) {
    size_t n = (2 * base_n) - 1;

    unsigned char** map = new unsigned char*[n];
    for (unsigned i = 0; i < n; ++i) map[i] = new unsigned char[n];

    // Resize
    // 1 0 1
    // 0 0 0
    // 1 0 1
    for (size_t i = 0; i < n; i += 2) {
        for (size_t j = !(i % 2 == 0); j < n; j += 2) {
            map[i][j] = base[i / 2][j / 2];
        }
    }

    // Diamond algorithm
    // 0 0 0
    // 0 X 0
    // 0 0 0
    for (size_t i = 1; i < n; i += 2) {
        for (size_t j = 1; j < n; j += 2) {
            unsigned char& map_ij = map[i][j];

            unsigned char a = map[i - 1][j - 1];
            unsigned char b = map[i - 1][j + 1];
            unsigned char c = map[i + 1][j - 1];
            unsigned char d = map[i + 1][j + 1];
            map_ij = (a + b + c + d) / 4;

            unsigned char rv = std::rand() % r;
            if (map_ij + r < 255) map_ij += rv; // EDIT: <-- thanks! the bug! `map_ij + rv`, not `r`
            else map_ij = 255;
        }
    }

    // Square algorithm
    // 0 1 0
    // 1 0 1
    // 0 1 0
    for (size_t i = 0; i < n; ++i) {
        for (size_t j = (i % 2 == 0); j < n; j += 2) {
            unsigned char& map_ij = map[i][j];

            // get surrounding values
            unsigned char a = 0, b = a, c = a, d = a;
            if (i != 0) a = map[i - 1][j];
            if (j != 0) b = map[i][j - 1];
            if (j + 1 != n) c = map[i][j + 1];
            if (i + 1 != n) d = map[i + 1][j];

            // average calculation
            if (i == 0) map_ij = (b + c + d) / 3;
            else if (j == 0) map_ij = (a + c + d) / 3;
            else if (j + 1 == n) map_ij = (a + b + d) / 3;
            else if (i + 1 == n) map_ij = (a + b + c) / 3;
            else map_ij = (a + b + c + d) / 4;

            unsigned char rv = std::rand() % r;
            if (map_ij + r < 255) map_ij += rv;
            else map_ij = 255;
        }

    }

    return map;
}

如果您除了http://www.gameprogrammer.com/fractal.htmlhttp://www.lighthouse3d.com/opengl/terrain/index.php?mpd2以外的其他技巧或资源,都可以用于基于分形的地形生成,那么我会感谢他们的评论。

编辑:

MDP

按照Fabians的建议(ty),这是新图像,但是它仍然存在一些奇怪的怪癖,您应该可以立即看到它们(到处都是小“酒窝”)。

是什么导致这种奇怪的行为?更新的源代码:http : //www.pastie.org/1924223

编辑:

非常感谢Fabian找到边界检查错误,对于那些感兴趣的人,这里是512x512 png的当前解决方案。和当前的源代码(由Fabian修改)MDP

编辑(多年后): Python版本https://gist.github.com/dcousens/5573724#file-mdp-py


在图片中,每个点看起来都在相同的高度。拐角也一样高吗?
deft_code 2011年

1
物有所值,您的图像看起来非常漂亮。:)
ChrisE

scrand():我不太确定我是否理解—是否应该在间隔(-r / 2,r / 2]上返回一个有符号的字符?相邻的区域似乎突然发黑,然后又爬回白色。总的来说,它看起来也像是尖锐的条纹,再次向我暗示您可能正在溢出。更高的精度(例如整数),然后将值限制在[0,256]或[-128,127]范围内?
ChrisE 2011年

问题在下面得以解决,这是因为我必须检查随机值的范围,而不是其实际值。scrand()是一个临时的“噪声”函数,理想情况下返回[-128,127]
减速

啊,酷!很高兴听到它现在正在工作。
克里斯(ChrisE)2011年

Answers:


12

该算法以递归方式添加一个值,但该值可以为正数或负数(通常为+ -1 /(2 ^ octave))

如果从零开始并且仅添加正值,则只能向上移动,这就是为什么看到顶点被拉低的原因。

尝试从127开始而不是四个角为零,还尝试使用带符号的字符(然后检查顶部和底部的边界)

编辑

因此,需要在主(64 >> i)中进行另外两项更改才能在每个八度音程处获得一半效果,还需要更改输出函数(将final [] [] tp映射到imgdta []的输出函数)需要放入

imgdta [(i * n)+ j] = 128 + final [i] [j];

而不是if else块。

另一件事,我不确定为什么,但是如果您完全取消检查,边界检查就会失败(第38和65行),您也会注意到一些新的黑色斑点,所以我认为您可能需要提升为更大的类型在进行边界检查之前,请检查您是否希望使用“ 64 / i”获得更嘈杂的图像。

另一个编辑

刚发现它是什么,您正在边界检查中与“ r”而不是“ rv”进行比较。这是固定代码:http : //pastie.org/1927076


这绝对是更好的解决方法,但是到目前为止还没有雪茄,看来我的图像仍然有些“怪癖”,我更新了原始帖子。
deceleratedcaviar

不确定,但第93行看起来不正确,64 / i可能需要为64 >> i(因为每个八度音阶的影响是您的一半)
理查德·法比安

啊!非常感谢,我简直不敢相信,我知道第二个问题会很愚蠢。很喜欢您的临时TGA代码,对不起,我应该为您省去麻烦,并放好表头。
deceleratedcaviar

3

跳出两件事:

  1. 您是否有令人信服的理由进行定点操作?本身没有什么问题,并且有很多使用它的理由(最显着的要求是内存,如果您打算升级到HUGE map),但是我肯定会从算法的浮点版本开始在工作后将其转换为定点;如果没有别的话,那应该消除一个可能的错误源(特别是,我怀疑您的钳位可能会导致问题,以及何时添加/减去rv的条件)。
  2. 虽然很难从我看到的代码中看出来,但似乎您的随机高度位移并没有随水平缩放,并且与(1)中的问题相结合可能会导致某些问题-您不应该在每个级别上的移动量相同。

哦,还有一件非算法的事情:我强烈建议不要在mdp()函数中进行分配;传入两个不同的已分配数组,并进行“就地”迭代,从一个到另一个。如果没有其他问题,这将使您在进行图层时来回乒乓球,而不必每次都分配新的数组。


有一些好处,显然我只是想使算法正确,实现远非理想,这时我什至没有清理内存:P。
deceleratedcaviar

在这一点上,通过的缩放比例为64 / i,显然我稍后会进行更改,但这并不能真正解释当前遇到的酒窝效应。:S
deceleratedcaviar

0

除了上述内容,您当前还没有删除要分配的内存。为了解决这个问题,请将第104行更改为:

for (unsigned i = 1; i < 6; ++i) final = mdp(final, n, 64 / i);

for (unsigned i = 1; i < 6; ++i) {
  signed char** new_final = mdp(final, n, 64 / i);
  for (unsigned i = 0; i < n; ++i)
    delete[] final[i];
  delete[] final;
  final = new_final;
}

并将其写出到tga文件后添加:

for (unsigned i = 0; i < n; ++i)
  delete[] final[i];
delete[] final;

我非常了解如何清理内存,但是看到这只是一个算法原型,并且将其重写为使用向量,所以我只是想确保它是正确的。
deceleratedcaviar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.