3次元点群を3Dビューアでグリグリとただ表示するだけならPoint Cloud Libraryを使ってすぐにできるんだけど、インタラクティブなコンテンツとして点群を利用したい場合にはPoint Cloud Libraryだけだとちょっと味気ない。Point Cloud Libraryだと視点を動かす時は点群の更新が止まっちゃうし。
何でUnityで点群を扱いたいかというと、お察しの通り、Kinectで取得した点群をカッコよく表示したいのです。Kinect V2になってからMicrosoftが公式にUnityプラグインを配布し始めたし、せっかくだから自前でOpenCVとかPoint Cloud Libraryでゴリゴリ頑張るよりも、Unityで他のAssetと組み合わせてサクッとリッチなコンテンツに仕上げたいのだ。
Microsoft公式のKinect v2 for Unityプラグインには、サンプルとしてKinectのColorとDepthをMesh化して表示するScriptコードが付属しているんだけど、無理やりMesh化して表示してるからちょっと汚らしい。
Microsoft公式のUnityプラグインおよびサンプルプロジェクトは以下のページの”Unity Pro packages“のリンクから。↓
https://www.microsoft.com/en-us/download/details.aspx?id=44561
こちらの公式サンプルでは、Kinect V2から取得した点群を4分の1の量にダウンサンプリングしてから、それらを頂点としたポリゴンメッシュ化してリアルタイム表示している。
Kinect V2で取得可能な点群(つまりDepth画像の解像度)は
512 × 424 = 217,088
だけど、Unityには「1つのMeshオブジェクトが持つ三角形の数は最大65,535まで」という制限があるため、ダウンサンプリングで頂点の数を減らしてMesh化してるんだと思う。
このサンプルでは解像度をダウンサンプリングする代わりに、Depth値を近傍ピクセルの平均から求めたりもしてるんだけど、結果として表示されるMeshがあんまりきれいじゃない。
2017年12月 追記:Meshオブジェクトのポリゴン数制限はUnity 2017.3から解消されたようです。
ということで、Unityで「面」ではなく「点」の描画を実現する方法を調べてみた。
ちょっと調べてみると、どうやら点群ファイルを表示するための有料のAssetでPoint Cloud Viewer and Toolsというものがすでにあるようだ。以下サポートページに詳細が載っている。↓
Point Cloud Viewer & Tools for Unity
このツールはファイル読み込み用なので、どうやら動的にKinectの情報を表示はできなさそう。読み込みをサポートしているフォーマットはXYZ, XYZRGB, CGO, ASC, CATIA ASC, PLY (ASC)。読み込んだファイルを自動でUnityのポリゴン制限数で分割して表示と、バイナリデータへの保存ができるようだ。
Kinectの点群をリアルタイムで表示するにはやっぱり自分でScriptを書くしかなさそうなので点の描画方法を調べてみたら、ドンピシャなブログ記事を見つけた。↓
Rendering a Point Cloud inside Unity
Here is a short example of how to render a point cloud using MeshRenderer inside Unity, have in mind that you have a limit of 65k points per mesh, so if you want to render more points, you need to split them.
ソースコードも全部載せてくれている。OpenGLのAPIコマンドを有効にしてPoint SizeとSmooth PointをEnableにして、Shader側で受け取ってやるってことね。
上記の記事だけだとShaderへのパラメータ渡しの記述が欠けてるけど、以下のフォーラムの記事に全部載っている。↓
How do I use PSIZE in a Unity 4.5.4 shader?
このフォーラム記事では、DirectX環境ではPoint Sizeの指定が描画に反映されないことについて話題になっている。要するに、残念ながらOpenGL環境でしか動かない仕様っぽい。
こちらが描画用のPoint Cloudをランダムに生成するC# Scriptのサンプルコード↓
using UnityEngine; using System.Collections; [RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))] public class PointCloud : MonoBehaviour { private Mesh mesh; int numPoints = 60000; // Use this for initialization void Start () { mesh = new Mesh(); GetComponent<MeshFilter>().mesh = mesh; CreateMesh(); } void CreateMesh() { Vector3[] points = new Vector3[numPoints]; int[] indecies = new int[numPoints]; Color[] colors = new Color[numPoints]; for(int i=0;i<points.Length;++i) { points[i] = new Vector3(Random.Range(-10,10), Random.Range (-10,10), Random.Range (-10,10)); indecies[i] = i; colors[i] = new Color(Random.Range(0.0f,1.0f),Random.Range (0.0f,1.0f),Random.Range(0.0f,1.0f),1.0f); } mesh.vertices = points; mesh.colors = colors; mesh.SetIndices(indecies, MeshTopology.Points,0); } }
点を受け取って描画するShaderのコード↓
Shader "Custom/VertexColor" { SubShader { Pass { Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"} LOD 200 CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct VertexInput { float4 v : POSITION; float4 color: COLOR; }; struct VertexOutput { float4 pos : SV_POSITION; float4 col : COLOR; float size : PSIZE; }; VertexOutput vert(VertexInput v) { VertexOutput o; o.pos = mul(UNITY_MATRIX_MVP, v.v); o.col = v.color; o.size = 10.0; return o; } float4 frag(VertexOutput o) : COLOR { return o.col; } ENDCG } } }
そしてUnityでOpenGLのPoint Sizeコマンドを有効にするC# Scriptコード。(これはMain Cameraとかにアタッチする)↓
#if UNITY_STANDALONE #define IMPORT_GLENABLE #endif using UnityEngine; using System; using System.Collections; using System.Runtime.InteropServices; public class EnablePointSize : MonoBehaviour { const UInt32 GL_VERTEX_PROGRAM_POINT_SIZE = 0x8642; const UInt32 GL_POINT_SMOOTH = 0x0B10; const string LibGLPath = #if UNITY_STANDALONE_WIN "opengl32.dll"; #elif UNITY_STANDALONE_OSX "/System/Library/Frameworks/OpenGL.framework/OpenGL"; #elif UNITY_STANDALONE_LINUX "libGL"; // Untested on Linux, this may not be correct #else null; // OpenGL ES platforms don't require this feature #endif #if IMPORT_GLENABLE [DllImport(LibGLPath)] public static extern void glEnable(UInt32 cap); private bool mIsOpenGL; void Start() { mIsOpenGL = SystemInfo.graphicsDeviceVersion.Contains("OpenGL"); } void OnPreRender() { if (mIsOpenGL) glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); glEnable(GL_POINT_SMOOTH); } #endif }
初めて知ったけど、UnityのMeshってMeshTopologyを指定すれば三角形じゃなくてもいけるのね。
リアルタイムで動く点群をグリグリできると、スターウォーズに出てくる立体映像みたいでカッコイイね。
関連記事
Live CV:インタラクティブにComputer Visi...
MPFB2:Blenderの人体モデリングアドオン
プロシージャル手法に特化した本が出てるみたい(まだ買わないけ...
Python for Unity:UnityEditorでP...
この連休でZBrushの スキルアップを…
Mask R-CNN:ディープラーニングによる一般物体検出・...
AndroidもopenGLも初心者さ (でもJavaは知っ...
Twitter APIのPythonラッパー『python-...
GAN (Generative Adversarial Ne...
ゴジラ三昧
ZBrushのお勉強
Multi-View Environment:複数画像から3...
OpenCVで顔のランドマークを検出する『Facemark ...
Active Appearance Models(AAM)
ドラマ『ファーストクラス』のモーショングラフィックス
WordPress on Google App Engine...
顔検出・認識のAPI・ライブラリ・ソフトウェアのリスト
Google Chromecast
マイケル・ベイの動画の感覚
『スター・ウォーズ 最後のジェダイ』のVFXブレイクダウン ...
UnityのuGUIチュートリアル
自前のShaderがおかしい件
iPhone x ロボットハッカソン~RomoのiPhone...
Google App EngineでWordPress
Unityの薄い本
Unityで画面タッチ・ジェスチャ入力を扱う無料Asset『...
ブログをGoogle App EngineからAmazon ...
Google App Engine上のWordPressでA...
アニゴジ関連情報
OpenCVでカメラ画像から自己位置認識 (Visual O...
Rerun:マルチモーダルデータの可視化アプリとSDK
ZBrushCore
機械学習に役立つPythonライブラリ一覧
レンダラ制作はOpenGL とか DirectX を使わなく...
Regard3D:オープンソースのStructure fro...
ZBrushでアヴァン・ガメラを作ってみる モールドの彫り込...
ポリゴンジオメトリ処理ライブラリ『pmp-library (...
Unityで強化学習できる『Unity ML-Agents』
openMVGをWindows10 Visual Studi...
Unity MonoBehaviourクラスのオーバーライド...
Super Resolution:OpenCVの超解像処理モ...
ZBrushで仮面ライダー3号を造る 仮面編 PolyGro...
コメント
参考にさせていただきました。ありがとうございます。
そのままでは動かなかったのですが、
struct VertexOutput {
float4 pos : SV_POSITION;
float4 col : COLOR;
float4 size : PSIZE;
};
を
struct VertexOutput {
float4 pos : SV_POSITION;
float4 col : COLOR;
float size : PSIZE;
};
に書き換えたところ動きました。
すみません、書き間違えてました。
確かに、sizeはベクトルじゃなくてスカラー値ですよね。本文のコードも修正しました。