【Three.js】パーリンノイズでカーテンを作る

JavaScript,Three.js

オーロラ

はじめに

線を描いてオシャレなものを作りたい。というワケで手始めにカーテンを作ってみようと思います。

作るにあたってこちらの記事を参考にさせていただきました。参考というか、ほぼそのまま。とても分かりやすかったです。ありがとうございます。

線を1本だけ描いてみる

const points = [];
// 始点
points.push(new THREE.Vector3(0, 10, 0));
// 終点
points.push(new THREE.Vector3(10, 0, 0));

const geometry = new THREE.BufferGeometry().setFromPoints(points);
const material = new THREE.LineBasicMaterial({color: 0xffff00});
const line = new THREE.Line(geometry, material);
scene.add(line);

まずは始点と終点の座標を作って配列に入れましょう。それをTHREE.BufferGeometrysetFromPoints()に渡してジオメトリを作ります。

で、ジオメトリとマテリアルをTHREE.Lineのコンストラクタに渡せば線が引けます↓。

線を動かす

始点は固定して、終点だけをZ軸のマイナス方向に動かしてみます。

// 線のアニメーション
function drawCurtain() {
  line.geometry.attributes.position.array[5] -= 0.1;
  line.geometry.attributes.position.needsUpdate = true;
}

3行目のline.geometry.attributes.position.array。コイツ配列でして、中身はこんな風になっています↓。

配列のインデックスは[0]から始まるので[5]の要素をいじってあげましょう。そうするとこんな感じで終点が遠ざかっていきます(動画)↓。

線の動かし方が分かったので、次は線をたくさん作ってランダムに動くようにしてみましょう。

パーリンノイズ

ケン・パーリンさんが作ったから「パーリンノイズ」。かっこいいですね。「パーリンノイズ」って言いたくなる。

このパーリンノイズを使うと「自然な揺らぎ」を作ることができます。煙とか炎とか地形とか。

完全なランダムにするとグチャグチャになっちゃうけど、パーリンノイズだとイイ感じになる。こんな感じです↓。

ランダムではあるんだけど、直前の値と近い値になるようです。ホント、カーテン作るために開発されたんじゃないかってぐらい、カーテン作るのに適してると思いますね。

線をたくさん描く

const lines = [];

for (let i = 0; i < 500; i++) {
  const points = [];
  points.push(new THREE.Vector3((i - 250) / 10, 50, 0));
  points.push(new THREE.Vector3((i - 250) / 10, 0, 0));
  
  const geometry = new THREE.BufferGeometry().setFromPoints(points);
  const material = new THREE.LineBasicMaterial({color: 0xffffff});
  const line = new THREE.Line(geometry, material);
  scene.add(line);
  lines.push(line);
}

まずは、まっすぐな線を500本作って横一列にズラーっと並べます。あとで線一本一本にアニメーションをつけていくので、linesっていう名前の配列に入れておきます。こうなります↓。

ビシーッ。

パーリンノイズでアニメーション

noise.seed(Math.random());
function drawCurtain() {
  const time = Date.now() / 10000;
  for (let i = 0; i < 500; i++) {
    
    const px = i / 100;
    const py = time;

  const z = noise.perlin2(px, py) * 20;

    lines[i].geometry.attributes.position.array[5] = z
    lines[i].geometry.attributes.position.needsUpdate = true;
  }
}

パーリンノイズの使い方はとっても簡単。noise.perlin2(px, py)。引数の値が近ければ、戻り値も近くなるようです。使い方は簡単だけど、中身は何やってんのか分かりませんでした。パーリンさんに感謝。

パーリンノイズには他にもperlin3、simplex2、simplex3があります。そちらはまたの機会に…。

こんな感じになります(動画)↓。

3行目のtimeの値が大きいほどカーテンの動きが早くなります。

6行目のpxの値が大きいほど隣の値との差が大きくなり、ギザギザになります↓。

9行目でperlin2の戻り値に20を掛けていますが、これは振り幅になります。大きいほどカーテンの揺れも大きくなります↓。

1行目のnoise.seed(Math.random())ですが、これが実行される度にパーリンノイズが作ってくれるランダムな値が変わるようです。

逆に言うと、これを書いていない状態で、perlin2の引数に毎回同じ値を渡してあげると、毎回同じ結果が返ってきます。

今回はperlin2の引数に時間を渡しているので書かなくても大丈夫なんですけど、なんとなく書いておきました。

時間経過とともに変化するようなモノを作るなら、あんまり関係ないものかも知れません。

線に色をつける

noise.seed(Math.random());
function drawCurtain() {
  const time = Date.now() / 10000;
  for (let i = 0; i < 500; i++) {
    
    const px = i / 100;
    const py = time;

    const z = noise.perlin2(px, py) * 20;

    lines[i].geometry.attributes.position.array[5] = z
    lines[i].geometry.attributes.position.needsUpdate = true;

    // HSL色空間
    const h = Math.round((i / 500) * 360);
    const s = 100;
    const l = 30;
    const color = new THREE.Color(`hsl(${h},${s}%,${l}%)`);
    lines[i].material.color = color;
  }
}

HSL色空間(HLS色空間とも言うのかな?)というものがあるそうです。

Hが色相。色を360度の円で表していて、0度が赤で180度が青緑(赤の反対色)。

Sが彩度。小さいほど灰色に近づきます。

Lは輝度。0は黒。100は白。

さらっとしか調べてないので違っていたらごめんなさい。そんなワケでできたのがコレ↓。

デモサイトはこちら

オーロラですね。オーロラがこんな色してるのかは分かりませんがオーロラです。

あとがき

はい。というワケでパーリンノイズを使ってみました。ホントに便利ですね。ランダムなんだけど「自然」っていうのがスゴイ。煙とか波とかも作ってみたいなぁと思いました。今回は以上です。ありがとうございました。

おしゃれ度

★★★☆☆

Posted by ナカタ