サイトアイコン NegativeMindException

UnityでPoint Cloudを表示する方法

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を指定すれば三角形じゃなくてもいけるのね。

リアルタイムで動く点群をグリグリできると、スターウォーズに出てくる立体映像みたいでカッコイイね。


スポンサーリンク

関連記事

  • Python.NET:Pythonと.NETを連携させるパッケージ
  • オープンソースのロボットアプリケーションフレームワーク『ROS (Robot Operating S...
  • 『ハン・ソロ/スター・ウォーズ・ストーリー』のVFXブレイクダウン まとめ
  • WordPressのサーバ引っ越し方法を考える
  • OpenCV3.3.0でsfmモジュールのビルドに成功!
  • ZScript
  • WordPressのテーマを自作する
  • iOSデバイスのためのフィジカル・コンピューティングツールキット『konashi(こなし)』
  • 単純に遊びに行くのはだめなのか?
  • Unite 2014の動画
  • MPC社によるゴジラ(2014)のVFXブレイクダウン
  • マルコフ連鎖モンテカルロ法
  • Polyscope:3Dデータ操作用GUIライブラリ
  • 白組による『シン・ゴジラ』CGメイキング映像が公開された!
  • OpenCVのfindEssentialMat関数を使ったサンプルを読んでみる
  • NICOGRAPHって有名?
  • AfterEffectsプラグイン開発
  • リメイク版ロボコップスーツのメイキング
  • Adobeの手振れ補正機能『ワープスタビライザー』の秘密
  • ヒーローに変身なりきりアーケードゲーム『ナレルンダー』
  • OpenMVSのサンプルを動かしてみる
  • 書籍『メイキング・オブ・ピクサー 創造力をつくった人々』を読んだ
  • 書籍『ゼロから作るDeep Learning』で自分なりに学ぶ
  • ZBrushでアマビエを作る その2
  • 3Dグラフィックスの入門書
  • Mean Stack開発の最初の一歩
  • Arduinoで人感センサーを使う
  • Unityで画面タッチ・ジェスチャ入力を扱う無料Asset『TouchScript』
  • Unityの各コンポーネント間でのやり取り
  • ZBrushでゴジラ2001を作ってみる 身体のSubToolを分割
  • TorchStudio:PyTorchのための統合開発環境とエコシステム
  • 仮想関数
  • Raspberry PiのGPIOを操作するPythonライブラリ『RPi.GPIO』の使い方
  • バージョン管理の履歴を可視化するツール『Gource』
  • OpenCVで顔のランドマークを検出する『Facemark API』
  • オープンソースの取引プラットフォーム
  • Stanford Bunny
  • 素敵なパーティクル
  • 第1回 3D勉強会@関東『SLAMチュートリアル大会』
  • OpenMesh:オープンソースの3Dメッシュデータライブラリ
  • 網元AMIで作ったWordpressサイトのインスタンスをt1microからt2microへ移行した
  • この連休でZBrushの スキルアップを…
  • モバイルバージョンを終了