KinectでUnityちゃんを動かす

<a href="https://qiita.com/yuzupon/items/4528f7fc09a42fb8af2e">前回</a>の続きを書いていきます！
今回はUnityちゃんを動かしていこうと思います

↓参考にした記事です↓
http://www.buildinsider.net/small/bookkinectv2/0703

#もくじ
1.Unityちゃんインポート
2.kinect側の準備
3.コードを最低限の部分だけ書く


#1.Unityちゃんインポート
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/191497/5874413b-78d6-a322-253f-31fa77ba7d41.png)

Assets>UnityChan>Modelsの中にモデルが入っているのでHierarchyに置いちゃいましょう
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/191497/0456041b-37cb-ae9b-43af-75b664f04566.png)

遠いのでカメラを近づけます
-3くらいでいいですかね
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/191497/3e696dad-d0f3-1877-3994-e3ef31058ce9.png)

#2.kinect側の準備
<a href="https://qiita.com/yuzupon/items/4528f7fc09a42fb8af2e">前回</a>の記事にあったKinectViewフォルダのMainSceneを開いて、BodyManagerをプレファブ化しちゃいます
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/191497/0d378de3-1d75-a584-b26a-786cbcbd0285.png)

このプレファブ化したBodyManagerを先ほどUnityちゃんを出したシーンのHierarchyに入れます
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/191497/1da987d3-c14b-d826-0109-ecb11317060f.png)

これでKinect側の準備はOKです！

せっかくなのでBodyManagerにアタッチされているBodySourceManagerの中身をざっくり紹介します

```C#:BodySourceManager.cs
using UnityEngine;
using System.Collections;
using Windows.Kinect;

public class BodySourceManager : MonoBehaviour 
{
    private KinectSensor _Sensor;
    private BodyFrameReader _Reader;
    private Body[] _Data = null;//認識した体の情報がはいります(最大6人)
    
    public Body[] GetData()
    {
        return _Data;
    }
    
    void Start () //Kinectを開く系の処理をしています
    {
        _Sensor = KinectSensor.GetDefault();

        if (_Sensor != null)
        {
            _Reader = _Sensor.BodyFrameSource.OpenReader();
            
            if (!_Sensor.IsOpen)
            {
                _Sensor.Open();
            }
        }   
    }
    
    void Update () 
    {
        if (_Reader != null)
        {
            var frame = _Reader.AcquireLatestFrame();
            if (frame != null)
            {
                if (_Data == null)//取得した体の情報を入れている
                {
                    _Data = new Body[_Sensor.BodyFrameSource.BodyCount];
                }
                
                frame.GetAndRefreshBodyData(_Data);
                
                frame.Dispose();
                frame = null;
            }
        }    
    }
    
    void OnApplicationQuit()//アプリ終了時に呼ばれる関数
    {
        if (_Reader != null)//BodyFrameReaderを破棄
        {
            _Reader.Dispose();
            _Reader = null;
        }
        
        if (_Sensor != null)//キネクトを停止
        {
            if (_Sensor.IsOpen)
            {
                _Sensor.Close();
            }
            
            _Sensor = null;
        }
    }
}

```
今回大切なのが、Bodyのデータです
これを使えば結構色々なことできます

#3.コードを最低限の部分だけ書く
今回は<a href="http://www.buildinsider.net/small/bookkinectv2/0703">記事</a>を参考にしますが、分かりやすくするために本当に最低限の部分だけ書いていきます

流れとしては

・最初に追尾した人のBodyデータを取得する
・そのBodyデータに基づいてUnityちゃんを動かす

てな感じでいってみようと思います

まず、BodySourceManagerスクリプトに次のコードを追加します
キネクトを傾かせて置いたときの対策です(記事参照)

```C#:BodySourceManager.cs
public class BodySourceManager : MonoBehaviour
{
 //～中略～
  public Windows.Kinect.Vector4 FloorClipPlane
  {
    get;
    private set;
  }

  void Update () 
  {
    if (_Reader != null) 
    {
      var frame = _Reader.AcquireLatestFrame();
      if (frame != null) 
      {
        if (_Data == null) 
        {
          _Data = new Body[_Sensor.BodyFrameSource.BodyCount];
        }

        frame.GetAndRefreshBodyData(_Data);

        // FloorClipPlaneを取得する
        FloorClipPlane = frame.FloorClipPlane;

        frame.Dispose();
        frame = null;
      }
    }
  }
}
```

お次にVectorExtensionsスクリプトを作成し、Vector4の拡張クラスとして定義します(記事参照)

```C#:VectorExtensions.cs
using UnityEngine;

public static class VectorExtensions
{
  public static Quaternion ToQuaternion( this Windows.Kinect.Vector4 vactor, Quaternion comp )
  {
    return Quaternion.Inverse( comp ) * 
             new Quaternion( -vactor.X, -vactor.Y, vactor.Z, vactor.W );
  }

  public static Windows.Kinect.Vector4 ToMirror( this Windows.Kinect.Vector4 vector )
  {
    return new Windows.Kinect.Vector4() 
    {
      X = vector.X, 
      Y = -vector.Y, 
      Z = -vector.Z, 
      W = vector.W
    };
  }
}
```

KinectAvatarスクリプトを作ります
今回はミラーなどを省きました！

