Unityで3Dオブジェクトをボクセル化する「unity-voxelizer」について
こちらのblogで紹介されていたunity-voxelizerを試してみて、どんな仕組みで動いているのかを調査。
まず、デフォルトのSphereにたいして unity-voxerlizer を適用すると
こんな感じのボクセルSphereになる。
ボクセルの密度パラメータを大きくすると、さらに細かいボクセルSphereになる。
(密度パラメータを大きくしすぎるとVoxel生成しすぎてUnity固まるので注意)
仕組みとしては、ボクセル化対象となるオブジェクトが存在する空間をバウンディングボックスで定義しておき、密度パラメータに応じてボクセルを設置していく。
[Header("ボクセル化対象のバウンディングボックスの設定")] [SerializeField] private Bounds bounds = new Bounds(Vector3.zero, Vector3.one); // 密度パラメータ [SerializeField] private int xDensity = 8; [SerializeField] private int yDensity = 8; [SerializeField] private int zDensity = 8;
これらのパラメータを、unity-voxelizerが提供するVoxelizerクラスに渡してインスタンス生成し、Vocelize関数を実行するとボクセル化に必要な情報を生成してくれる。
voxeliser = new Voxeliser(bounds, xDensity, yDensity, zDensity); voxeliser.Voxelize(transform);
あとは、バウンディングボックス内の密度に応じて、それぞれの空間にボクセルを置くべきかどうかを Voxeliserインスタンスでチェックして置いていくだけ。
for (int x = 0; x < xDensity; x++) { for (int y = 0; y < yDensity; y++) { for (int z = 0; z < zDensity; z++) { if (voxeliser.VoxelMap[x][y][z]) { var pos = worldCentre + new Vector3 ( x * gridCubeSize.x, y * gridCubeSize.y, z * gridCubeSize.z ); var go = Instantiate(m_voxelModel, pos, Quaternion.identity); go.transform.localScale = gridCubeSize; go.transform.SetParent(rootTransform, true); } } } }
ただ、voxeliser.Voxelize(transform) がどうやってボクセル空間を構築しているのかが自分には難しかった・・・。
やってることとしては、ざっと以下の手順だと思われる。
- ボクセル化対象オブジェクトのMeshをチェックしてAABBの配列を生成
- 密度パラメータに応じたボクセル空間に対し、1で作ったAABBの重なりをチェック(ここのチェック処理がかなり難しい。多分、いい感じに重なっていたらtrueを返している)
- ボクセルの存在可否だけをまとめた "bool[] _voxelMap" が作られる
MeshやAABBの周りの操作はまだ全然できないので、今後勉強していかないと。