未来を創る、テックコミュニティー

代表技術通信~Unityのことをちゃんと勉強する⑨ 読み込めました、あとは表現力

草場代表
2020/10/08

こんばんは。代表の草場です。

【PointCloud】大量の点群データをUnityで読み込んでVR化する!【メタバース】」、だんだんと理解ができてきました。シンラボメンバーのUnity使い、ともよりさんのおかげです。時間をいただき、ありがたい。
基本的には解説記事通りなのですが、学んだことをメモします。今回は、三原山のデータで試しました。
豊島園バージョンは以下。

環境

OS:Windows 10
Unity:2019.4.11f1
点群データ:三原山。約3億点。約5GB。plyファイル。

まずはJun ItoさんのGitHubをローカルにクローンしました。そしてUnityで起動。

①まずは点群データをテキストファイルに変換

現在もっているデータはplyファイルです。CloudCompareを使います。記事ではターミナルで実行されていますが、うまく再現できなかったので、GUIでそのままやりました。もともとのデータ。

代表技術通信~Unityで点群表示、Oculus Questで表示③ DMM.make AKIBA歩いてみる」でやった通り、原点を調整します。編集>グローバル回転とスケールの編集をクリック。Shiftの欄にGlobal box centerの値をそのまま入れます。入力したら「はい」をクリック。Global box centerのX, Y, Zが0となりました。
点の数を減らします。今回は、0.2m感覚にしました。記事によると、この感覚は一つミソとのこと。編集>再サンプリングから設定です。
そしてTextファイルで保存します。データの区切りはSpaceにします。

44MBになりました。これを、Jun ItoさんのGitHubでいうこところの、Dataフォルダに置きます。

②点群の読み込み

さて、Unityで表示するために、まず点群を読み込みます。GitHubでいうところのPtsReader.csです。
記事にある、「ファイルを1行ごとにパースし、Tuple<Vector3, Vector3>のListとして返します。」が、
return await Task.Run(() =>
content.Split('\n').Where(s => s != "").Select(parseRow).ToList()

の部分です。
以下の部分も鍵です。
return (new Vector3( splitted[0],
                               splitted[2], // PTSファイルは通常Z-upなので、ここでZとYを交換しY-upに変換
                               splitted[1] ),
           new Vector3( splitted[3],
                               splitted[4],
                               splitted[5] )); }

③ComputerBufferヘデータセット

ここからが理解しきれてない部分ですが、記事の以下の部分です。

CPUベースだと処理的に難しいため、Compute Bufferを利用し初期化以外は極力GPUで実行できるように実装しています。

バッファ領域を確保・セットします。確保する領域サイズは、データ数 × データ一つあたりのサイズです。
int size = Marshal.SizeOf(new Vector3());
posbuffer = new ComputeBuffer(positions.Count, size);
colbuffer = new ComputeBuffer(colors.Count, size);
posbuffer.SetData(positions);
colbuffer.SetData(colors);

④ComputerBufferヘ描画命令

バッファへの書き込みが完了したあとは、OnRenderObjectメソッドで、GameObjectやMeshRendererを使わない形でGPUに直接レンダリング命令を出しています。

void OnRenderObject()
{ if (bufferReady)
             { // レンダリングのたびに頂点の個数分シェーダーを実行
               // MeshTopology.Pointsを指定することで、面ではなく頂点が描画される
               material.SetPass(0);
               Graphics.DrawProceduralNow(MeshTopology.Points, pts.Count); } }

ここでMeshTopology.Pointsを渡すことで、Unityデフォルトのメッシュ描画モードではなく、頂点描画モードでのレンダリングが実行されます。(詳細
またここで頂点の個数を渡すことで、Shader側で頂点に一つ一つ順番にアクセスする処理が可能になっています。

⑤Shaderによる描画

ある程度勉強していたので、なんとなくわかりました。PointCloud.shaderです。メモリ領域に読み込んだ頂点・色のバッファを円の形で表示するShaderです。

StructuredBuffer<float3> colBuffer;
という名前でセットされたBufferの値にアクセスできるので、頂点IDを用い、
float4 pos = float4(posBuffer[id], 1);
のような形でバッファに格納したデータを取得しています。また、vertex shaderからfragment shaderに値を渡す際に、POSITIONセマンティクスとTEXCOORDセマンティクス(何でも良い)の2つの変数でスクリーンポジションを渡すことにより、各点を円の形にクリッピングしています。

で、まだ理解が及んでいない点。Unity上のヒエラルキーにPointCloudAnchorを置き、そこに今回のptsファイルをアタッチします。
GameManagerオブジェクトにControllerManager.csがアタッチされています。このあたり、まだわかりません。

Playで実行すると、三原山を歩いた軌跡が出てきました。

Oculus Quest表示でしました。

この記事を書いた人
草場代表
エディター