```C#:KinectAvatar.cs
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Windows.Kinect;

public class KinectAvatar : MonoBehaviour {
    [SerializeField]
    BodySourceManager bodySourceManager;

    //自分の関節とUnityちゃんのボーンを入れるよう
    [SerializeField] GameObject Ref;
    [SerializeField] GameObject LeftUpLeg;
    [SerializeField] GameObject LeftLeg;
    [SerializeField] GameObject RightUpLeg;
    [SerializeField] GameObject RightLeg;
    [SerializeField] GameObject Spine1;
    [SerializeField] GameObject LeftArm;
    [SerializeField] GameObject LeftForeArm;
    [SerializeField] GameObject LeftHand;
    [SerializeField] GameObject RightArm;
    [SerializeField] GameObject RightForeArm;
    [SerializeField] GameObject RightHand;

    // Use this for initialization
    void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
        //最初に追尾している人のBodyデータを取得する
        Body body = bodySourceManager.GetData().FirstOrDefault(b => b.IsTracked);

        // Kinectを斜めに置いてもまっすぐにするようにする
        var floorPlane = bodySourceManager.FloorClipPlane;
        Quaternion comp = Quaternion.FromToRotation(
            new Vector3(-floorPlane.X, floorPlane.Y, floorPlane.Z), Vector3.up);

        Quaternion SpineBase;
        Quaternion SpineMid;
        Quaternion SpineShoulder;
        Quaternion ShoulderLeft;
        Quaternion ShoulderRight;
        Quaternion ElbowLeft;
        Quaternion WristLeft;
        Quaternion HandLeft;
        Quaternion ElbowRight;
        Quaternion WristRight;
        Quaternion HandRight;
        Quaternion KneeLeft;
        Quaternion AnkleLeft;
        Quaternion KneeRight;
        Quaternion AnkleRight;

        Quaternion q;
        Quaternion comp2;
        CameraSpacePoint pos;

        // 関節の回転を取得する
        if (body != null)
        {
            var joints = body.JointOrientations;

            //Kinectの関節回転情報をUnityのクォータニオンに変換
            SpineBase = joints[JointType.SpineBase].Orientation.ToQuaternion(comp);
            SpineMid = joints[JointType.SpineMid].Orientation.ToQuaternion(comp);
            SpineShoulder = joints[JointType.SpineShoulder].Orientation.ToQuaternion(comp);
            ShoulderLeft = joints[JointType.ShoulderLeft].Orientation.ToQuaternion(comp);
            ShoulderRight = joints[JointType.ShoulderRight].Orientation.ToQuaternion(comp);
            ElbowLeft = joints[JointType.ElbowLeft].Orientation.ToQuaternion(comp);
            WristLeft = joints[JointType.WristLeft].Orientation.ToQuaternion(comp);
            HandLeft = joints[JointType.HandLeft].Orientation.ToQuaternion(comp);
            ElbowRight = joints[JointType.ElbowRight].Orientation.ToQuaternion(comp);
            WristRight = joints[JointType.WristRight].Orientation.ToQuaternion(comp);
            HandRight = joints[JointType.HandRight].Orientation.ToQuaternion(comp);
            KneeLeft = joints[JointType.KneeLeft].Orientation.ToQuaternion(comp);
            AnkleLeft = joints[JointType.AnkleLeft].Orientation.ToQuaternion(comp);
            KneeRight = joints[JointType.KneeRight].Orientation.ToQuaternion(comp);
            AnkleRight = joints[JointType.AnkleRight].Orientation.ToQuaternion(comp);

            // 関節の回転を計算する 
            q = transform.rotation;
            transform.rotation = Quaternion.identity;

            comp2 = Quaternion.AngleAxis(90, new Vector3(0, 1, 0)) *
                             Quaternion.AngleAxis(-90, new Vector3(0, 0, 1));

            Spine1.transform.rotation = SpineMid * comp2;

            RightArm.transform.rotation = ElbowRight * comp2;
            RightForeArm.transform.rotation = WristRight * comp2;
            RightHand.transform.rotation = HandRight * comp2;

            LeftArm.transform.rotation = ElbowLeft * comp2;
            LeftForeArm.transform.rotation = WristLeft * comp2;
            LeftHand.transform.rotation = HandLeft * comp2;

            RightUpLeg.transform.rotation = KneeRight * comp2;
            RightLeg.transform.rotation = AnkleRight * comp2;

            LeftUpLeg.transform.rotation = KneeLeft *
                            Quaternion.AngleAxis(-90, new Vector3(0, 0, 1));

            LeftLeg.transform.rotation = AnkleLeft *
                            Quaternion.AngleAxis(-90, new Vector3(0, 0, 1));

            // モデルの回転を設定する
            transform.rotation = q;

            // モデルの位置を移動する
            pos = body.Joints[JointType.SpineMid].Position;
            Ref.transform.position = new Vector3(-pos.X, pos.Y, -pos.Z);
        }
    }
}

```

それではこのKinectAvatarスクリプトをUnityちゃんにアタッチし、シリアライズの部分を入れていきます！

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/191497/4992dfcb-0bfc-09f6-da83-0c07b7cb4f5a.png)
この青い部分がUnityちゃんのボーン部分です！

名前を照らし合わせて入れていきます
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/191497/a4c9fc1c-ff2d-c8a6-e18a-5f8bf40dd32e.png)
こんな感じです

そして最後にBodySorceManagerの場所にBodySorceManagerオブジェクトを入れましょう
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/191497/b7318d67-b32b-ce09-55a4-592d5ce6a291.png)

これで準備は完了のはず！！
カレンダーの時間ちょっとすぎてしまったんでまた更新します！！
では！