- 2013年01月18日 (金)
- Tweet
WebGL対応のライブラリThree.jsを爆速にする方法
前回のWebGL(Three.js)とStage3D(Away3D)の比較ですが、Mr.doobさんを始め国内外の多くの方からご指摘頂きWebGL(Three.js)版を最適化したところ、最終的にはFlash(Away3D)版と同じぐらいのパフォーマンスになりました。当初、最適化・検証不足で間違った情報を掲載してしまい申し訳ありませんでした。
さて、そのWebGL(Three.js)版を最適化した手法が有意義だったのでシェアしたいと思います。
デモの紹介
まずはこちらの2つのデモの再生を比較してみてください。WebGL対応のブラウザ(例:Google Chrome)でご覧ください。
▼最適化前
▼最適化後
どうでしょう?
圧倒的に後者のほうが滑らかに再生できているのではないかと思います。
後者のほうは配置している3Dのオブジェクト数が10倍近く多いにもかかわらずです。
※ちなみにFlash Stage3Dだとこの6倍以上の100万ポリゴンで60fpsを達成しました。
最適化の秘密
最適化の秘密を紹介したいと思います。Flash(Away3D)の最適化でも紹介したのと同様、GPUを用いるコンテンツにおいてドローコール(描画の命令)の回数はパフォーマンスに最も影響します。そのためドローコールを少なくすることが3Dコンテンツ制作の際に最も気に留めるべきポイントとなります。
大量の3Dオブジェクトを表示する場合は、3Dオブジェクトのジオメトリ(3D形状における頂点の座標群)を結合することによってGPUに対するドローコールを少なくすることができます。Three.jsでは、THREE.GeometryUtils.merge()メソッドでジオメトリを結合できます。コードは次のように記述します。
// 空のジオメトリを作成 var geometry = new THREE.Geometry(); // 立方体個別の要素を作成 var meshItem = new THREE.Mesh(new THREE.CubeGeometry(30, 30, 30, 1, 1, 1)); // Box for (var i = 0; i < 10000; i++) { meshItem.position.x = 10000 * Math.random(); meshItem.position.y = 10000 * Math.random(); meshItem.position.z = 10000 * Math.random(); // ジオメトリを結合 THREE.GeometryUtils.merge(geometry, meshItem); } // マテリアルを作成 var material = new THREE.MeshBasicMaterial({color:"#F00"}); // 3D空間に追加 var mesh = new THREE.Mesh(geometry, material); container.add(mesh);
3Dオブジェクトを一個一個3D空間に追加して表示するよりは、大量の立方体をまとめた巨大な3Dオブジェクトを1個だけ3D空間に追加したほうが負荷が少ないという感じです。前者はGPUに対して一個一個ドローコールが発生するのですが、後者だと1回にまとめて(厳密には転送できる頂点の個数で分割した回数だけ)ドローコールが発生します。
注意点
ジオメトリをまとめてしまうので、3Dオブジェクト(Meshのインスタンス)としては一つになります。そのため、個別にマテリアルを設定したりマウスイベントを設定するのはできなくなります(工夫次第ではできると思いますが、簡単にはできなくなります)。
そのため、同じような形状のジオメトリを大量に表示させたい場合にこのテクニックを使ってみるといいかもしれません。
また3Dモデルを用意するときも、出来る限りメッシュは分割せずに用意するといいでしょう。このあたりの最適化テクニックはFlash Stage3D勉強会で触れられていたので、そちらの資料も参考にしてみるといいでしょう。
Stage3D勉強会(第2回) – 発表資料 | ClockMaker Blog
※Stage3D 勉強会 (第3回)のほうもよければご参加ください
追記(平成29年11月8日):最新版リビジョンr88でのジオメトリの結合方法をICS MEDIAに投稿しました。最新の情報は次の記事を参考ください。
2013年07月03日(水) 22:21
こんにちは。
本件でcubeにカラーを当てるのではなく、6面に違う画像を当てる方法はご存知でしょうか。
本件はリビジョン53のthree.jsを利用されていて、自分も同じものを利用しております。
gitのchangelogを拝見すると53からmaterialsが排除となってしまったようなのです。
本件と若干ずれた内容になってしまいますが、可能でしたら、ご教授お願い致します。
2013年12月06日(金) 09:20
[…] 無理なのでこれがWebGLの強みですね。 さらにレンダリングを速くする最適化する手法としてこちらで紹介されています。複数のオブジェクトをまとめたオブジェクトを描画したい場合は効 […]
2014年01月27日(月) 22:34
[…] することができます。Three.jsでは、THREE.GeometryUtils.merge()メソッドでジオメトリを結合できます。こちらサイトを参考にさせていただきました。WebGL対応のライブラリThree.jsを爆速にする方法 […]