【Three.js】彗星みたいなものを作る

JavaScript,Three.js

キレイだわぁ。

はじめに

前回作ったパーティクルに動きをつけて、粒子をまき散らしながら移動する彗星のようなものを作っていきたいと思います。

レール(彗星の通り道)を作る関数

//*************************************************************
// 曲線を作る(彗星の通り道になる)
//*************************************************************
function createCurve() {
  const curve = new THREE.CatmullRomCurve3([
    new THREE.Vector3(10, 30, 250),
    new THREE.Vector3(50, 0, 200),
    new THREE.Vector3(0, 10, 150),
    new THREE.Vector3(10, 10, 100),
    new THREE.Vector3(20, 20, 50),
    new THREE.Vector3(0, 0, 0)
  ]);
  const points = curve.getPoints(800);
  return points;
}

これが彗星の通り道になります。CatmullRomCurve3クラスのコンストラクタに任意の座標を好きなだけ入れてあげると、その座標を通るイイ感じの曲線を作ってくれます。すごいね。

getPointsメソッドは、その曲線を801個(引数に渡した数+1)に分割して、その座標を返してくれます。彗星はその座標上を移動していくことになります。

キラキラクラスを作る

これがひとつひとつの粒子になります。

//*************************************************************
// キラキラクラス
//*************************************************************
class KiraKira extends THREE.Sprite {
  constructor(mat, pos, life, speed, rad) {
    super(mat);
    this.scale.set(0.5, 0.5, 0.5);
    this.startPos = pos;
    this.startLife = life;  
    this.position.copy(pos);
    this.life = life;
    this.speed = speed;
    this.rad = rad;
  }

  update() {
    // パーリンノイズでイイ感じにまき散らす
    const time = Date.now() / 20000;
    const r = noise.perlin2(this.speed / 1, time);
    this.position.x += Math.cos(this.rad) / 8 * r;
    this.position.y += r / 10 + this.speed;
    this.position.z += Math.sin(this.rad) / 8 * r;

    // だんだん透明にする
    this.material.opacity -= (1 / this.startLife);
    
    this.life -= 1;
    
    if (this.life <= 0) {
      this.position.copy(this.startPos);
      this.life = this.startLife;
      this.material.opacity = 1;
    }
  }
}

前回とほとんど変わっていません。ただ、粒子をふわーっと広がる感じにしたいのでパーリンノイズを使いました。後から思ったんですけど、パーリンノイズじゃなくて普通のランダムでも良かったかも。カッコつけようとしていたのかもしれません。

このまき散らせ方なんですけど、あまり良くないんですよね。x-z平面上に広がるので、タイミングによっては平べったくなってしまうんです。もっと良い方法探してみます。

キラキラマザークラスを作る

これが本日のファインプレー。他の追随を許さない、この圧倒的ネーミングセンスよ。キラキラを生み出す物体、キラキラマザー。

散々「彗星」って言っておきながら、CometじゃなくてKirakiraMother

//*************************************************************
// キラキラマザークラス
//*************************************************************
class KirakiraMother extends THREE.Object3D {

  constructor(curve) {
    super();
    this.curve = curve;
    this.curvePos = 0;
    this.position.copy(this.curve[this.curvePos]);
    this.kirakiraCounter = 0;
  }
  
  update() {
    if (this.curvePos < this.curve.length - 1) {
      this.curvePos += 1;
      this.position.copy(this.curve[this.curvePos]);
      this.createKirakira();
    }
  }

  createKirakira() {
    // キラキラは1000個ぐらいしか作れないようにする
    if (this.kirakiraCounter <= 1001) {

      // 一度に作るキラキラの数は10
      for (let i = 0; i < 10; i++) {
        
        const mat = new THREE.SpriteMaterial({map: particle});
        const vec = this.position;
        const life = Math.floor(Math.random() * (200 - 20)) + 20;
        const speed = Math.random() * (0.05 - 0.01) + 0.01;
        const rad = degToRad(Math.floor(Math.random() * 359));

        const kirakira = new KiraKira(mat, vec, life, speed, rad);

        scene.add(kirakira);
        kiras.push(kirakira);

        // キラキラを1個作ったらカウントアップ
        this.kirakiraCounter += 1;
      }
    }
  }
}

updateメソッドが呼ばれる度に、レール上の次の座標へ移動します。そして移動する度にキラキラを10個まき散らします。

lifeとかspeedの値を少し変えるだけでもガラっと印象が変わりますね。いじくりだすとキリが無いので注意が必要です。

完成したもの

いいんじゃないでしょうか。

あとがき

楽しいです。動くものって良いですよね。

キラキラの広がり方にもう少しこだわってみようかなぁと思います。常に進行方向の逆側にぶわーっと広がるようにしたい。ありがとうございました。

おしゃれ度

★★★☆☆

Posted by ナカタ