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を指定すれば三角形じゃなくてもいけるのね。
リアルタイムで動く点群をグリグリできると、スターウォーズに出てくる立体映像みたいでカッコイイね。
関連記事
映画から想像するVR・AR時代のGUIデザイン
『パシフィック・リム: アップライジング』のVFXブレイクダ...
ZBrushでアヴァン・ガメラを作ってみる
タマムシっぽい質感
OpenVDB:3Dボリュームデータ処理ライブラリ
JavaScriptとかWebGLとかCanvasとか
Point Cloud Libraryに動画フォーマットが追...
Model View Controller
SSII 2014 デモンストレーションセッションのダイジェ...
Pythonのソースコードに特化した検索エンジン『Nulle...
フルCGのウルトラマン!?
3Dグラフィックスの入門書
Unityをレンダラとして活用する
SSD (Single Shot Multibox Dete...
WordPressのテーマを自作する
OpenMVS:Multi-View Stereoによる3次...
ZBrushでカスタムUIを設定する
Point Cloud Utils:Pythonで3D点群・...
3D映画のポストプロダクション 2D-3D変換
AR (Augmented Reality)とDR (Dim...
ZBrushでゴジラ2001を作ってみる 身体のバランスを探...
Python拡張モジュールのWindows用インストーラー配...
サンプルコードにも間違いはある?
ニンテンドー3DSのGPU PICA200
ポリゴンジオメトリ処理ライブラリ『pmp-library (...
ニューラルネットワークと深層学習
trimesh:PythonでポリゴンMeshを扱うライブラ...
Alice Vision:オープンソースのPhotogram...
Physics Forests:機械学習で流体シミュレーショ...
NeRF (Neural Radiance Fields):...
CGのためのディープラーニング
自前のShaderがおかしい件
openMVGをWindows10 Visual Studi...
Runway ML:クリエイターのための機械学習ツール
法線マップを用意してCanvas上でShadingするサンプ...
ZBrushでアヴァン・ガメラを作ってみる 甲羅のバランス調...
NumSharp:C#で使えるNumPyライクな数値計算ライ...
『ハン・ソロ/スター・ウォーズ・ストーリー』のVFXブレイク...
布地のシワの法則性
UnityでARKit2.0
UnityでTweenアニメーションを実装できる3種類の無料...
Iterator
コメント
参考にさせていただきました。ありがとうございます。
そのままでは動かなかったのですが、
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はベクトルじゃなくてスカラー値ですよね。本文のコードも修正しました。