Unity+Vuforia+MMD4Mecanimで初音ミクが踊るAndroid用ARアプリを作ってみた
UnityでARアプリが簡単に作れると知って、ちょっと試してみたら、案外簡単にできた。その作り方を簡単なメモとして記録しておく。
作ったARアプリはAndroidアプリ。ARマーカーをカメラで映すと、初音ミクが曲に合わせて踊るというもの。カメラ機能で撮影も可能。CDのジャケットでもARマーカーにできると思う。
曲はラマーズPのWAVEFILEで、モーションはhinoさん作成のもの、モデルはコロン式初音ミクをお借りしました。
ARマーカーは、特徴点が抽出できる絵なら何でも良いようなので、ボカロ関連のイベントを集めたサイトVOCALENDARの宣伝用カードを利用(ステルスマーケティング)。
所要日数は、初めてUnityをインストールしてからチュートリアルで基礎を勉強する期間も含めて2日間かかった。
開発手順
以下、開発手順を箇条書き。
- Unityのプロジェクトを新規作成
- MMD4Mecanim関連の手順 (ここを参考に)
- MMD4Mecanimのパッケージをインポート
- MMDモデル(PMX)とモーション(VMD)、曲の音声ファイル(mp3)をプロジェクトにインポート
- PMX2FBXでPMX(とVMD)をFBXに変換
- Vuforia関連の手順 (ここを参考に)
- 統合手順
以上で、アプリの基本形は作成完了。あとは適用先のプラットフォームにAndroidを選択してビルドすれば完成。
さらに下記のスクリプトを追加して、さらに機能を作り込んだ。
ARマーカーが写っている間だけ動く
ARマーカーが写っている間だけ初音ミクが歌い踊る形にするため、ITrackableEventHandlerスクリプトを作成。
Vuforia SDKが提供するDefaultTrackableEventHandlerを元に、下記のスクリプトを作成。ImageTargetに適用した。
using UnityEngine; public class ColonMikuTrackableEventHandler : MonoBehaviour, ITrackableEventHandler { private TrackableBehaviour mTrackableBehaviour; private AudioSource mAudioSource; private Animator mAnimator; void Start() { mTrackableBehaviour = GetComponent<TrackableBehaviour>(); if (mTrackableBehaviour) { mTrackableBehaviour.RegisterTrackableEventHandler(this); } mAudioSource = FindObjectOfType<AudioSource>(); mAnimator = FindObjectOfType<Animator>(); if(mAnimator != null) { mAnimator.speed = 0; } } public void OnTrackableStateChanged( TrackableBehaviour.Status previousStatus, TrackableBehaviour.Status newStatus) { if (newStatus == TrackableBehaviour.Status.DETECTED || newStatus == TrackableBehaviour.Status.TRACKED || newStatus == TrackableBehaviour.Status.EXTENDED_TRACKED) { OnTrackingFound(); } else { OnTrackingLost(); } } private void OnTrackingFound() { Renderer[] rendererComponents = GetComponentsInChildren<Renderer>(true); Collider[] colliderComponents = GetComponentsInChildren<Collider>(true); // Enable rendering: foreach (Renderer component in rendererComponents) { component.enabled = true; } // Enable colliders: foreach (Collider component in colliderComponents) { component.enabled = true; } if(mAudioSource != null) { mAudioSource.Play(); } if(mAnimator != null) { mAnimator.speed = 1; } } private void OnTrackingLost() { Renderer[] rendererComponents = GetComponentsInChildren<Renderer>(true); Collider[] colliderComponents = GetComponentsInChildren<Collider>(true); // Disable rendering: foreach (Renderer component in rendererComponents) { component.enabled = false; } // Disable colliders: foreach (Collider component in colliderComponents) { component.enabled = false; } if(mAudioSource != null) { mAudioSource.Pause(); } if(mAnimator != null) { mAnimator.speed = 0; } Debug.Log("Trackable " + mTrackableBehaviour.TrackableName + " lost"); } }
撮影ボタンと終了処理
画面を撮影するボタンの追加と、戻るボタンでアプリを終了する処理のため、下記のスクリプトを作成。空のGameObjectを作成して、このスクリプトを適用した。
撮影には、スクリーンキャプチャをpngで保存するUnityのAPI、Application.CaptureScreenshot()を使用。
using UnityEngine; using System.Collections; // キー操作 public class KeyControllScript : MonoBehaviour { private Rect mShotButtonRect; void Start() { float w = 80; float h = 50; mShotButtonRect = new Rect( (float)(Screen.width/2 - w/2), (float)(Screen.height - h * 1.1), w, h); } // Update is called once per frame void Update () { if(Input.GetKey(KeyCode.Escape)) { Application.Quit(); } } void OnGUI() { if(GUI.Button(mShotButtonRect, "Shot")) { string path = ""; if(SystemInfo.operatingSystem.Contains("Android")) { path = "../../../../DCIM/Camera/"; } path = path + "screenshot" + System.DateTime.Now.Ticks.ToString() + ".png"; Application.CaptureScreenshot(path); } } }
撮影した写真は、SDカードの "DCIM/Camera" 以下に格納される。
SDカードに書き込むには、Androidアプリにpermissionを設定する必要がある。
プロジェクトの "Assets/Plugins/Android/AndroidManifest.xml" に、下記のエントリを
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />