我的 perlin 噪声函数有什么问题?

What is wrong with my perlin noise function?

所以我目前正在研究 perlin 噪声发生器,由于某种原因我得到了不正确的输出:

柏林噪声在 "grid" 中,与传统的柏林噪声不同。 这是我的代码:

var perlinNoise = {
vectors: [{x:1,y:0},{x:1,y:-1},{x:0,y:-1},{x:-1,y:-1},{x:-1,y:0},{x:-1,y:1},{x:0,y:1},{x:1,y:1}],
fade: function(t){
    return t * t * t * (t * (t * 6 - 15) + 10);
},
pointToCell: function(x, y){
    cellX = Math.floor(x);
    cellY = Math.floor(y);
    return {x:cellX, y:cellY};
},
cellToVectors: function(cellX, cellY){
    halfCell = .5;
    //I use the four intercardinal directions to label the vectors.
    //The random values are multiplied by 8 to map them to the 8 entries of the vectors array.
    NEvector = this.vectors[Math.floor(randomFromCoords(cellX + halfCell, cellY + halfCell)*8)];
    SEvector = this.vectors[Math.floor(randomFromCoords(cellX + halfCell, cellY - halfCell)*8)];
    SWvector = this.vectors[Math.floor(randomFromCoords(cellX - halfCell, cellY - halfCell)*8)];
    NWvector = this.vectors[Math.floor(randomFromCoords(cellX - halfCell, cellY + halfCell)*8)];
    return {NE: NEvector, SE: SEvector, SW: SWvector, NW: NWvector};
},
dotProduct: function(vector1, vector2){
    //Another way to calculate the dot product. This is more performance friendly than cosine calculations.
    return vector1.x * vector2.x + vector1.y * vector2.y;
},
lerp: function(value1, value2, t){
    return (1 - t) * value1 + t * value2;
},
perlinNoise: function(x, y){
    var cellCoord = this.pointToCell(x, y);

    //Get the positions of the x and y coordinants relative to the cell
    var Xoffset = this.fade(x - cellCoord.x);
    var Yoffset = this.fade(y - cellCoord.y);

    var vectors = this.cellToVectors(cellCoord.x, cellCoord.y);

    //The offset from each corner is calculated.
    //Then the dotproduct between the offset vector and the random vector is calculated.
    var NEoffset = {x: 1 - Xoffset, y: 1 - Yoffset};
    var NEdotProduct = this.dotProduct(NEoffset, vectors.NE);

    var SEoffset = {x: 1 - Xoffset, y: Yoffset};
    var SEdotProduct = this.dotProduct(SEoffset, vectors.SE);

    var SWoffset = {x: Xoffset, y: Yoffset};
    var SWdotProduct = this.dotProduct(SWoffset, vectors.SW);

    var NWoffset = {x: Xoffset, y: 1 - Yoffset};
    var NWdotProduct = this.dotProduct(NWoffset, vectors.NW);

    var Nlerp = this.lerp(NWdotProduct, NEdotProduct, Xoffset);

    var Slerp = this.lerp(SWdotProduct, SEdotProduct, Xoffset);

    var finalValue = this.lerp(Slerp, Nlerp, Yoffset);
    if(finalValue < -.5 ){
        console.log("less than -.5");
    }
    return finalValue;
},
noise: function(width, height){
    var values = [];
    for (var y = 0; y < height; ++y) {
        for (var x = 0; x < width; ++x) {
                values[x + y * width] = (this.perlinNoise(x/30,y/30)+1)/2;
        }
    }
    return values;
},
element: document.getElementById("PerlinDisplay1"),
loop: function (){},
initialize: function(){
    initCanvas("PerlinDisplay1Canvas");
    var values = this.noise(canvas.width, canvas.height);
    //maps values from 0 to 1 to grey scale pixels, already tested.
    var valuesAsPixels = values.map(x => ValueToPixel(x));
    UpdateCanvas(valuesAsPixels);
},
deinitialize: function(){}

}

函数 initCanvas、ValueToPixel 和 UpdateCanvas 有效,并且已经在其他用例中进行了测试。对于我做错了什么,我真的很感激。

编辑:根据要求,我正在添加函数 ValueToPixel 和 UpdateCanvas。

function UpdateCanvas(pixels){
    var n = 0;
    for (var y = 0; y < canvas.height; ++y) {
        for (var x = 0; x < canvas.width; ++x) {
            var index = (y * canvas.width + x) * 4;
            for(var channel = 0; channel < 4; ++channel){
                data[index + channel]  = pixels[index/4][channel];
                n++;
            }
        }
    }
    context.putImageData(imageData, 0, 0);
}

function ValueToPixel(value){
    //red, green, blue, alpha
    return [value*255, value*255, value*255, 255];
}

我想通了!我错误地计算了角落的偏移量。我错误地计算了到角落的距离的绝对值,而不是到角落的偏移量。下面是更正后的代码片段:

//The offset from each corner is calculated.
//Then the dotproduct between the offset vector and the random vector is calculated.
var NEoffset = {x: Xoffset - 1, y: Yoffset - 1};
var NEdotProduct = this.dotProduct(NEoffset, vectors.NE);

var SEoffset = {x: Xoffset - 1, y: Yoffset};
var SEdotProduct = this.dotProduct(SEoffset, vectors.SE);

var SWoffset = {x: Xoffset, y: Yoffset};
var SWdotProduct = this.dotProduct(SWoffset, vectors.SW);

var NWoffset = {x: Xoffset, y: Yoffset - 1};
var NWdotProduct = this.dotProduct(NWoffset, vectors.NW);

请注意,不是从 1 中减去偏移量,而是从偏移量中减去 1。