この記事は、複数オブジェクトを1つのオブジェクトにする方法のメモです
以下は知っておくべき要素
mergeGeometries
- 複数のGeometryを1つのGeometryにする
- マージする複数のGeometryのAttributionはそろっている必要がある
- 揃える場合は一度網羅的にAttributionを探索し
無いGeometryに対しては適当な値を付与する必要がある - 触った限りだとnoIndexesとindexesのGeometryも混在不可
- indexが無い場合は、縮退三角形(Degenerate triangle) の理論で
頂点のindexをそのままindexとして挿入する手を使えばうまくいく - キモとなるのが第二引数の
useGroups
-
useGroups
を有効にすると、内部で勝手にGeometryにaddGroup
してくれて、
materialの配列と紐づけて使えるようになる - ここでいうGeometryのgroupとはmaterialインデックスの範囲情報のこと
const geometries = [ geo1, geo2, geo3 ];
const mergedGeometry = BufferGeometryUtils.mergeGeometries(geometries, true);
Materials(Material[])
- Materialの配列
- 順番は必ず
mergeGeometries
に渡したGeometryの順番で、紐づくMaterialを格納する - ここで重要なのがMaterialのプリミティブタイプは揃える必要がある(gl_LINES, gl_TRIANGLESなど)
- 揃えなければ、メッシュ化すればLineやPointは描画されなく、ライン化すればMeshやPointは描画されない
// この場合はMeshなので、`LineMaterial`や`PointsMaterial`は含めることができない
const materials = [ mat1, mat2, mat3 ];
const mesh = new THREE.Mesh(mergedGeometry, materials);
これをすることのメリット
- オブジェクトが1つになる
- これを使わない方法として
Group
オブジェクトに.add
する方法があるが、
階層構造になって複雑化する
- これを使わない方法として
- 少しだけパフォーマンス改善するかも
- 多層になってたオブジェクトなら、
traverse
で子をたどる手数が減るという意味で
- 多層になってたオブジェクトなら、
これを導入するうえで確認するべきこと
-
根本的なパフォーマンス改善にはならない
- DrawCallはMaterialの個数に応じて1Callになるので、演算の削減にはならない
- Materialを1つにして
mergeGeometries
で1つのGeometryにできるなら
かなりパフォーマンス削減に期待できる- 1つにする場合は
mergeAttributes
をチェック
(もちろんテクスチャがある場合はマージできないので
自前でテクスチャアトラス化が必要)
- 1つにする場合は
-
InstancedMesh
も検討すると良い