前回の続きです。
あれから乱数について調べていたら、これを見つけました。
入力に対して一意に乱数っぽい値が決まる、疑似乱数というものらしい。
これを使えば、勾配ベクトルを予め求めておかなくても良いし、grid を意識しなくても済むことに気が付きました。
ただ、
先の疑似乱数のままだと常に結果が同じになってしまってつまらないので、変化が起こるように工夫してみました。
ということで、
疑似乱数を導入して改善してみました。
使い方は前回と同様ですが、seed() に grid を渡す必要がなくなります。
また、初期値のままで良いなら seed() を呼ばなくても構いません。
以下に、改善したソースコードを載せます。
/*!
* PerlinNoise.js ver 1.1.0 (2022-01-14)
* (c) katwat [katwat.s1005.xrea.com]
* based on https://github.com/joeiddon/perlin
* The MIT License
*/
(function(definition) {
if (typeof exports === "object") { // CommonJS
module.exports = definition();
} else if (typeof define === "function" && define.amd) { // AMD (RequireJS)
define(definition);
} else { // <script>
PerlinNoise = definition();
}
}(function() {
var randomShift = 0;
function seed() {
randomShift = 2 * Math.PI * Math.random();
}
function random(x,y) { // pseudo random -> https://qiita.com/shimacpyon/items/d15dee44a0b8b3883f76
var v = Math.sin(x * 12.9898 + y * 78.233 + randomShift) * 43758.5453123;
return v - Math.floor(v); // fraction
}
function gradient(x,y,gx,gy) {
var theta = 2 * Math.PI * random(gx,gy);
return (x - gx) * Math.cos(theta) + (y - gy) * Math.sin(theta);
}
/*function smoother(x) { // old vesion
var x2 = x * x,
x3 = x2 * x;
return -2 * x3 + 3 * x2;
}*/
function smoother(x) {
var x3 = x*x*x,
x4 = x3 * x,
x5 = x4 * x;
return 6*x5 - 15*x4 + 10*x3;
}
function lerp(x,y,a) { // linear interpolation
return x + (y - x) * a;
}
return {
seed: seed,
get: function(x,y) {
var xi = Math.floor(x),
yi = Math.floor(y),
sx = smoother(x - xi),
sy = smoother(y - yi),
tl = gradient(x,y,xi ,yi ),
tr = gradient(x,y,xi+1,yi ),
bl = gradient(x,y,xi ,yi+1),
br = gradient(x,y,xi+1,yi+1);
return lerp( lerp(tl,tr,sx), lerp(bl,br,sx), sy); // range: -1.0 to 1.0
}
};
}));
なお、
ソースコードのファイルは以下からダウンロードできます。