Three.js とは?

Three.js は、WebGL を活用してブラウザ上で 3D グラフィックスを手軽に扱える JavaScript ライブラリです。
WebGL を直接操作する複雑なコードを書かなくても、3D オブジェクトやパーティクル、アニメーションを直感的に作成できるため、インタラクティブなウェブコンテンツの開発で広く利用されています。

Three.js の描画処理は内部で最適化されており、通常はブラウザ上でも十分なパフォーマンスを発揮します。
しかし、高解像度の 3D モデルやリアルタイムライティングを多用するシーンでは、フレームレートが低下してサイト全体の操作感が損なわれることがあります。
本記事では、こうしたパフォーマンス低下に対処するための具体的な最適化テクニックを紹介します。

Three.js の描画パフォーマンスを改善する方法

ここからは、Three.js を使った描画のパフォーマンスを改善するための実践的なアプローチをいくつか紹介します。
プロジェクトの状況に応じて、効果の高い手法から順に試してみてください。

レンダリング解像度の動的調整

最も効果的な最適化の一つが、レンダリング解像度の動的な調整です。
解像度を下げると描画負荷は大幅に軽減されますが、当然ながら画面の鮮明さは低下します。そこで、FPS(フレームレート)を監視して、パフォーマンスが低下したときだけ一時的に解像度を下げ、安定したら元に戻す仕組みを導入するのがおすすめです。

サンプルコード

const targetFps = 60;
let dynamicScale = 1;
const performanceMonitor = () => {
	const fps = getCurrentFps(); // フレームレートを測定する関数を実装
	if (fps < targetFps) {
		dynamicScale = Math.max(0.5, dynamicScale - 0.1);
	}
	else if (fps > targetFps + 10) {
		dynamicScale = Math.min(1, dynamicScale + 0.1);
	}
	renderer.setSize(window.innerWidth * dynamicScale, window.innerHeight * dynamicScale);
	effectComposers.forEach(composer => composer.setSize(window.innerWidth * dynamicScale, window.innerHeight * dynamicScale));
};
setInterval(performanceMonitor, 500); // 定期的に監視

ピクセル比の調整

高解像度ディスプレイ(Retina ディスプレイなど)では、デバイスのピクセル比に合わせてレンダリングが行われるため、描画コストが大きくなります。
setPixelRatio に固定値 1 を渡すことで、物理ピクセル数に関係なく標準解像度でレンダリングされるため、負荷を軽減できます。見た目の差はわずかなので、パフォーマンスを優先したい場合に有効です。

// 一般的な処理
this.renderer.setPixelRatio(window.devicePixelRatio);

// 少し軽量
this.renderer.setPixelRatio(1);

不要なオブジェクトの削除

シーン内に残り続ける不要なオブジェクトは、描画負荷だけでなくメモリの浪費にもつながります。
使い終わったメッシュのジオメトリやマテリアルは、dispose() メソッドで明示的に破棄しましょう。Three.js はガベージコレクションに頼らず、手動でリソースを解放する設計になっているため、この処理は非常に重要です。

this.scene.traverse(object => {
    if (object.isMesh && object.geometry) {
        object.geometry.dispose();
    }
    if (object.material) {
        if (Array.isArray(object.material)) {
            object.material.forEach(mat => mat.dispose());
        } else {
            object.material.dispose();
        }
    }
});

シーン切り替え時のリソース破棄

シーンの切り替えやページ遷移を行う場合、前のシーンで使用していたリソースが正しく破棄されていないと、メモリリークの原因になります。
レンダラーの破棄やコンテキストの強制解放、全オブジェクトの削除を確実に行いましょう。

サンプルコード

this.renderer.dispose();
this.renderer.forceContextLoss();
this.scene.children.slice().forEach(child => this.scene.remove(child)); // 全オブジェクト削除

まとめ

Three.js で快適な 3D 体験を提供するには、レンダリング解像度の動的調整、ピクセル比の最適化、不要オブジェクトの破棄、シーン切り替え時のリソース管理といった最適化が欠かせません。
これらのテクニックを組み合わせることで、描画パフォーマンスを大幅に向上させ、幅広いデバイスで滑らかに動作する 3D コンテンツを実現できるはずです。
パフォーマンスの問題に直面した際は、まずブラウザの開発者ツールで FPS やメモリ使用量を確認し、ボトルネックを特定したうえで適切な手法を適用してみてください。