アセットマネジメントシステム
A-Frameにはアセットマネジメントシステムがあり、アセットを一カ所に集めたり、アセットを事前にキャッシュしてパフォーマンスを向上させることができます。アセット管理システムは、純粋にアセットをプリロードするためのものであることに注意してください。実行時にエンティティに設定するアセットについては、アセットへの直接のURLを介して行うことができます。
ゲームやリッチな3D体験では、シーンをレンダリングする前に、モデルやテクスチャなどのアセットをあらかじめロードしておくことが伝統的に行われています。これにより、アセットが視覚的に欠落しないようにし、レンダリング中にシーンがアセットを取得しようとしないようにするため、パフォーマンスが向上します。
アセットは<a-assets>の中に置きます。<a-assets>は<a-scene>の中に置きます。
アセットには以下があります。
<a-asset-item>- 3Dモデルや素材などの雑多なアセット<audio>- サウンドファイル<img>- 画像テクスチャ<video>- ビデオテクスチャ
ブラウザがすべてのアセットを取得する(またはエラーになる)か、アセットシステムがタイムアウトになるまで、シーンはレンダリングまたは初期化されません。
# 例
<a-assets>で資産を定義し、セレクタを使って実体からそれらの資産を指し示すことができます。
<a-scene>
<!-- Asset management system. -->
<a-assets>
<a-asset-item id="horse-obj" src="horse.obj"></a-asset-item>
<a-asset-item id="horse-mtl" src="horse.mtl"></a-asset-item>
<a-mixin id="giant" scale="5 5 5"></a-mixin>
<audio id="neigh" src="neigh.mp3"></audio>
<img id="advertisement" src="ad.png">
<video id="kentucky-derby" src="derby.mp4"></video>
</a-assets>
<!-- Scene. -->
<a-plane src="#advertisement"></a-plane>
<a-sound src="#neigh"></a-sound>
<a-entity geometry="primitive: plane" material="src: #kentucky-derby"></a-entity>
<a-entity mixin="giant" obj-model="obj: #horse-obj; mtl: #horse-mtl"></a-entity>
</a-scene>
シーンとそのエンティティは、初期化およびレンダリングの前に、すべてのアセットを(タイムアウトまで)待ちます。
# クロスオリジンリソース共有(CORS)
A-Frame は XHRs (opens new window) を使ってアセットを取得するため、ブラウザのセキュリティ上、アセットが異なるドメインにある場合は、CORS(cross-origin resource sharing)ヘッダ (opens new window)を付けて提供する必要があります。もしくは、シーンと同じ場所でアセットをホストする必要があります。
その他のオプションについては、GitHub PagesはすべてをCORSヘッダ付きで提供します。
シンプルなデプロイメント プラットフォームとして、GitHub Pages をお勧めします。または、CORSヘッダーが設定されたファイルを提供する他のサービス(Amazon S3など)。
その他のオプションでは、GitHub Pages (opens new window) はすべてを CORS ヘッダで提供します。シンプルなデプロイメントプラットフォームとして、GitHub Pagesをお勧めします。または、CORSヘッダを設定してファイルを提供する他のサービス(Amazon S3など)。
CORS ヘッダが設定されている場合、<a-assets> はリソースが異なるドメインにあることを検出すると、メディア要素(例:<audio>、<img>、<video>)に自動的に crossorigin 属性を設定します。
# オーディオとビデオのプリロード
オーディオとビデオアセットがシーンをブロックするのは、autoplayを設定した場合か、preload="auto"を設定した場合のみです。
<a-scene>
<a-assets>
<!-- These will not block. -->
<audio src="blockus.mp3"></audio>
<video src="loadofblocks.mp4"></video>
<!-- These will block. -->
<audio src="blocky.mp3" autoplay></audio>
<video src="blockiscooking.mp4" preload="auto"></video>
</a-assets>
</a-scene>
# タイムアウトを設定する
タイムアウトを設定すると、すべてのアセットがロードされたかどうかに関係なく、シーンはレンダリングを開始し、エンティティは初期化を開始します。デフォルトのタイムアウトは3秒です。別のタイムアウトを設定するには、timeout 属性にミリ秒単位で数値を渡します。
一部のアセットの読み込みに時間がかかる場合、ネットワークが遅い場合にユーザーが一日中待つことがないように、適切なタイムアウトを設定することができます。
<a-scene>
<a-assets timeout="10000">
<!-- You got until the count of 10 to load else the show will go on without you. -->
<img src="bigimage.png">
</a-assets>
</a-scene>
# イベント
<a-assets>と<a-asset-item>はA-Frameのノードなので、読み込みが終わるとloadedイベントを発行します。
#
| Event Name | 概要 |
|---|---|
| loaded | すべてのアセットがロードされた、またはアセットがタイムアウトした。 |
| timeout | アセットがタイム・アウトした。 |
# 個別アセットの進捗を読み込む
# <a-asset-item>
<a-asset-item> は three.jsのFileLoader (opens new window) を呼び出します。
<a-asset-item>はどのようなファイルタイプにも使用できます。終了したら、それはテキストレスポンスでそのデータメンバを設定します。
| Event Name | 概要 |
|---|---|
| error | Fetchエラーです。イベントの詳細にはXMLHttpRequestのインスタンスを含むxhr |
| progress | 進行時に発行される。イベントの詳細には、XMLHttpRequest インスタンスを含む xhr、loadedBytes、totalBytes が含まれます。 |
| loaded | srcで指定されたアセットがロードされました。 |
# <img>
画像は標準的なDOM要素なので、標準的なDOMイベントをリッスンすることができます。
| Event Name | 概要 |
|---|---|
| load | イメージがロードされた |
# HTMLMediaElement
オーディオとビデオアセットはHTMLMediaElement (opens new window)です。ブラウザはこれらの要素に対して特定のイベントを発生させます。ここでは便宜上、これらの要素について説明します。
| Event Name | 概要 |
|---|---|
| error | アセットの読み込みにエラーが発生しました。 |
| loadeddata | 進行中 |
| progress | 進行中 |
A-Frameは、この進捗イベントを利用して、ブラウザがバッファリングした時間とアセットの継続時間を比較し、アセットのロードを検知します。
# レスポンスタイプの指定
<a-asset-item>で取得したコンテンツは、プレーンテキストとして返されます。arraybufferのような別のレスポンスタイプを使いたい場合は、<a-asset-item>のresponse-type属性を使用します。
<a-asset-item response-type="arraybuffer" src="model.gltf"></a-asset-item>
# 内部でどのように動いているか
A-Frameの各要素は、AFRAME.ANodeのプロトタイプである<a-node>を継承しています。
ANodeは読み込みと初期化の順番を制御します。ある要素(<a-assets>、<a-asset-item>、 <a-scene>、<a-entity>のいずれか)が初期化されるには、その子要素がすでに初期化されていなければなりません。ノードはボトムアップで初期化されます。
<a-assets> は ANode であり、ロードする前に子ノードがロードされるのを待ちます。また、<a-assets> は <a-scene> の子であるため、シーンは事実上すべてのアセットがロードされるのを待つ必要があります。また、<a-entity> に追加のロード ロジックを追加し、<a-assets> を定義した場合は、明示的に <a-assets> のロードを待ちます。
<a-asset-item> uses THREE.FileLoader to fetch files. three.js stores the
returned data in THREE.Cache. Every three.js loader inherits from
THREE.FileLoader, whether they are a ColladaLoader, OBJLoader,
ImageLoader, etc. And they all have access and are aware of the central
THREE.Cache. If A-Frame already fetched a file, A-Frame won't try to fetch it
again.
<a-asset-item>はTHREE.FileLoaderを使用してファイルを取得します。three.jsは返されたデータをTHREE.Cacheに格納します。ColladaLoader、OBJLoader、ImageLoaderなど、すべてのthree.jsのローダーはTHREE.FileLoaderを継承しています。そして、それらはすべてTHREE.Cacheにアクセスし、中央のTHREE.Cacheを認識します。A-Frameがすでにファイルを取得した場合、再取得は行いません。
このように、アセットでエンティティの初期化をブロックしているため、エンティティがロードされる頃には、すべてのアセットがすでにフェッチされていることになります。<a-asset-item> を定義し、エンティティが THREE.FileLoader を使用してファイルをフェッチしている限り、キャッシュは自動的に機能します。
# FileLoaderとキャッシュにアクセスする
もっと詳しく聞きたい場合はthree.jsのFileLoaderにアクセスすること。
console.log(document.querySelector('a-assets').fileLoader);
XHRレスポンスを格納するキャッシュにアクセスするために。
console.log(THREE.Cache);