Edited at

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

最近作っていたthree.jsでの作品で軽量化を図ろうとGeometryBufferGeometryというものに書き換える作業がありました。

その中でも特にジオメトリの頂点をいじる時に迷った点がいくつかあったのでここに残しておきます。


BufferGeometryについて

BufferGeometryは通常のgeometryよりもより効率的な表現ができるみたいです。

いろいろな方の情報を見てみると生のwebGLを触る感覚で制御できるだとか。(知らなかった)

ただ、公式リファレンスにも書いてある通り、通常のジオメトリのほうが弄る分には楽らしいですね。


わざわざこれを使う必要があるの?

実際、これを使わなくても通常のジオメトリでほぼ同じ処理はできます。

ただ、より多くの頂点がある場合には処理速度に差が出るので、Three.jsのページが重くなった時の改善策の一つとなりそうなので覚えておこうと思いました。


通常のジオメトリとの違い

大きな違いとしてはバッファジオメトリは頂点などのデータをBufferAttributeを通して行うようです。


インスタンス生成

通常のジオメトリ制作に関してはこのような形式になります。


通常のジオメトリ

var geometry = new THREE.Geometry();

geometry.vertices.push(
new THREE.Vector3( -10, 10, 0 ),
new THREE.Vector3( -10, -10, 0 ),
new THREE.Vector3( 10, -10, 0 )
);

geometry.faces.push( new THREE.Face3( 0, 1, 2 ) );

geometry.computeBoundingSphere();


そしてBufferGeometryの場合は下記のとおりです。


バッファジオメトリ

var geometry = new THREE.BufferGeometry();

var vertices = new Float32Array( [
-10.0, 10.0, 0,
-10.0, -10.0, 0,
10.0, -10.0, 0,
] );
geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );


どちらも

var material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );



var mesh = new THREE.Mesh( geometry, material );

を書き加えてシーンに入れてしまえば下図のような赤い三角形が見えると思います(カメラのZ座標を100に設定しています。)

ss.PNG

PlaneやBoxといったプリミティブの生成に関してはほぼ変化がありません。クラス名にbufferが付くくらいです。

生成に関する引数も変わりません。


planeの例

//Geometry

var planeGeo = new THREE.PlaneGeometry(width, height,widthSegments,Segments);
//BufferGeometry
var planeGeo_B = new THREE.PlaneBufferGeometry(width, height,widthSegments,Segments);


頂点の座標を動かす

個別の頂点を指定して動かすためには全く別のメソッドを使います。

ですが引数の考えなどはほぼ同じであるため、その点に気を遣えば特に問題はありません。

//Geometry

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


頂点座標の変化を更新するとき

これはどちらのジオメトリにも言えますが頂点情報を毎フレーム更新するには更新の許可をする文を記入しなければいけません。

これも通常のジオメトリとbufferジオメトリで記述する文章が異なるので注意です。

//Geometry

geometry.verticesNeedUpdate=true;
//BufferGeometry
geometry.attributes.position.needsUpdate = true;


法線情報の更新

ジオメトリの頂点情報が変化すると法線も計算しなおした方がいいでしょう。

これに関してはどちらも利用するメソッドは同じです。

geometry.computeVertexNormals ();

geometry_B.computeVertexNormals ();

ただ、通常のジオメトリには

geometry.computeFaceNormals ()

geometry.computeFlatVertexNormals ()

のメソッドも存在しています。


持っている頂点の数

あとここも地味に躓いた。微妙に名前が違うんですよね。

//Geometry

geometry.vertices.length
//BufferGeometry
geometry_B.attributes.position.count


さいごに

筆者の僕もThree.jsの初心者です。

ただ、このあたりの情報に関してはほとんど情報がなかったため、同じ道を通る方のために残しておくことにしました。

もし間違っている点、説明の至らない点がありましたら、遠慮なくコメント等で指摘頂けますと幸いです。随時更新いたします。