【问题标题】:Diamond Square Algorithm fixed size钻石平方算法固定大小
【发布时间】:2016-11-08 07:33:42
【问题描述】:

我正在尝试找到一种方法来为以下内容设置固定比例:

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

我看到该算法需要数组大小的 2 (+1) 次方。

我遇到的问题是,无论分辨率如何,我都希望生成相同的高度图。因此,如果我的分辨率为 512,它看起来与分辨率 256 相同,但细节更少。我只是不知道如何做到这一点。

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

目前算法是在javascript中,这里是一个sn-p:

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

以前有人做过吗?

【问题讨论】:

  • 看起来不像,然后大声笑!

标签: javascript algorithm performance


【解决方案1】:

不太确定我是否理解您的问题,但如果可以,我会提供进一步的说明。

您描述了一种情况,您希望在不放大 512 的情况下使用分辨率为 256 的菱形正方形高度图。我将通过一个使用 2x2 高度图到 4x4 的“大小”的示例。

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

您可以使用角的高度来渲染它,也可以通过取周围四个点的平均值将其变成 2x2 的正方形集 - 实际上这只是算法的“正方形”步骤,没有位移步。

所以在这种情况下,左上角方块的“高度”将是 (0, 0)、(0, 1)、(1, 1) 和 (1, 0) 点的平均值。

如果您想以更高的分辨率绘制此图,您可以将每个方格分成一组更小的 4 个方格,并根据与每个点的接近程度调整平均值。

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

您曾说过,达到您希望达到的尺寸对于处理器来说太过分了,因此您可能希望在较小的尺寸上采用这种采样方法。一种有效的方法是将高度图渲染到纹理并从中采样以及所需的位置。

【讨论】:

    【解决方案2】:

    正确实施的 diamond & square 算法具有相同的第一个N 步骤,而与地图分辨率无关,因此唯一能确保外观相同的方法是为伪随机生成器使用一些指定的种子。 p>

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

    1. 播种
    2. 分配数组并设置基本随机性幅度
    3. 钻石
    4. 方形
    5. 较低的基础随机性幅度
    6. 循环#3直到达到最低分辨率

    如果您没有正确降低随机性大小,则较低的递归/迭代层可能会覆盖上层结果的形状,从而使其不起作用。

    这里看看我是怎么做的,只需添加种子:

    看线:

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

    r 是基本随机性大小。您降低它的方式将决定结果的形状,如您所见,我不是将其除以二,而是乘以 220/256,因此较低的分辨率具有更大的凹凸,适合我的需求。

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

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

    【讨论】:

      猜你喜欢
      • 2014-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多