13
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

解散Advent Calendar 2017

Day 7

KinectでUnityちゃんを動かす

Posted at

前回の続きを書いていきます!
今回はUnityちゃんを動かしていこうと思います

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

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

#1.Unityちゃんインポート
キャプチャ.PNG

Assets>UnityChan>Modelsの中にモデルが入っているのでHierarchyに置いちゃいましょう
キャプチャ.PNG

遠いのでカメラを近づけます
-3くらいでいいですかね
キャプチャ.PNG

#2.kinect側の準備
前回の記事にあったKinectViewフォルダのMainSceneを開いて、BodyManagerをプレファブ化しちゃいます
キャプチャ.PNG

このプレファブ化したBodyManagerを先ほどUnityちゃんを出したシーンのHierarchyに入れます
キャプチャ.PNG

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

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

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.コードを最低限の部分だけ書く
今回は記事を参考にしますが、分かりやすくするために本当に最低限の部分だけ書いていきます

流れとしては

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

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

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

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の拡張クラスとして定義します(記事参照)

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スクリプトを作ります
今回はミラーなどを省きました!

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
この青い部分がUnityちゃんのボーン部分です!

名前を照らし合わせて入れていきます
キャプチャ.PNG
こんな感じです

そして最後にBodySorceManagerの場所にBodySorceManagerオブジェクトを入れましょう
キャプチャ.PNG

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

13
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?