three.jsで使うテクスチャーをPreloadJSで一括ロードしよう!

  • 18
    Like
  • 0
    Comment

ceb40bdb-685a-d434-db94-e4e3b23ff887.png

この記事は、Three.js Advent Calendar 2016 11日目の記事です。

three.jsでコンテンツを作る上でさけては通れないテクスチャーのロード処理。実はPreloadJSを併用することで劇的に効率良くテクスチャーが扱えるようになることをご存知でしょうか?今回はそんなマル秘テクニックを解説します。

TextureLoaderは一個のロードしかできない :smiling_imp:

three.jsに元々TextureLoaderというローダーが備わっています。次のコードはhoge.jpgを読み込むためのコードです。

// テクスチャーのロード
var loader = new THREE.TextureLoader();
var texture = loader.load('hoge.jpg');

// マテリアルに貼り付け
var material = new THREE.MeshBasicMaterial( { 
    map: texture
});

TextureLoaderload()メソッドを使用して一つの画像を読み込んでいます。しかしこのままでは複数の画像を読み込みたい場合、。一個一個の画像に対してload()メソッドを呼ぶ必要があります。ほとんどのプロジェクトの場合、テクスチャーは複数読み込む必要があるためTextureLoaderでは非常に面倒です。しかしPreloadJSを併用することでこの問題が解決します。

PreloadJSとは :thinking:

PreloadJSとはCreateJSが提供している画像や音楽ファイルを読み込むためのモジュールです。PreloadJSを使用することで複数のアセットの読み込みが可能になり、ローディング表示などの実装にも役立ちます。PreloadJSはCreateJSを使用せずとも単体で使用することができます。

three.jsとPrelaodJSを併用した簡単なデモを作成しました。GitHubにソースコードも置いていますので参考ください。


Untitled.gif

ここからPreloadJSを使用したテクスチャーロードの実装方法を解説しますがドキュメントを併せて見ておくと分かりやすいです。

PreloadJSでのテクスチャーロード実装 :wink:

PreloadJSを使ったテクスチャーロード方法を解説します。まずはPreloadJSをHTMLで読み込みます。

<!-- PreloadJSの読み込み -->
<script src="https://code.createjs.com/preloadjs-0.6.2.min.js"></script>

PreloadJSを使用する準備が出来たのでJavaScriptを書いていきます。次のコードは画像を読み込んでthree.jsで使えるテクスチャーに変換するまでのコードです。

// 読み込むテクスチャーリスト
var manifest = [
    { id: 'hoge', src: './texture/hoge.png'},
    { id: 'huga', src: './texture/huga.png'}
];

// ロードキューを作成
var loadQueue = new createjs.LoadQueue();

// ロード完了を監視
loadQueue.on('complete', function() {
    // loadQueueからロードした画像データを取得
    var image = loadQueue.getResult('hoge');
    // three.jsで使えるテクスチャーに変換
    var texture = new THREE.Texture(image);
    // 【重要】更新を許可
    texture.needsUpdate = true;
});

// テクスチャーのロードを開始
loadQueue.loadManifest(manifest);

コードを順に解説していきます。

1. マニフェストデータを用意

読み込みたい画像の一覧データを配列で用意します。

// 読み込むテクスチャーリスト
var manifest = [
    { id: 'hoge', src: './texture/hoge.png'},
    { id: 'huga', src: './texture/huga.png'}
];

idに設定した文字列は読み込み結果から画像を取得する際に使用します。分かりやすいidを設定しましょう。srcには読み込みたい画像のパスを設定します。PreloadJSではこのような読み込みリストデータをManifestマニフェストと呼びます。

2. LoadQueueを生成

LoadQueueはローダーと思ってもらって差し支えありません。LoadQueueを生成し、これを利用して画像のロードを行っていきます。

// ロードキューを作成
var loadQueue = new createjs.LoadQueue();

3. ロード完了イベントのリスナーを登録

ロード完了後の処理を追加します。全てのアセットのロードが完了するとcompleteイベントが発火されるのでon()メソッドでイベントリスナーを登録して監視します。

// ロード完了を監視
loadQueue.on('complete', function() {
    // loadQueueからロードした画像データを取得
    var image = loadQueue.getResult('hoge');
    // three.jsで使えるテクスチャーに変換
    var texture = new THREE.Texture(image);
    // 【重要】更新を許可
    texture.needsUpdate = true;
});

ロード完了後はgetResult()メソッドにマニフェストで設定したIDを引数として渡すことで読み込んだ画像データを取得できます。

// loadQueueからロードした画像データを取得
var image = loadQueue.getResult('hoge');

この時点でのimageの中身は<image />のようなタグ情報になっているのでこのままではテクスチャテクスチャーとして使用できません。この画像データをTHREE.Textureのインスタンス生成時に引数として渡すことで初めてthree.jsで扱えるテクスチャーオブジェクトに変換されます。

// three.jsで使えるテクスチャーに変換
var texture = new THREE.Texture(image);

needsUpdatetrueに設定することを必ず忘れないようにしてください!!この設定を忘れるとテキスチャーが反映されず黒いMeshが表示されてしまいます。

// 【重要】更新を許可
texture.needsUpdate = true;

4. ロード開始

最後にloadManifest()メソッドを使ってマニフェストで指定した画像の読み込みを開始します。

// テクスチャーのロードを開始
loadQueue.loadManifest(manifest);

使い方

読み込んだテクスチャーはそのままマテリアルの生成時にプロパティーとして渡すことで使用できます。

var material = new THREE.MeshPhongMaterial({
  map: texture
});

尚、上記ではTHREE.Textureで説明しましたがTHREE.CubeTextureでも同じように読み込んだ画像から生成できます。SkyBoxでも同じ様に使えるので便利です。

// キューブテクスチャー
var texture = new THREE.CubeTexture([
  loadQueue.getResult('px'),
  loadQueue.getResult('nx'),
  loadQueue.getResult('py'),
  loadQueue.getResult('ny'),
  loadQueue.getResult('pz'),
  loadQueue.getResult('nz')
]);
texture.needsUpdate = true;

まとめ :bow:

今回紹介した方法を用いれば、テクスチャが読み込み終わっていないのにモデルが表示されてしまうなどの問題も解決できます。さらに、PreloadJSはテクスチャーだけでなく音楽ファイルも読み込めるのでthree.jsのローダーは使用せずにアセットのロードはPreloadJSで一元管理したほうがプロジェクト内の見通しが良くなると思います。アセットの読み込み周りでお困りであれば一度試してみてはいかがでしょうか。