HoloLensハンズオン
キャラと音声対話をしてみよう!
自己紹介
氏名:井出 将弘
所属:TIS 株式会社 戦略技術センター
Twitter&Qiita:@decchi
元々は今は亡きGoogle TangoからARに興味を持ち、Mikulusの体験
から本格的にAR/MR/VRの世界にのめりこむ。
現在はMR対話エージェント(今日のハンズオンで作るもの)を中心に
研究開発をしています。
ハンズオンを始める前に
事前準備は完了していますか?
事前準備は以下にあります!
Tech-Circle HoloLensハンズオン 音声対話をしてみよう!(事前準備編)
https://qiita.com/decchi/items/78f3ce00b2c3ecedfc79
ハンズオンを始める前に
コマンドプロントでクローンした
OrenoYome_Hands_Onのプロジェクトに移動し、
①git fetch origin master
②git reset --hard origin/master
で最新を取得してください。
ハンズオン始めます!
事前準備が終わってUnityエディタはこうなっていま
すか?
とりあえずUnityちゃん召喚
召喚イメージ
エアータップ
召喚準備①
今のシーンにはカメラがないので、配置します。
HoloToolkit¥Input¥Prefabs¥HoloLensCamera
のプレハブをHierarchyビューに配置
召喚準備②
配置したHoloLensCameraのInspectorビューを開き、
NearClipを0.01にしてUnityちゃんが近づいてもポリ
ゴンが欠けないようにします。
召喚準備③
エアータップを検出するために
HoloToolkit¥Input¥Prefabs¥InputManagerの
プレハブをHierarchyビューに配置
召喚準備④
配置したInputManagerの子要素として
EventSystemを追加する。
召喚準備⑤
UnityChan¥Prefabs¥unitychanのプレハブを
Hierarchyビューに配置してUnityちゃんをシーンに登
場させます。
召喚準備⑥
Unityちゃんのアニメーションをあらかじめ用意してあ
るWalkControllerに変更し、エラーになっている不要
なスクリプトを削除します。
召喚準備⑦
まだUnityちゃんを動かさないですが、 Unityちゃんに
NavMeshAgentのコンポーネントを追加しておきます。
デフォルトだと移動速度が速いので、Speedの値を
0.75に設定しておきます。Obstacle Avoidanceも0.3
を設定。
召喚準備⑧
HoloToolkit¥SpatialMapping¥Prefabs¥Spatial
MappingのプレハブをHierarchyビューに配置し、空
間認識を使えるようにします。
召喚準備⑨
あらかじめシーンに用意しておいたSingletonオブ
ジェクトにYomeControlerとSetGlobalListenerを
追加して、 YomeControler のYomeの値に
HierarchyビューのUnityちゃんを設定する。
スクリプト解説
YomeControler:キャラクターの動きに関するクラス。
IInputClickHandlerを継承することでエアータップイ
ベントを実装している。また、Singletonを継承し、他の
クラスからキャラクターの動きに関するメソッドを呼び
やすくしている。
SetGlobalListener:アタッチしたオブジェクトに設定
されているスクリプトのジェスチャーイベントが、特定
のオブジェクトをGazeしなくても実行されるようになる。
召喚準備⑩
注視点をわかりやすくするためにカーソルを追加。
HoloToolkit¥Input¥Prefabs¥Cursor¥ DefaultCu
rsorのプレハブをHierarchyビューに配置。
召喚してみる
これで一旦召喚できるようになったので、Holographic
Emulationか実機デプロイでUnityちゃんを召喚でき
るか試してみましょう(まだ出てくるだけです)
キャラとの音声対話の実装
実装イメージ
音声認識
音声合成
対話システム
音声認識したテキスト
回答のテキスト
音声対話の実装①
まずは音声認識、回答のテキストを表示するためのUIを
追加する。
OrenoYome¥PrefabにあるFukidashiUIと
YomeFukidashiUIのプレハブをそれぞれHierarchy
ビューに配置する。YomeFukidashiUIはUnityちゃん
の子要素として配置する。
音声対話の実装②
Unityちゃんに音声を発話させるためAudioSourceを
追加する。
音声対話の実装③
Singletonオブジェクトに音声合成スクリプトの
TextToSpeechManagerを追加する。
AudioSourceにはUnityちゃんのAudioSourceを、
VoiceはZiraを設定する。
音声対話の実装④
Singletonオブジェクトに対話機能を実装する
ConversationManagerを追加する。
ConversationManagerの各値を以下の通り設定する。
音声対話の実装⑤
ConversationManagerをEditScriptで開き、音声認
識、対話サービスとの連携、音声合成を実装します。
これについてはQiita記事にまとめていますので、そちら
を参照します。
Holoの嫁と会話するためのステップバイステップ
https://qiita.com/decchi/items/f4766d6f45da0e59639b
音声対話の実装⑥
音声認識の実装についてはQiita記事の「音声をテキス
トに変換する(Speech to Text)」の項にまとめています
ので参照してください。その後ConversationManager
のStep1のコメントの下に実装してきましょう。実装する
内容は以下の通りです。(次ページに実装の答えあり)
①m_DictationRecognizerの変数にインスタンスを設定
②m_DictationRecognizerにDictationResultのイベントを設定
③DictationResultのイベントに以下の処理を追加
③-1 inputTextField.textに音声認識したテキストを設定
③-2 GetReplyメソッドをStartCoroutineで起動し、引数に音声認識
したテキストを渡す。
④ m_DictationRecognizer.Start()で音声認識を開始する。
音声対話の実装⑦
答え
public void Initialize()
{
//Step1 音声認識の実装
m_DictationRecognizer = new DictationRecognizer();
m_DictationRecognizer.DictationResult += (text, confidence) =>
{
inputTextField.text = text;
//通信するためのメソッドはCoroutineで呼び出します。
StartCoroutine(GetReply(text));
};
m_DictationRecognizer.Start();
XPic.gameObject.SetActive(false);
}
音声対話の実装⑧
次にStep2として対話システムと連携します。 Qiita記
事の「対話サービスに発話内容を送信する」の項にまと
めていますので参照してください。
Step2の実装はあらかじめ用意したエージェントを利用します。
ConversationManager のStep2のコメントの箇所についてエージェントの
キーを設定します。
(set key here)のところを入れ替えます。
今回のハンズオンのキーは以下を使用します。
6e69b55263ca4831aec888e3a1c97a4b
※キーは2017/10/4現在の値なので、今後変更されている可能性がありま
す。ご了承ください。
音声対話の実装⑨
答え
//Step2 対話エージェントの設定
request.SetRequestHeader("Authorization", "Bearer 6e69b55263ca4831aec888e3a1c97a4b");
音声対話の実装⑩
最後にStep3として音声合成を実装します。
Qiita記事の「音声合成で対話サービスからの応答を
音声に変換する(Text to Speech)」の項にまとめてい
ますので参照してください。
Step3の実装はtextToSpeech.SpeakTextメソッドに対話サービスからの
レスポンスの回答のテキストを設定するだけです。簡単ですね。
(ピリオドがあるとそれまで発話されるので、スペースに置換しておくとよいで
す。)
実装の答えは次ページ
音声対話の実装⑪
答え
//Step3 音声合成の実装
textToSpeech.SpeakText(respose.result.fulfillment.speech.Replace(".", " "));
キャラをイキイキさせる
UXの向上
対話はできるようになりましたが、まだキャラはイキイキ
していません。イキイキさせるために以下の要素を実装
します。
①リップシンク
②目線を合わせる
③「Come On」でこっちにきてもらう。
リップシンクの実装①
リップシンクについては今回はOVRLipSyncを利用し
ます。
まず、 SingletonオブジェクトにOVRLipSyncのスクリ
プトを追加します。
リップシンクの実装②
次にUnityちゃんにOVRLipSyncContextと
OVRLipSyncContextMorphTargetのスクリプトを追
加します。
リップシンクの実装③
OVRLipSyncContextはAudioSourceにUnityちゃん
のAudioSourceを設定し、AudioMuteのチェックをは
ずします。
リップシンクの実装④
OVRLipSyncContextMorphTargetはまず
skinnedMeshRendererにMTH_DEFを設定し、
VisemeToBlendTargetsを以下の通り設定します。
リップシンクの実装⑤
次にOVRLipSyncContextMorphTargetの
skinnedMeshRendererに設定したMTH_DEFをダブ
ルクリックし、Inspectorビューを開きます。そして
BlendShapesの値を以下のように設定します。
リップシンクの実装⑥
設定が終わったら
OVRLipSyncContextMorphTargetのスクリプトを
EditScriptで開き、Update()をLateUpdate()に変更
します。
void Update ()
{
if((lipsyncContext != null) && (skinnedMeshRenderer != null))
void LateUpdate ()
{
if((lipsyncContext != null) && (skinnedMeshRenderer != null))
リップシンクの実装⑦
最後に少し特殊な設定ですが、スクリプトの実行順序の
設定をします。
まずは上部のメニューのEdit→Project Settings→
Script Execution Orderを選択。
リップシンクの実装⑧
Inspectorビューに設定画面が開くので、下の図のよう
にOVRLipSync→OVRLipSyncContextの順になるよ
うに設定します。そしてApplyで設定を適用します。
LookAtIKの実装①
目線を合わせるためにLookAtIKを実装します。
まずUnityちゃんにIKLookAtのスクリプトを追加します。
lookAtObjには目線を合わせる対象の
HoloLensCameraを設定します。
LookAtIKの実装②
次にUnityちゃんのAnimatorControllerである
WalkControllerを開き、以下のように編集します。
①BaseLayerの歯車をクリックし、IK Passのチェッ
クをつける。
②Faceの歯車をクリックし、Maskにface only mask
を設定する。
動的NavMesh生成の実装①
「Come On」でこっちにきてもらうために動的NavMesh
生成を実装します。
まず、 Singletonオブジェクトに
LocalNavMeshBuilderのスクリプトを追加します。
動的NavMesh生成の実装②
次にSpatialMappingプレハブのコンポーネントにある
SpatialMappingObserverをEditScriptで開き、
AddComponent<WorldAnchor>()のメソッドを実行
している箇所を探します。
ここがメッシュを生成している箇所なので
WorldAnchorと同じように
AddComponent<NavMeshSourceTag>()で生成し
たメッシュがNavMeshになるようにします。
実装
worldAnchor = newSurface.Object.AddComponent<WorldAnchor>();
newSurface.Object.AddComponent<NavMeshSourceTag>();
これで完成です!
HoloLensにデプロイして
体験しましょう!
参考リンク集
◆Holoの嫁と会話するためのステップバイステップ
https://qiita.com/decchi/items/f4766d6f45da0e59639b
◆HoloLensで実現する動的経路探索
https://qiita.com/morio36/items/d75228d2ccdb9c24574b
◆【Unite 2017 Tokyo】VR MAGIC! ~キャラクターに命を吹き込んだこの4年
間の記録~
https://www.slideshare.net/Unite2017Tokyo/unite-2017-tokyovr-
magic4

HoloLensハンズオン キャラと音声対話をしてみよう!