

ASUSの深度センサー「Xtion2」を使うと、身体にセンサー等のデバイスを装着することなく、人間の動きを捉えることが可能になります。
今回はXtion2で実際に3DCGのキャラクターを動かしながら、VTuberのように音声を加えて動画に仕立ててみました!
Xtion2でUnity上の3Dキャラクターを動かす仕組み
ASUSの深度センサー「Xtion2」と、画像認識プログラムを組み合わせて人間を撮影することで、人の形を認識させるとともに、人の形から推測される骨格の位置を割り出す(=骨格検出)ことができます。
この骨格の位置を3DCGモデルの骨格と紐付けることで、人の動きと3DCGモデルの動きを連動させることが可能になります。
※Xtion2を用いた骨格検出については下記の記事も参考にしてください。
“深度センサー Xtion2 を使って画面上の3Dモデルを動かす”
https://www.pc-koubou.jp/magazine/15974
OpenNI/Nuitrack/Unityの準備
事前にASUSのサイトから「OpenNI」、3DiViのサイトから「Nuitrack」をインストールしてください。
“Xtion 2 Driver & Tools | 3Dセンサー | ASUS 日本”.ASUS.
https://www.asus.com/jp/3D-Sensor/Xtion-2/HelpDesk_Download/
“Nuitrack Full Body Skeletal Tracking Software”.3DiVi Inc.
https://nuitrack.com/
また、今回3DCGキャラクターは上記のとおりUnity上で動かしますので、下記サイトからUnityをインストールし、「Asset Store」より「Nuitrack Skelton Tracking」をインポートした上で、サンプルプログラム「BasicSkeleton.unity」を起動しておいてください。
“Unity”.2019.Unity Technologies.
https://unity3d.com/jp
※セットアップの詳細は下記記事の内容も参考にしてください
“深度センサー Xtion2 を使って画面上の3Dモデルを動かす”
https://www.pc-koubou.jp/magazine/15974
Unity側の設定
3Dキャラクター「ユニティちゃん」の準備
今回動かす3DキャラクターはUnityの公式キャラクター「ユニティちゃん」を使用します。
“ABOUT | UNITY-CHAN! OFFICIAL WEBSITE”
http://unity-chan.com/contents/about/
Unityの画面左下「Assets→NuitrackSDK→Unitychan→Models」を選択し、下部中央に出てきた「unitychan」を、左上の「BasicSkeleton」にドラッグアンドドロップします。
Assets→NuitrackSDK→Unitychan→Models→unitychan の階層
NuitrackとUnityの連携設定
ユニティちゃんの準備ができたら、Nuitrackで認識した動きがUnity上のユニティちゃんの動きに反映されるように設定を行います。
今回はチュートリアルの中のプログラムをベースに動かしてみたいと思います。
まず「Assets→NuitrackSDK→Tutorials→First Project」の「NativeAvatar.cs」をダブルクリックで開いてソースコードを変更します。
「NativeAvatar.cs」をダブルクリックすると、ファイルに紐づけられたアプリケーションでコードを編集する画面(テキストエディタ等)が開きますので、以下のソースコードをコピーして「NativeAvatar.cs」に貼り付けます。
もともと「NativeAvatar.cs」に書かれていたコードはすべて削除し、下記のソースコードと入れ替え、上書き保存します。
#region Description // The script performs a direct translation of the skeleton using only the position data of the joints. // Objects in the skeleton will be created when the scene starts. #endregion using UnityEngine; using System.Collections.Generic; [AddComponentMenu("Nuitrack/Example/TranslationAvatar")] public class NativeAvatar : MonoBehaviour { string message = ""; public nuitrack.JointType[] typeJoint; GameObject[] CreatedJoint; public GameObject PrefabJoint; //↓追加 public Quaternion[] navi_Quatenion = new Quaternion[16]; void Start() { CreatedJoint = new GameObject[typeJoint.Length]; for (int q = 0; q < typeJoint.Length; q++) { CreatedJoint[q] = Instantiate(PrefabJoint); CreatedJoint[q].name = typeJoint[q].ToString(); //名前の変更に一行追加 CreatedJoint[q].transform.SetParent(transform); } message = "Skeleton created"; } void Update() { if (CurrentUserTracker.CurrentUser != 0) { nuitrack.Skeleton skeleton = CurrentUserTracker.CurrentSkeleton; message = "Skeleton found"; for (int q = 0; q < typeJoint.Length; q++) { nuitrack.Joint joint = skeleton.GetJoint(typeJoint[q]); Vector3 newPosition = 0.001f * joint.ToVector3(); CreatedJoint[q].transform.localPosition = newPosition; //↓追加 navi_Quatenion[q] = joint.ToQuaternion(); } } else { message = "Skeleton not found"; } } // Display the message on the screen void OnGUI() { GUI.color = Color.red; GUI.skin.label.fontSize = 50; GUILayout.Label(message); } }
「NativeAvatar.cs」が保存できたら、編集していたテキストエディタ等を閉じ、Unityに戻ります。
ユニティちゃんを動かすための設定
Nuitrackで捉えた動きをUnity上のキャラクターの動きに反映するための設定ができたら、先ほど読み込んだユニティちゃんの3Dモデルが実際に動くように設定を行います。
Unityの上部メニュー「GameObject」内の「Create Empty」をクリックします。
作成された「GameObject」をクリックして、右側インスペクタの「Add Component」をクリックし、「New Script」をクリックして、任意の名前を入力して「Create and Add」をクリックします。
任意の名前を入力して「Create and Add」をクリック
今回は「NewBehaviourScript」と命名する
作成したスクリプト「NewBehaviourScript」が「Assets」(NuitrackSDKの上)内にできていますので、 「NewBehaviourScript」をダブルクリックで開き、先ほどと同様にテキストエディタ等でソースコードを変更します。
「Assets」内の階層にある、先ほど作成したスクリプトファイルを開いて編集する
「NewBehaviourScript 」が開いたら、下記「NewBehaviourScript.cs」のソースコードをコピーして貼り付ける。
こちらも元のソースコードをすべて下記に入れ替え、上書き保存します。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class NewBehaviourScript : MonoBehaviour { public GameObject _UnityChan; //ユニティちゃんのボーン public GameObject Ref; public GameObject Hips; public GameObject LeftUpLeg; public GameObject LeftLeg; public GameObject RightUpLeg; public GameObject RightLeg; public GameObject Spine1; public GameObject Spine2; public GameObject LeftShoulder; public GameObject LeftArm; public GameObject LeftForeArm; public GameObject LeftHand; public GameObject RightShoulder; public GameObject RightArm; public GameObject RightForeArm; public GameObject RightHand; public GameObject Neck; public GameObject Head; public GameObject navi; public GameObject navi_Waist; Component component; Quaternion[] quaternion = new Quaternion[16]; // Use this for initialization void Start () { navi = GameObject.Find ("NativeAvatar").gameObject; //ユニティちゃんの各部位のオブジェクトの取得 _UnityChan = GameObject.Find ("unitychan").gameObject; Ref = _UnityChan.transform.FindChild("Character1_Reference").gameObject; Hips = Ref.gameObject.transform.FindChild("Character1_Hips").gameObject; LeftUpLeg = Hips.transform.FindChild("Character1_LeftUpLeg").gameObject; LeftLeg = LeftUpLeg.transform.FindChild("Character1_LeftLeg").gameObject; RightUpLeg = Hips.transform.FindChild("Character1_RightUpLeg").gameObject; RightLeg = RightUpLeg.transform.FindChild("Character1_RightLeg").gameObject; Spine1 = Hips.transform.FindChild("Character1_Spine").gameObject. transform.FindChild("Character1_Spine1").gameObject; Spine2 = Spine1.transform.FindChild("Character1_Spine2").gameObject; LeftShoulder = Spine2.transform.FindChild("Character1_LeftShoulder").gameObject; LeftArm = LeftShoulder.transform.FindChild("Character1_LeftArm").gameObject; LeftForeArm = LeftArm.transform.FindChild("Character1_LeftForeArm").gameObject; LeftHand = LeftForeArm.transform.FindChild("Character1_LeftHand").gameObject; RightShoulder = Spine2.transform.FindChild("Character1_RightShoulder").gameObject; RightArm = RightShoulder.transform.FindChild("Character1_RightArm").gameObject; RightForeArm = RightArm.transform.FindChild("Character1_RightForeArm").gameObject; RightHand = RightForeArm.transform.FindChild("Character1_RightHand").gameObject; Neck = Spine2.transform.FindChild("Character1_Neck").gameObject; Head = Neck.transform.FindChild("Character1_Head").gameObject; navi_Waist = navi.transform.FindChild("Waist").gameObject; } // Update is called once per frame void Update () { for (int i = 0;i < 16;i++) { quaternion[i] = navi.GetComponent().navi_Quatenion[i]; } Hips.transform.position = navi_Waist.transform.position; Hips.transform.rotation = quaternion[3]; Hips.transform.Rotate(0,-270,-90); Spine1.transform.rotation = quaternion[2]; Spine1.transform.Rotate(0,90,-90); LeftArm.transform.rotation = quaternion[4]; LeftArm.transform.Rotate(0,180,0); LeftForeArm.transform.rotation = (quaternion[6]); LeftForeArm.transform.Rotate(0, 180, 0); LeftHand.transform.rotation = (quaternion[8]); LeftHand.transform.Rotate(0, 180, 0); RightArm.transform.rotation = (quaternion[5]); RightForeArm.transform.rotation = (quaternion[7]); RightHand.transform.rotation = (quaternion[9]); RightUpLeg.transform.rotation = quaternion[11]; RightUpLeg.transform.Rotate(0,-90,90); RightLeg.transform.rotation = quaternion[13]; RightLeg.transform.Rotate(0,-90,90); LeftUpLeg.transform.rotation = quaternion[10]; LeftUpLeg.transform.Rotate(0, -90, 90); LeftLeg.transform.rotation = quaternion[12]; LeftLeg.transform.Rotate(0,-90,90); Neck.transform.rotation = (quaternion[1]); Neck.transform.Rotate(0, 70, -100); } }
上記を「NewBehaviourScript.cs」にペーストしたら、「NewBehaviourScript.cs」を保存してテキストエディタ等を閉じ、再度Unityに戻ります。
Unityに戻ったら「BasicSkeleton」内の「NativeAvatar」をリストの一番下にドラッグ&ドロップします。
「Native Avatar」が一番下になるようにドラッグする
現状では実際に動かした際、関節を示す赤い丸表示が表示されてしまうため、これを非表示にするために「Assets→NuitrackSDK→Tutorials→First Project→JointSphere」をクリックし、右側インスペクタの「Scale」のXYZを0にします
「JointSphere」を選択してInsepectar画面に
「Inspector」内の「Scale」のパラメーターx.y.zを0に変更する
ユニティちゃんをXtion2で動かしてみる
上記の準備ができたら、unity画面上部の実行ボタンをクリックして動作確認してみます。
Unityの画面の真ん中の再生ボタンをクリックして実行します
このように、人の動きと連動して画面内のユニティちゃんが動いてくれます。
エラーが出る場合
環境等によりエラーが表示される場合は、下記設定を行います。
まず、スクリプトの実行順を設定します。
https://docs.unity3d.com/ja/2018.1/Manual/class-MonoManager.html
Script Execution Order (スクリプト実行順設定)
(Edit > Project Settings > Script Execution Order) を使ってスクリプトの実行順を制御できます。
ホームメニューから Edit > project をクリック
「 Script Execution Order」を選択して右側の「+」ボタンを押す
リストの中から「NativeAvator」と「NewBehaviourScript」←(先ほど命名した名前)を選択
二つ選んだあとの最終的な画面(追加されていることを確認)したあとに
「Apply」ボタンをクリック
背景とナレーションを加えてVTuber風に仕上げる
Xtion2でユニティちゃんを動かすことができたら、背景とナレーションを入れてVTuber風の動画に仕上げてみましょう。
背景の設定
今回はAsset Store内にある「Skybox Series Free」という素材を使用します。「Asset Store」>「All Assets」>「Textures & Materials」>「Skybox Series Free」を選択し、「Download」ボタンをクリック後、「Import」ボタンをクリックして読み込みます。
「Asset store」に入りAll Assetsの部分をクリック
リストの中から「Texture&Materials」を選択する
「Skybox Series Free」を選択、DownloadしてImportする
読み込み後、数ウィンドウが開きますので右下「Import」をクリックします。
Importが終わると、別ウインドウが開くので「Import」を押す
「Window」メニューから「Rendering」>「Lighting Settings」の順にクリックします。
「window」メニュー>「Rendering」>「Lighting Settings」の順でクリック
下図のような別ウィンドウが開きますので、右上の「Skybox Material」右にある丸い部分(下図赤枠)をクリックします。
表示された「Select Material」ウィンドウから好みの背景をクリックすると、ゲームウィンドウ内に背景が反映されます(下図)。
VTuber風動画完成
背景が入ったらあらためて実際に人の動きと連携させて動かしてみます。
最近はこのような3Dキャラクターを自分の代わりに画面に登場させた動画を配信するVTuberと呼ばれる方が出てきていますが、今回の動画に声を付けてVTuber風(?)に仕上げてみました。
おじさん声ではありますが……なんとなくそれらしい動画になった気がします。
Xtion2ならではのコンテンツ作りに挑戦しよう!
Xtion2で動かしたUnity上のキャラクターにナレーションを入れて上記動画のような形まで作成してきましたが、キャラクターを変えたり(もちろん声も)背景にこだわると、本格的なVTuberのようなコンテンツが作れそうです。
身体にセンサー等をなにも付けずに身体の動きを反映できるXtion2ならではのコンテンツ作りに是非挑戦してみてください。
※今回登場したキャラクター「ユニティちゃん」はユニティちゃんライセンス条項の元に提供されています。
[ネクスマグ] 編集部
パソコンでできるこんなことやあんなこと、便利な使い方など、様々なパソコン活用方法が「わかる!」「みつかる!」記事を書いています。