Vueで3Dをやるならこれ!TresJSで始める宣言的Three.jsの世界
「Vueで3D表現をやりたいけど、Three.jsのコードって命令的でVueのコンポーネント指向と合わないんだよな…」
そんな風に悩んだことはありませんか?
React界隈にはReact Three Fiber (R3F)という強力なライブラリがあり、コンポーネントベースでサクッと3Dシーンを構築できます。
「Vueにもあんなライブラリがあればいいのに…」と思っていた皆さん、朗報です。
TresJS があります!
今回は、VueエコシステムにThree.jsの魔法をもたらす「TresJS」について、公式サイトのドキュメントを交えながら、その魅力と使い方をたっぷりご紹介します。
TresJSとは?
TresJS(「トレス」と読みます。スペイン語で「3」の意味)は、Vueコンポーネントを使って宣言的にThree.jsのシーンを構築できるオープンソースライブラリです。
公式サイトでは以下のように紹介されています。
TresJS is an open-source library that provides a declarative way of using Three.js in Vue. Build your scenes using Vue components in a declarative way with all the power of Vue's reactivity.
(意訳:TresJSは、VueでThree.jsを宣言的に使用するためのオープンソースライブラリです。Vueのリアクティビティの力をフルに活用し、Vueコンポーネントを使って宣言的にシーンを構築できます。)
作者のAlvaro Saburido氏は、React Three FiberやLunchbox(Vue用の別のカスタムレンダラー)にインスパイアされ、「カスタムレンダラーを必要とせず、Three.jsのコンストラクタに基づいてVueコンポーネントを自動生成する」 というアプローチでTresJSを開発しました。
これにより、Three.jsがアップデートされても、TresJS側でのメンテナンスをほとんど必要とせずに最新機能を利用できるという大きなメリットがあります。
なぜTresJSを使うのか?
Three.jsは非常に強力な3Dライブラリですが、Vueのようなコンポーネントベースのフレームワークに慣れた開発者にとっては、学習曲線が急に感じられることがあります。
TresJSは、以下の特徴でそのギャップを埋めてくれます。
| 特徴 | 説明 |
|---|---|
| 馴染みのあるコンポーネント | 命令的なThree.jsのコードの代わりに、Vueコンポーネントを使って3Dシーンを構築できます。 |
| デフォルトでリアクティブ | Vueのリアクティビティシステムを活用して、動的な3D体験を作成できます。 |
| Composable | 一般的な3Dパターンや機能をカプセル化した強力なコンポーザブル(useLoopなど)にアクセスできます。 |
| 宣言的 | 「どのように」ステップバイステップで構築するかではなく、「何が」シーンに表示されるべきかを記述します。 |
| 開発者体験 (DX) | HMR(Hot Module Replacement)、TypeScriptサポート、Vue DevTools統合など、Vueの完全な開発者体験を得られます。 |
命令的から宣言的へ
百聞は一見に如かず。従来のThree.jsのコードとTresJSのコードを比較してみましょう。
従来のThree.js(命令的)
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
const renderer = new THREE.WebGLRenderer()
const geometry = new THREE.BoxGeometry()
const material = new THREE.MeshBasicMaterial({ color: 0x00FF00 })
const cube = new THREE.Mesh(geometry, material)
scene.add(cube)
TresJS(宣言的)
<template>
<TresCanvas>
<TresPerspectiveCamera :position="[0, 0, 5]" />
<TresMesh>
<TresBoxGeometry />
<TresMeshBasicMaterial :color="0x00FF00" />
</TresMesh>
</TresCanvas>
</template>
どうですか?Vue開発者なら、直感的に構造が理解できるのではないでしょうか。
<TresCanvas> がレンダラーやシーンのセットアップを良しなにやってくれて、その中にカメラやメッシュ(形状とマテリアル)を配置していくだけです。
TresJSの魔法:自動生成カタログ
TresJSの最も面白い仕組みの一つが、自動生成カタログ (Autogenerated Catalogue) です。
TresJS provides an autogenerated catalogue of Vue components that map directly to Three.js classes. Any class exported from the
threepackage is automatically available as a Vue component with theTresprefix.
つまり、Three.jsのクラス(例:PerspectiveCamera、Mesh、BoxGeometry)に Tres というプレフィックスをつけるだけで、そのままVueコンポーネントとして使えるんです!
-
new THREE.PerspectiveCamera()➡️<TresPerspectiveCamera /> -
new THREE.Mesh()➡️<TresMesh /> -
new THREE.BoxGeometry()➡️<TresBoxGeometry />
わざわざインポートする必要もありません。Three.jsの公式ドキュメントを見ながら、そのままTresJSのコンポーネント名に変換して使えるので、学習コストがグッと下がります。
プロパティの渡し方
Three.jsのコンストラクタ引数やプロパティは、VueのPropsとして渡すことができます。
コンストラクタ引数 (args)
<!-- Creates: new THREE.BoxGeometry(2, 2, 2) -->
<TresBoxGeometry :args="[2, 2, 2]" />
プロパティ
<TresMesh
:position="[0, 1, 0]"
:rotation="[0, Math.PI, 0]"
:scale="2"
:cast-shadow="true"
>
<!-- ... -->
</TresMesh>
強力なエコシステム
TresJSはコアライブラリだけでなく、開発をさらに加速させる周辺パッケージも充実しています。
1. Cientos
React Three Fiberにおける drei のような存在です。
OrbitControls(カメラ操作)、環境光のセットアップ、3Dモデルの読み込みヘルパーなど、よく使う機能がコンポーネントやコンポーザブルとして用意されています。
2. Post-processing
画面全体にエフェクト(ブルーム、被写界深度、グリッチなど)をかけるポストプロセッシングを、Vueコンポーネントで簡単に追加できるパッケージです。
3. Nuxtモジュール
Nuxtユーザー向けに @tresjs/nuxt が用意されています。これを導入するだけで、コンポーネントの自動インポートやクライアントサイドレンダリングの設定などをすべて自動でやってくれます。
インタラクションも簡単(ポインターイベント)
3Dオブジェクトをクリックしたり、ホバーしたりする処理も、Vueの標準的なイベントリスナーと同じ感覚で書けます。
<script setup lang="ts">
function onPointerEnter() {
console.log('Pointer entered the box!')
}
function onClick() {
console.log('Box clicked!')
}
</script>
<template>
<TresCanvas>
<TresMesh
@pointerenter="onPointerEnter"
@click="onClick"
>
<TresBoxGeometry />
<TresMeshNormalMaterial />
</TresMesh>
</TresCanvas>
</template>
裏側では @pmndrs/pointer-events が動いており、レイキャスト(光線を飛ばしてオブジェクトとの交差を判定する処理)などを自動で最適化してくれます。
アニメーションとレンダーループ
3Dシーンに動きをつけるには、毎フレームごとに処理を実行するレンダーループにアクセスする必要があります。TresJSでは useLoop コンポーザブルを使って簡単に実現できます。
<script setup lang="ts">
import { useLoop } from '@tresjs/core'
import { ref } from 'vue'
const cube = ref()
const { onBeforeRender } = useLoop()
onBeforeRender(({ delta, elapsed }) => {
if (cube.value) {
// 毎フレーム回転させる
cube.value.rotation.y += delta * 2
// 上下にフワフワ動かす
cube.value.position.y = Math.sin(elapsed * 3) * 0.5
}
})
</script>
<template>
<TresMesh ref="cube">
<TresBoxGeometry />
<TresMeshNormalMaterial />
</TresMesh>
</template>
delta(前フレームからの経過時間)や elapsed(総経過時間)が引数として渡ってくるので、フレームレートに依存しない滑らかなアニメーションを簡単に実装できます。
まとめ
TresJSは、Vueのリアクティビティとコンポーネント指向の恩恵を受けながら、Three.jsの強力な3D表現力をフルに引き出せる素晴らしいライブラリです。
「3Dは難しそう…」と敬遠していたVueエンジニアの方も、TresJSなら普段のVue開発の延長線上で楽しく3Dプログラミングを始められるはずです。
Discussion