菱形方法算法固定大小

时间:2016-07-06 09:36:59

标签: javascript algorithm performance

我正在试图找到一种方法来为:

设定固定比例

https://en.wikipedia.org/wiki/Diamond-square_algorithm

我发现该算法需要2(+1)大小的数据。

我遇到的问题是,无论分辨率如何,我都希望生成相同的高度图。因此,如果我的分辨率为512,它将与256分辨率相同,但细节较少。我只是无法弄清楚如何做到这一点。

我最初的想法是始终在某个维度创建高度图,例如我想要的1024和下采样到res。问题是我希望高分辨率相当高(比如4096),这会严重降低低分辨率下的性能,因为我们必须以尽可能高的分辨率运行算法。

目前这个算法在javascript中这里是一个片段:

function Advanced() {
    var adv = {},
    res, max, heightmap, roughness;

    adv.heightmap = function() {
        // heightmap has one extra pixel this is ot remove it.
        var hm = create2DArray(res-1, res-1);
        for(var x = 0;x< res-1;x++) {
            for(var y = 0;y< res-1;y++) {
                hm[x][y] = heightmap[x][y];
            }
        }
        return hm;
    }

    adv.get = function(x,y) {
        if (x < 0 || x > max || y < 0 || y > max) return -1;
        return heightmap[x][y];
    }

    adv.set = function(x,y,val) {
        if(val < 0) {
            val = 0;
        }

        heightmap[x][y] = val;

    }

    adv.divide = function(size) {
        var x, y, half = size / 2;
        var scale = roughness * size;
        if (half < 1) return;

        for (y = half; y < max; y += size) {
            for (x = half; x < max; x += size) {
                adv.square(x, y, half, Math.random() * scale * 2 - scale);
            }
        }
        for (y = 0; y <= max; y += half) {
            for (x = (y + half) % size; x <= max; x += size) {
                adv.diamond(x, y, half, Math.random() * scale * 2 - scale);
            }
        }
        adv.divide(size / 2);
    }

    adv.average = function(values) {
        var valid = values.filter(function(val) {
            return val !== -1;
        });
        var total = valid.reduce(function(sum, val) {
            return sum + val;
        }, 0);
        return total / valid.length;
    }

    adv.square = function(x, y, size, offset) {
        var ave = adv.average([
            adv.get(x - size, y - size), // upper left
            adv.get(x + size, y - size), // upper right
            adv.get(x + size, y + size), // lower right
            adv.get(x - size, y + size) // lower left
        ]);
        adv.set(x, y, ave + offset);
    }

    adv.diamond = function(x, y, size, offset) {

        var ave = adv.average([
            adv.get(x, y - size), // top
            adv.get(x + size, y), // right
            adv.get(x, y + size), // bottom
            adv.get(x - size, y) // left
        ]);

        adv.set(x, y, Math.abs(ave + offset));
    }

    adv.generate = function(properties, resolution) {
        Math.seedrandom(properties.seed);

        res = resolution + 1;
        max = res - 1;
        heightmap = create2DArray(res, res);

        roughness = properties.roughness;

        adv.set(0, 0, max);
        adv.set(max, 0, max / 2);
        adv.set(max, max, 0);
        adv.set(0, max, max / 2);

        adv.divide(max);
    }

    function create2DArray(d1, d2) {
        var x = new Array(d1),
        i = 0,
        j = 0;

        for (i = 0; i < d1; i += 1) {
            x[i] = new Array(d2);
        }

        for (i=0; i < d1; i += 1) {
            for (j = 0; j < d2; j += 1) {
                x[i][j] = 0;
            }
        }

        return x;
    }

    return adv;
}

以前有人这么做过吗?

2 个答案:

答案 0 :(得分:0)

我不确定我是否理解你的问题,但如果可以,我会提供进一步的澄清。

您已经描述了一种情况,您希望将分辨率为256的菱形方块高度图用于512的大小而不进行缩放。我将通过一个使用2x2高度图到#34;尺寸&#34;的示例。 4x4。

菱形方形高度图实际上是一组顶点而不是切片或正方形,因此大小为2x2的高度图实际上是一组3x3顶点,如下所示:

enter image description here

你可以使用角落的高度来渲染它,或者你可以通过取四个周围点的平均值将它变成一组2x2的正方形 - 实际上这只是&#34; square&#34;没有位移步骤的算法步骤。

enter image description here

所以在这种情况下,&#34;身高&#34;左上方的平均值是(0,0),(0,1),(1,1)和(1,0)点的平均值。

如果你想以更高的分辨率绘制它,你可以将每个方块分成一组较小的4个方块,根据它与每个点的接近程度来调整平均值。

enter image description here

所以现在左上角的正方形的值将是它周围的4个子点的样本或者相对于它周围的点的位置样本。但实际上这只是再次应用的菱形方形算法,没有任何位移(没有粗糙度),因此您可以再次应用算法并转到更大的尺寸。

您已经说过要达到您想要的尺寸对于处理器来说太大了,所以您可能希望采用较小尺寸的采样方法。一种有效的方法是将高度图呈现为纹理和样本以及所需的位置。

答案 1 :(得分:0)

正确实施钻石&amp; square 算法具有相同的第一N步,无论地图分辨率如何,因此唯一能确保相同外观的是使用一些指定的种子用于伪随机生成器。

要完成这项工作,您需要:

  1. 设定种子
  2. 分配数组并设置基本随机性幅度
  3. 金刚石
  4. 较低的基本随机性幅度
  5. 循环#3 ,直到达到最低分辨率
  6. 如果你没有正确降低随机性幅度,那么较低的递归/迭代层可以覆盖上层结果的形状,使其不起作用。

    这里看看我是如何做的,只需添加种子:

    见行:

    r=(r*220)>>8; if (r<2) r=2;
    

    r是基本随机性幅度。您降低它的方式将决定结果的形状,因为您可以看到我没有将它除以2而是乘以220/256,因此较低的分辨率具有更大的凸起,这符合我的需要。

    现在,如果你想使用非2^x+1分辨率,那么选择更接近更大的分辨率,然后按比例缩小以使其也适用于它们。应该仔细缩小以保留前几个递归/迭代步骤的主要网格点或使用双立方...

    如果您有兴趣,请查看基于链接的更新数据生成器: