YASUHIRO
チームラボ風の3D空間をThree.jsで作る!実装からパフォーマンス改善まで
Frontend

チームラボ風の3D空間をThree.jsで作る!実装からパフォーマンス改善まで

チームラボが作り出すような、植物に囲まれた没入感のある空間って素敵ですよね!せっかくなら新しい技術に触れて表現したいと思い、Three.jsを使ってブラウザ上で動く3D空間を作成しました。

1. 開発工程:観察と基本のセットアップ

  1. 1実際に植物園に行き、インスピレーションを得るための写真撮影
  2. 2好きな花を20種、草を8種類ピックアップし、透過画像化
  3. 3Three.jsを用いてシーン、カメラ、レンダラーを初期化

まずは空間のベースとなるセットアップを行います。

import * as THREE from 'three';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
    75, // 視野角 (FOV)
    window.innerWidth / window.innerHeight, // アスペクト比
    0.1, // 近距離クリップ
    1000 // 遠距離クリップ
);

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

camera.position.z = 10; // カメラを遠ざける位置

2. 空間の構築とユーザーインタラクション

上下左右を植物で囲むために、スプライト(2D画像)をランダムな位置に配置していきます。アーチ型の天井を作るために、X座標に対してsin関数を使って高さを調整し、画像に傾きをつける工夫をしました。

3. ぶつかった壁:パフォーマンスの悪化

開発を進めると、致命的な問題が発生しました。最初の画像読み込みに時間がかかりすぎる上、描写した画像が配列に残り続けるため、時間が経つごとに画面が重くなってしまったのです。PageSpeed Insightsのスコアも真っ赤でした。

画像の重さ
配列の肥大化
レンダリング遅延
UXの低下

4. 解決策:高速化へのアプローチ

快適な空間を取り戻すため、以下の3つのアプローチで徹底的にチューニングを行いました。

  1. 1画像の軽量化:png/jpgを次世代フォーマットの WebP に変換
  2. 2CDNの利用:画像のホスティングをDropboxから jsDelivr(CDN) に移行して配信を高速化
  3. 3動的レンダリング(カリング):カメラのZ座標を監視し、表示領域外のオブジェクトを scene.remove で削除&配列から除外
function removeObjectsOutOfRange(objectsList, zMin, zMax) {
    // インデックスのズレを防ぐため、逆順にループ処理
    for (let i = objectsList.length - 1; i >= 0; i--) {
        const object = objectsList[i];
        if (object.position.z < zMin || object.position.z > zMax) {
            scene.remove(object); // シーンから削除
            objectsList.splice(i, 1); // 配列から削除
        }
    }
}

5. 安定性の担保:ローディング画面の実装

初期ロード時の「止まっている感」をなくすため、TextureLoader を使って並列ロードし、プログレスバーを実装。さらに、フレームレート(FPS)が30以上で安定するまでメイン画面を表示しない「安定性チェッカー」を組み込みました。

Qiitaで詳細を見る