在Value Noise算法实现中,每隔一行修复一次

时间:2014-05-17 06:25:59

标签: javascript algorithm random noise procedural-generation

下面是我的Value Noise实现,我正在使用它来生成地形。当地形的长度(Y尺寸)长于其宽度(X尺寸)时,它会产生奇怪的瑕疵,但不会产生。

我一直盯着这几个小时。知道是什么导致了这个吗?

(来自demo的屏幕截图。您可以在浏览器控制台中查看代码并立即通过将THREE.Terrain.Value = ValueNoise; rebuild();放在下面的代码后立即查看结果。)

1:1宽高比:

1:1 Aspect Ratio

1:1.1宽高比:

1:1.1 Aspect Ratio

/**
 * Generate a heightmap using white noise.
 *
 * @param {Vector3[]} g The terrain vertices.
 * @param {Object} options Settings
 * @param {Number} scale The resolution of the resulting heightmap.
 * @param {Number} segments The width of the target heightmap.
 * @param {Number} range The altitude of the noise.
 * @param {Number[]} data The target heightmap.
 */
function WhiteNoise(g, options, scale, segments, range, data) {
    if (scale > segments) return;
    var i = 0,
        j = 0,
        xl = segments,
        yl = segments,
        inc = Math.floor(segments / scale),
        k;
    // Walk over the target. For a target of size W and a resolution of N,
    // set every W/N points (in both directions).
    for (i = 0; i <= xl; i += inc) {
        for (j = 0; j <= yl; j += inc) {
            k = j * xl + i;
            data[k] = Math.random() * range;
            /* c b *
             * l t */
            var t = data[k],
                l = data[ j      * xl + (i-inc)] || t, // left
                b = data[(j-inc) * xl +  i     ] || t, // bottom
                c = data[(j-inc) * xl + (i-inc)] || t; // corner
            // Interpolate between adjacent points to set the height of
            // higher-resolution target data.
            for (var lastX = i-inc, x = lastX; x < i; x++) {
                for (var lastY = j-inc, y = lastY; y < j; y++) {
                    if (x === lastX && y === lastY) continue;
                    var px = ((x-lastX) / inc),
                        py = ((y-lastY) / inc),
                        r1 = px * b + (1-px) * c,
                        r2 = px * t + (1-px) * l;
                    data[y * xl + x] = py * r2 + (1-py) * r1;
                }
            }
        }
    }
    // Assign the temporary data back to the actual terrain heightmap.
    // Accumulate additively across multiple calls to WhiteNoise.
    for (i = 0, xl = options.xSegments + 1; i < xl; i++) {
        for (j = 0, yl = options.ySegments + 1; j < yl; j++) {
            k = j * xl + i;
            g[k].z += data[k] || 0;
        }
    }
}

/**
 * Generate random terrain using value noise.
 *
 * The basic approach of value noise is to generate white noise at a
 * smaller octave than the target and then interpolate to get a higher-
 * resolution result. This is then repeated at different resolutions.
 *
 * @param {Vector3[]} g The terrain vertices.
 * @param {Object} options Settings
 */
ValueNoise = function(g, options) {
    // Set the segment length to the smallest power of 2 that is greater
    // than the number of vertices in either dimension of the plane
    var segments = Math.max(options.xSegments, options.ySegments) + 1, n;
    for (n = 1; Math.pow(2, n) < segments; n++) {}
    segments = Math.pow(2, n);

    // Store the array of white noise outside of the WhiteNoise function to
    // avoid allocating a bunch of unnecessary arrays; we can just
    // overwrite old data each time WhiteNoise() is called.
    var data = new Array(segments*(segments+1));

    // Layer white noise at different resolutions.
    var range = options.maxHeight - options.minHeight;
    for (var i = 2; i < 7; i++) {
        WhiteNoise(g, options, Math.pow(2, i), segments, range * Math.pow(2, 2.4-i*1.2), data);
    }

    // Clamp and stretch the results
    THREE.Terrain.Clamp(g, {
        maxHeight: options.maxHeight,
        minHeight: options.minHeight,
        stretch: true,
    });
};

1 个答案:

答案 0 :(得分:2)

当你指定临时data字段的高度变化时,你真的有两个不同的索引,因为你有两个不同的地图大小:原始地图和临时地图膨胀到下一个2的幂。所以:

for (i = 0, xl = options.xSegments + 1; i < xl; i++) {
    for (j = 0, yl = options.ySegments + 1; j < yl; j++) {
        var kg = j * xl + i;
        var kd = j * segments + i;

        g[kg] += data[kd];
    }
}

我还认为您的data索引中可能存在一个错误的错误。 data的大小应为(segments + 1) * (segments + 1),因为您需要两个维度中的外部单元格,而xlyl应为segments + 1