Posted at

[Three.js] BufferGeometry vs Geometry


はじめに

WebGLライブラリThree.jsには、GeometryBufferGeometryの2種類の形状を表す形式があります。

この記事では


  • 2つの形式の関係

  • 2つの形式の操作の違い

  • パフォーマンス

の3点について解説します。


対象とする読者

この記事はThree.jsをすでに利用しているユーザーを想定しています。

そのためThree.jsのインストールガイドなどの内容は取り扱いません。


環境

この記事はThree.js r108を前提にしています。

バージョンが変わった場合、この記事の内容は適用できない場合があります。

記事を読む前にお手元の環境の確認をお願いします。


先に結論だけ


  • 現状のThree.jsではBufferGeometryクラスが形状を表す基本クラス、Geometryクラスが代替手段と位置付けられる。

  • BufferGeometryとGeometryクラスでは、頂点データなどにアクセスする方法が違う。

  • 2つのクラスをインスタンス化したり、頂点データを操作した場合大きなパフォーマンスの差が出る。

  • データの操作なしに同一の形状を再描画するだけなら、パフォーマンスの差は少ない。


2つの形式の関係

現在、Three.jsでは2つの形式を


  • BufferGeometry : 形状を表す基本的なクラス

  • Geometry : ユーザーフレンドリーなBufferGeometryの代替手段

と位置付けています。


BufferGeometry

An efficient representation of mesh, line, or point geometry.


BufferGeometry 公式ドキュメント


Geometry

Geometry is a user-friendly alternative to BufferGeometry.


Geometry 公式ドキュメント


ソースコードの依存関係

2つの形式は、ソースコード上ではどちらも依存関係がありません。

よく似た関数が用意されていますが、それぞれ独自に実装されています。

2つのクラスはそれぞれEventDispatcherを継承しています。


相互変換

2つの形式は、BufferGeometry.fromGeometry関数およびGeometry.fromBufferGeometry関数で相互変換が可能です。


〇〇BufferGeometryと〇〇Geometryの関係

Three.jsには基本的な形状を簡単に生成できるよう、プリミティブな形状を表すGeometryクラスが用意されています。立方体を表すBoxGeometryや平面を表すPlaneGeometry、球体を表すSphereGeometryなどがこれにあたります。

これらの〇〇Geometryクラスには、それぞれ対応する〇〇BufferGeometryクラスも存在します。

〇〇Geometryクラスは頂点データの生成を自身で行わず、コンストラクター内で〇〇BufferGeometryを生成し、それをGeometry.fromBufferGeometry関数で変換して利用しています。

BoxGeometryの該当箇所はこちらです。

BufferGeometryとGeometryにはソースコードの依存関係はありませんが、〇〇BufferGeometryと〇〇Geometryの間には依存関係があります。


ユーティリティクラス

2つの形式は、それぞれユーティリティクラスをもっています。このユーティリティクラスは、複数の頂点データのマージなどに威力を発揮します。

よく似た関数がそれぞれ用意されていますので、操作感はかわりません。


2つの形式の操作の違い

2つの形式では、頂点データへのアクセス方法が異なります。

という違いがあります。

//Geometry

geometry.vertices[i].setX(posX);
//BufferGeometry
geometry_B.attributes.position.setX(i, posX);

Geometry形式の方が、頂点データの編集を短く記述できます。

BufferGeometryで扱うattributesオブジェクトとは、WebGLでの頂点データ形式です。

参考記事 : シェーダの記述と基礎

WebGLのシェーダーに直接渡せる形式なので、Geometryよりもパフォーマンスが向上します。

2つの形式の頂点操作に関するより詳しい内容は、こちらの記事をご参照ください。

three.jsのGeometryからBufferGeometryへの書き換えで躓いたところ


パフォーマンス

2つの形式のもっとも大きな違いはパフォーマンスです。パフォーマンスの差を確認するためにデモページを作成しました。



https://masatomakino.github.io/threejs-lab/buffergeo

このデモページでは、画面中央に縦横256分割された球体が表示されています。


  • updateGeometryチェックボックスがONなら、毎フレーム球体のジオメトリを破棄して再生成する。

  • isBufferGeometryチェックボックスがONならBufferGeometryを、OFFならGeometryを生成する。

という条件で再描画を行なっています。

動作環境によって結果は異なりますが、以下の結果がデモページから読み取れます。


  • 毎フレーム破棄と再生成を繰り返した場合、BufferGeometryの方がGeometryより10倍程度高速である。

  • 破棄と再生成を行わず描画するだけの場合、数万ポリゴン程度のデータでは2つの形式の差は出ない。


    • (より巨大で複雑なデータを使用すれば、描画だけでもパフォーマンスの差が出る可能性はあります。)



2つの形式でパフォーマンスの差が大きく出るのは生成と頂点データの書き換え時でした。頂点データにアクセスせず同一の形状を再描画しつづけるならばあまり大きな差は出ません。

以上、ありがとうございました。