three.jsでレインボーロードを走ってみた


作ったもの

See the Pen rainbowroad run by cahid (@cahid0814) on CodePen.

事の発端

three.jsを触っている時に「道路を走っている描写作れそう!レインボーロード作れるじゃん!」
と思いついたので勉強がてら作ってみることに。

簡単な解説

それらしく見えれば良いなーくらいで作ってますので作りは雑です。

道路

createRainbowRoad(15.5);
createRainbowRoad(-15.5);
createRainbowRoad(46.5);
createRainbowRoad(-46.5);
function createRainbowRoad(xPosition) {
    let panelGeo = new THREE.PlaneGeometry(30,30,0);
    let panelDistance = 800;
    let group = new THREE.Group();
    let k = 0;
    let colorArray = [
        0xf80000,0xb878f8,0x3058f8,0x00e0a8,0x00f800,0xf8f800,0xf87800
    ];
    for (let i = 0; i < 150; i++, k++) {
      let panelMate = new THREE.MeshBasicMaterial( { color: colorArray[k],specular: 0xffffff, side: THREE.BackSide } );
      let panelMesh = new THREE.Mesh( panelGeo, panelMate );
      let radian = (i / 150) * Math.PI * 2;
      panelMesh.position.set(0, panelDistance * Math.cos(radian), panelDistance * Math.sin(radian));
      panelMesh.lookAt(new THREE.Vector3(0, 0, 0));
      if(k === 6) { k = 0; }
      group.add( panelMesh );
    }
    group.position.x = xPosition;
    scene.add(group);
}

パネルを虹色順に色を指定し、面を原点に向けて円状に量産。
マテリアルの設定をbacksideにして、片面だけ見せる事で地平線に向けて走っているように。

その後円状になったパネルを左右にずらして4つ作成。

星空

createStarField();
function createStarField() {
    let starGeo = new THREE.Geometry();
    for (let i = 0; i < 50000; i++) {
        starGeo.vertices.push(
            new THREE.Vector3(
                3000 * (Math.random() - 0.5),
                3000 * (Math.random() - 0.5),
                3000 * (Math.random() - 0.5)
            )
        );
    }
    let starMate = new THREE.PointsMaterial({
        size: 2,
        color: 0xddddbb
    });
    let starMesh = new THREE.Points(starGeo, starMate);
    scene.add(starMesh);
}

星空っぽく見えるようにポイントを量産して、ランダムに配置。

カメラの動き

run();
function run() {
    runSpeed += 0.2;
    let radian = (runSpeed * Math.PI) / 180;
    camera.position.y = 830 * Math.sin(radian);
    camera.position.z = 830 * Math.cos(radian);
    camera.position.x = 30 * Math.sin(radian * 8);
    camera.rotation.x = 1.2 - (runSpeed * 0.017453286);
    requestAnimationFrame(run);
    renderer.render(scene, camera);
}

カメラを道路から少し離れた箇所から円状に動かし、円の形に沿わせるようにカメラの向きを調整。
走ってる感を出すためにカメラの位置を左右に揺らす。

作った感想

three.jsは単純なものなら簡単に作れて楽しい反面、
ちゃんとやろうとすると数学的な知識や計算、空間把握が求められて難しい・・・

普段はhtmlとcssばかり書いているので、少しずつ出来ること増やしていこうと思います。

FORK Advent Calendar 2019
12日目 サーバレスの時代だけどハードウェアの話 @momoken
14日目 @dashimakitamago さんお願いします。