自習室

こもります

Kinect Wrapper Package for Unity3D をつかってみる

前置き

本記事は、以下の2記事を参考に、Kinect for Windows をUnity上で使ってみたときのメモです。作例は次回以降の記事に任せて、この記事では利用法の記録に徹します。

Kinect でお手軽に頭の位置とカメラ位置を連動させて Oculus Rift をもっと楽しむ - 凹みTips

KINECT SDKを使う その1・環境設定編 - Unityな日々(Unity Geek)

利用するのはこちらのライブラリです。

Microsoft Kinect - Microsoft SDK - Unity3D

Carnegie Mellon 大学大学院の Entertainment Technology Center (ETC) のプロジェクトとして公開されています。cmuは OmniTouchなど、いくつかのKinectがらみの研究をMicrosoftと共同で行ってたりしますし、もしかすると、ほぼ公式ラッパーなのかもしれません。

OmniTouch - Demo Video - ACM UIST 2011 - YouTube

基本的な使い方

書いてあるとおりですが、

  1. Kinect for Windows をセットアップする(詳細は省きます)
  2. サイトからKinect Wrapper Package for Unity3D をDLし
  3. UnityのProjectにインポートします
  4. Projectビュー中 Sceneから KinectSample シーンを開いて
  5. 実行

で、こうなります。

f:id:AMANE:20140217224504p:plain

ライブラリのバージョン

現在配布されているこのラッパーは、Kinect for Windows SDK v1.7 対応と言うことになっていますが、私の環境では、最新のv1.8で機能しています。

本ライブラリの機能

このサンプルでは、このラッパーの基本機能のうち、以下の物が実装されています。

KinectPrefab

基本となるパーツ。

KinectSensor.cs

ハードウェアKinectのセッティングをするスクリプト

  • sensorHeight, KinectCenter, LookAt の値を変更することで、Unity中の仮想的なKinectの位置を決めたり、Kinectのモータを動かして向きを変えることが可能。自分の理解と実装が異なる部分があったので、ここでは説明省かせていただきます。

  • Smoothing Correction Prediction JitterRadius MaxDeviationRaidus は、Skeletonデータの平滑化などのフィルタ計数。詳細はこちら Joint Filtering

  • Tracking Mode を指定可能。詳細は不明。公式の関連項目はこちら、かな? SkeletonStream.TrackingMode Property

KinectRecorder.cs

インスペクタ上で出力先を指定して、このソフトを実行中に F10 で録画・停止。ここで録画したデータを、エミュレータで再生が出来ます。

KinectEmulator.cs / DeviceOrEmulator.cs

レコードした動きを読み込んで、Kinectの前で動く代わりに使うことが出来る。 Device Or Emulator のUse Emulator をチェックし、Kinect Emulator の Input File に先ほど録画した動きのデータを指定。実行中に F12 で再読込。

SkeletonWrapper.cs

Kinect のスケルトントラッキングのデータを取り回すラッパ。サンプル中のPointMan や rainbowMan は、SkeletonWrapperからデータを受け取って動かします。

DepthWrapper.cs

Kinect のデプス画像のデータを取り回すラッパ

ColorImagePlane

f:id:AMANE:20140219113621p:plain

カラーイメージは、KinectSensor自体がハンドリングしています。 DisplayColor.cs にインスペクタからKinectPrefabを指定してあげれば、カラー画像を取得できるようになります。ここではPlane Meshを一枚作って、kinect.getColor() した画像データを、Plane Mesh のマテリアルのテクスチャに変換することで、描画しています。

DepthImagePlane

カラーイメージは、先述のDepthWrapperがハンドリングしています。DepthWrapper.depthImage で画像データを取得したのち、ColorImageの時と同様に、Plane Meshのマテリアルのテクスチャに変換・登録しています。この際、デプスのshort配列データを、適当にグレースケースの画像に変換しています。

また、インスペクタに目を戻すと、ColorIimagePlaneのときと全く同じように、Display Depthコンポーネントのdwという枠に KinectPrefab を登録していますが、これは、DisplayDepth.cs内部で、登録したKinectPrefab 中に含まれる DepthWrapper オブジェクトを見つけて、メンバとして利用できている、ということです。このあたりはUnity賢いですね。

f:id:AMANE:20140219113349p:plain

KinectPointMan

Kinectが出力する人のSkeletonの関節座標に、Sphereを描く、という単純なスクリプトKinectPointController.cs をくっつけたPrefabです。ソースを見ると、KinectのSkeletonデータを更新させたり、値を取得してくる方法が分かります。

// KinectPointController.cs より
void Update () {
    if(player == -1)
        return;
    //update all of the bones positions
    if (sw.pollSkeleton())
    {
        for( int ii = 0; ii < (int)Kinect.NuiSkeletonPositionIndex.Count; ii++) {
            //_bonePos[ii] = sw.getBonePos(ii);
            if( ((uint)Mask & (uint)(1 << ii) ) > 0 ){
                //_bones[ii].transform.localPosition = sw.bonePos[player,ii];
                _bones[ii].transform.localPosition = new Vector3(
                    sw.bonePos[player,ii].x * scale,
                    sw.bonePos[player,ii].y * scale,
                    sw.bonePos[player,ii].z * scale);
            }
        }
    }
}

SkeletonWrapper.pollSkeleton() で、スケルトン情報を更新したうえで SkeletonWrapper のpublicな変数たちにアクセスして具体的な値を取得します。最大2名分まで取得可能です。

  • Vector3[] bonePos : 関節位置
  • Vector3[] boneVel : 関節の移動速度ベクトル
  • Quaternion[] boneAbsoluteOrientation : 関節の回転姿勢

など。 最もシンプルな応用として、関節座標をつかって、自分の腕の向く先のベクトルを算出したり、顔の位置・向きを使ってUnityのカメラを動かす、と言うことが出来ます。

rainbowMan_v6

人型のメッシュ(見た目は標準Skeletonそのものですが…)に、Rig(ジョイント階層、骨格のモデル)を適用した物に、それをKinectが出力するSkeletonのデータで動かすスクリプト KinectModelControllerV2.cs をくっつけたPrefabです。ソースを見ると、ジョイントの回転なども含めて正確にモデルを動かすための方法が分かります。

メッシュとリグの関係についてはこの辺参照

オリジナルキャラクターを準備する / Preparing your own character

さいごに

Unityで人を動かせるようになると、CharacterのCG作りに興味が湧いてきますね。Blenderとかやるべきなのでしょうか。。また、座標変換周りもまだまだ不勉強で理解出来ていないところが多いことに気づかされました。

次は、これを使って何か作ってみようと思います。