メインコンテンツまでスキップ

カスタムアセットパーサー

PlayCanvas のすべてのアセットタイプは、アセットタイプごとに 1 つのリソースハンドラー'texture''model''audio' など)によって読み込まれます。ハンドラー内では、個々のファイルフォーマットをパーサーが処理します。たとえばテクスチャハンドラーには、ブラウザ画像、DDS、KTX2、Basis 用のパーサーがあります。ハンドラーはこれらのパーサーの公開レジストリを備えているため、エンジンを変更することなく、新しいファイルフォーマットのサポートを追加したり、組み込みのものを上書きしたりできます。

注記

カスタムパーサーはエンジン v2.21.0 以降で利用できます。これはエンジンのランタイム API であり、パーサーはアプリケーションの読み込み時に実行されます。エディタのアセットインポートパイプラインには影響しません。

アセット読み込みの仕組み

アセットが読み込まれると、ResourceLoader はそのアセットのタイプに登録された ResourceHandler を参照します。ハンドラーは登録された各パーサーに、新しく登録された順でリソースを認識できるかどうかを問い合わせ、パーサーを選択します:

  1. ハンドラーがリソースを表すコンテキスト(URL、拡張子など)を構築します
  2. canParse(context)true を返す、最も新しく登録されたパーサーが選択されます
  3. パーサーの load() がファイルを取得し、データを渡します
  4. パーサーの open() がそのデータをランタイムリソース(TextureModel など)に変換します

選択は新しい順に行われるため、後から登録したパーサーは、そのパーサーが認識するリソースについて組み込みのパーサーより優先されます。

パーサーのコントラクト

パーサーは、次のメソッドを持つプレーンオブジェクトまたはクラスインスタンスです:

class MyParser {
// このパーサーが対象のリソースを処理できる場合は true を返します
canParse(context) {
return context.ext === 'myformat';
}

// リソースを取得し、callback(err, data) で生データを渡します
load(url, callback, asset) {
this.handler.fetch(url, pc.Http.ResponseType.ARRAY_BUFFER, callback, asset);
}

// オプション: 読み込んだデータをランタイムリソースに変換します
open(url, data, asset) {
return data;
}
}

canParse に渡される context は、読み込まれるリソースを表します:

プロパティ説明
urlクエリ文字列を除いた元のリソース URL(または null
ext先頭のドットを除いた小文字のファイル拡張子。例: 'tga'
basename小文字のファイル名。例: 'lod-meta.json'
asset読み込み対象の Asset(存在する場合)
app実行中の AppBase

パーサーが登録されると、ハンドラーは自身をパーサーの handler プロパティに割り当てます。これにより load() から this.handler.fetch(url, responseType, callback, asset)(ハンドラーのリトライ設定でリソースをダウンロードし、事前取得済みデータがあれば再利用するヘルパー)や、ハンドラーの状態(たとえば this.handler.app)にアクセスできます。

パーサーの登録

パーサーは、対象のアセットタイプのハンドラーに登録します:

app.loader.getHandler('texture').addParser(new TgaParser());

パーサーは、そのアセットタイプの読み込みを開始する前に登録してください。登録済みのパーサーは removeParser(parser) で削除でき、現在登録されているパーサーは読み取り専用の parsers プロパティで確認できます。

選択は新しい順に行われるため、組み込みパーサーがすでに対応しているフォーマットを扱うパーサーを登録すると、組み込みのものを上書きします。これは特定の拡張子に対しても、キャッチオール(すべてを受け付ける)パーサーに対しても機能します。

例: TGA テクスチャパーサー

エンジンはランタイムで .tga ファイルを読み込みません。カスタムパーサーでサポートを追加できます:

class TgaParser {
canParse(context) {
return context.ext === 'tga';
}

load(url, callback, asset) {
this.handler.fetch(url, pc.Http.ResponseType.ARRAY_BUFFER, callback, asset);
}

// テクスチャパーサーは拡張された open シグネチャを使用します。ハンドラーがグラフィックス
// デバイスと、アセットデータから導出されたテクスチャオプションを渡します
open(url, data, device, textureOptions) {
// TGA ファイルを RGBA8 ピクセルにデコードします(任意のデコーダーを使用)
const { width, height, pixels } = decodeTga(data);

const texture = new pc.Texture(device, {
name: url,
width: width,
height: height,
format: pc.PIXELFORMAT_RGBA8,
levels: [pixels],

// アセット由来のオプションを最後にスプレッドすることで、アセットの設定
// (srgb、フィルタリング、mipmaps など)が上記のデフォルトを上書きします
...textureOptions
});

texture.upload();

return texture;
}
}

app.loader.getHandler('texture').addParser(new TgaParser());

パーサーを登録すれば、.tga ファイルは他のテクスチャと同様に読み込まれます:

const asset = new pc.Asset('picture', 'texture', { url: 'images/picture.tga' }, { srgb: true });
app.assets.add(asset);
app.assets.load(asset);

完全に動作するカスタムモデルパーサーの例については、エンジンの OBJ パーサーと、それを使用する OBJ ローダーの例を参照してください。

ハンドラーに関する注意

フォーマットを扱うほとんどのハンドラーがパーサーレジストリに対応しています: modeltexturematerialgsplatcontaineranimationanimclipanimstategraphtemplateaudiojsoncsshtmltextshaderbinary。いくつかの詳細はアセットタイプによって異なります:

  • texture — パーサーは上記の拡張された open(url, data, device, textureOptions) を実装します。組み込みのブラウザ画像パーサーはキャッチオールであるため、カスタムパーサーが処理しない未知の拡張子はそこにフォールバックします。
  • material — ハンドラーのアセットバインディング(マテリアルデータが参照するテクスチャアセットの割り当て)は、組み込みの JSON パーサーが生成する StandardMaterial に適用されます。カスタムパーサーが生成するマテリアルは、自身でアセット参照を管理します。
  • audio — サウンドマネージャーはパーサーから this.handler.manager として利用できます。カスタムパーサーは AudioBuffer にデコードし、pc.Sound でラップして返すことができます。
  • ファイルフォーマットを解析するのではなく他のアセットを構成するハンドラー(cubemapfontspritetextureatlas)と、特殊用途のハンドラー(bundlescriptfolder)は、登録されたパーサーを参照しません。

関連項目