はじめに
VRやARのコンテンツを作ろうとして、Three.jsやWebGLの学習コストの高さに尻込みしてしまった経験はありませんか。カメラの設定、シーングラフの構築、レンダリングループの管理と覚えることが多く、立方体ひとつ表示するだけでも数十行のJavaScriptが必要になりがちです。
A-Frameは、この複雑さをHTMLタグの記述だけで解決してくれるWebフレームワークです。<a-box>や<a-sphere>のようなカスタム要素を並べるだけで3D空間が組み上がり、裏側ではThree.jsとWebXRが面倒を見てくれます。VRヘッドセットがなくても、普通のブラウザとマウスがあればその場で体験を確認できます。
説明を読むより、実際に動かした方が早いと思います。先に挙動を見たい方はこちらからどうぞ。
A-Frameとは
A-Frameは、Mozillaのエンジニアが中心となって開発しているオープンソースのWebフレームワークで、HTMLの宣言的な記述だけで3D/AR/VR体験を構築できます。内部的にはThree.jsをラップしており、WebXR APIに対応しているため、デスクトップブラウザはもちろんMeta QuestなどのVRヘッドセットやスマートフォンのARモードでもそのまま動作します。
最大の特徴は「Entity-Component-System(ECS)」というアーキテクチャを採用している点です。3Dオブジェクトは<a-entity>という空の器(エンティティ)として表現され、geometryやmaterial、animationといった「コンポーネント」を属性として追加することで見た目や振る舞いを組み立てます。<a-box>や<a-sphere>のようなプリミティブタグは、よく使う組み合わせをあらかじめ用意したショートカットにすぎません。
主な特徴
- HTMLだけで3D空間を構築できる - JavaScriptを書かなくても
<a-scene>にタグを並べるだけでVR空間が完成する - WebXR/VRヘッドセット対応 - Meta QuestやPICOなどのVRヘッドセット、スマートフォンのARモードにそのまま対応する
- Entity-Component-System採用 -
AFRAME.registerComponentで独自の振る舞いを部品として追加でき、既存のコンポーネントとも自由に組み合わせられる - Three.jsとの高い互換性 - 内部エンジンはThree.jsなので、Three.jsの知識やジオメトリ・マテリアルの資産をそのまま活かせる
- ビジュアルインスペクタ内蔵 - ブラウザ上で
Ctrl+Alt+Iを押すとシーン内のオブジェクトをGUIで直接編集できる
インストール
A-Frameはビルドツールなしでも使えます。HTMLに<script>タグを1行追加するだけで導入できます。
<script src="https://aframe.io/releases/1.8.0/aframe.min.js"></script>
npmパッケージとして導入し、バンドラー経由で使うことも可能です。
npm install aframe
import 'aframe'
A-Frameのサンプルを動かす
下のサンプルは、色を変えられる<a-box>と、回転アニメーションの速度を調整できるスライダーを組み合わせたものです。A-Frameのanimationコンポーネントに指定したproperty(ここではrotation)が、dur(ミリ秒)で指定した時間をかけてtoの値まで変化し続けます。色の変更はbox.setAttribute('color', ...)でエンティティのmaterialコンポーネントを直接書き換えることで実現しています。
要点だけを抜き出すと次のようになります。
<a-scene embedded>
<a-box id="box" position="0 1.5 -4" rotation="0 45 0" color="#4CC3D9"
animation="property: rotation; to: 0 405 0; loop: true; dur: 4000; easing: linear">
</a-box>
<a-sky color="#ECECEC"></a-sky>
</a-scene>
<script>
const box = document.querySelector('#box')
box.setAttribute('color', '#EF2D5E') // materialコンポーネントを直接書き換え
</script>
実際に動かせるものが下です。3D空間はドラッグで視点を回転できます。カラーピッカーとスライダーを操作して、A-Frameのエンティティがリアルタイムに反応する様子を確かめてみてください。
色を変えると<a-box>のmaterialコンポーネントがその場で更新され、スライダーを動かすとanimationコンポーネントのdurが再設定されて回転速度が変わります。A-Frameのコンポーネントは、HTMLの属性としてだけでなくJavaScriptからsetAttributeで自由に書き換えられることが分かります。
基本的な使い方
最もシンプルな構成は、<a-scene>の中にプリミティブタグを並べるだけです。位置はx y zの3値、色は通常のCSSカラーコードで指定します。
<!DOCTYPE html>
<html>
<head>
<script src="https://aframe.io/releases/1.8.0/aframe.min.js"></script>
</head>
<body>
<a-scene>
<a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
<a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
<a-sky color="#ECECEC"></a-sky>
</a-scene>
</body>
</html>
<a-scene>を書くだけで、カメラ・ライト・レンダラー・VR/ARへの入場ボタンまで自動的に用意されます。これがA-Frameの「設定不要で始められる」というメリットの核心です。
実践的なユースケース
カーソルクリックでオブジェクトを選択する
VR空間では、マウスの代わりに視線やコントローラーでオブジェクトを選択する場面が多くあります。A-Frameではcursorコンポーネントとraycasterコンポーネントを組み合わせることで、マウスカーソルの位置から3D空間にレイを飛ばし、当たった要素のclickイベントを拾えます。
<a-entity id="cursor" cursor="rayOrigin: mouse" raycaster="objects: .clickable"></a-entity>
<a-box class="clickable" id="obj1" position="-1.5 1 -3" color="#4CC3D9"></a-box>
<script>
document.querySelector('#obj1').addEventListener('click', () => {
console.log('boxがクリックされた')
})
</script>
以下のサンプルでは、3つの図形のいずれかをクリックすると選択中のオブジェクトが拡大表示され、画面上部のラベルにIDが表示されます。
raycaster="objects: .clickable"で監視対象をクラス指定に絞っている点がポイントです。空のエンティティにこの2つのコンポーネントを付けるだけで、VR空間全体にクリック判定を追加できます。
独自コンポーネントでエンティティに振る舞いを追加する
A-FrameのECSアーキテクチャの真価は、AFRAME.registerComponentで独自のコンポーネントを作り、既存のプリミティブに属性として追加できる点にあります。schemaでコンポーネントが受け取るプロパティの型とデフォルト値を定義し、tick関数で毎フレームの処理を書きます。
AFRAME.registerComponent('bounce', {
schema: { speed: { type: 'number', default: 2 } },
init: function () {
this.startY = this.el.object3D.position.y
this.time = 0
},
tick: function (time, deltaTime) {
this.time += deltaTime
const y = this.startY + Math.sin((this.time / 1000) * this.data.speed) * 0.4
this.el.object3D.position.y = y
}
})
このコンポーネントは<a-sphere bounce="speed: 2">のように属性として付けるだけで有効になります。以下のサンプルでは、スライダーでspeedプロパティをリアルタイムに書き換えて、跳ねる速さを調整できます。
el.setAttribute('bounce', 'speed', value)のように、コンポーネント名とプロパティ名を分けて指定すると、そのプロパティだけをピンポイントで更新できます。物理演算や当たり判定など、公式が提供していない機能もこの仕組みで自作できます。
360度画像でパノラマビューアを作る
A-Frameには<a-assets>という「アセット管理システム」があり、画像や3Dモデルをあらかじめ読み込んでから<a-sky>などのsrc属性に割り当てられます。これにより、画像の読み込み待ちで真っ黒な空間が一瞬表示されるのを防げます。
<a-assets>
<img id="sechelt" src="https://cdn.aframe.io/360-image-gallery-boilerplate/img/sechelt.jpg">
</a-assets>
<a-sky id="sky" src="#sechelt"></a-sky>
<script>
document.querySelector('#sky').setAttribute('src', '#sechelt') // 事前ロード済みの画像に差し替え
</script>
以下のサンプルでは、ボタンを押すと<a-sky>のsrcが切り替わり、3種類の360度パノラマ写真を見比べられます。
ドラッグで視点を動かしながらボタンを切り替えると、360度写真の中に入り込んでいるような感覚を確認できます。実際のプロダクトでは、この<a-sky>を<a-videosphere>に差し替えれば360度動画のビューアも同じ要領で作れます。
まとめ
A-Frameは、HTMLタグを並べるだけでVR/AR体験を構築できるWebフレームワークです。Entity-Component-Systemというシンプルな設計により、<a-box>のようなプリミティブから、AFRAME.registerComponentで作る独自コンポーネントまで、一貫した書き方で機能を積み上げていけます。WebXRにも対応しているため、開発したシーンはそのままVRヘッドセットやスマートフォンのARモードでも動作します。
まずは公式サイトの豊富なサンプルを眺めながら、手元の<a-scene>にタグを追加して挙動を確かめてみてください。3Dやゲームエンジンの経験がなくても、HTMLとCSSの延長として3D表現に触れられるのがA-Frameの一番の魅力です。