目次


Watson×Unity!初心者でもできる、VR 空間で Unity ちゃんとおしゃべりアプリ!

Comments

今話題の技術や最新技術への挑戦を応援する【IBM×teratail のコラボ企画】第二弾です。今回は Watson×バーチャルリアリティ(以下 VR)を組み合わせたサンプルのご紹介です。

はじめに

VR 元年と言われた 2016 年以降、「Oculas」や「HTC Vive」、「PlayStation VR」などの様々な VR 機器、スマホでも気軽に VR が楽しめる「ハコスコ」などが話題に上がり、また、関東圏では渋谷やお台場に VR が体験できるアミューズメントパークも複数オープンされるなど、VR 業界は大きな盛り上がりを見せています。今なおその勢いの止まらない VR の世界、みなさんも VR で何か作ってみたいとワクワクしているかと思いますが、やはりその中でも夢が詰まっているものの一つといえば、VR 空間で自分の好きなキャラクターと自由に会話するというものではないでしょうか?

今回はそんな夢のような VR アプリの第一歩として、Unity ちゃんとスマホを通じて VR 空間で会話できるようなアプリを作ってみます。

利用技術について

今回の記事では主に Unity(Version は 5.6.2)を使っていきます。

※Unity のダウンロードはこちら

本記事では、Unity をまったく触ったことがない人でも進められるようになるべく細かく手順を説明していますが、基本操作を確認したい場合は、公式サイトのチュートリアルを参考にしてください。

Unity 内では、C#、JavaScript、Boo の 3 つのプログラミング言語が使えますが、本記事では C#を用います。C#の基本文法などを一通り確認したい方は、こちらの記事などが参考になります。

※Unity のドキュメントはこちら ※C#のドキュメントはこちら

また、Watson API も利用するので、Bluemix へのアカウント登録がお済みでない方はこちらより登録を完了させましょう。

Unity ちゃんのデータをゲットしよう

Unity ちゃんとは?

Unity ちゃんとは、Unity Technologies Japan が提供する人気オリジナルキャラクターで、開発者がかなり自由に使うことができるよう配慮されています。ガイドラインライセンス、キャラクターの詳しい説明などはこちらからご確認ください。なお、今回紹介するサンプルはユニティちゃんライセンス条項の元に提供されています。(© Unity Technologies Japan/UCL)

Unity ちゃんの 3D データをダウンロード

Unity を立ち上げ、NEW Project を作成してください。 左上の「Asset Store」タブを選択し、検索窓から「Unity-chan」と入力し検索しましょう。

いくつかの Unity-chan に関するアセットが表示されるので、その中から "Unity-chan!" Model を選択してください。次のように表示されるので、青い「Import」のボタンをクリックしましょう。

次のような Window が表示されるので、そのまま import をクリックしてください。

無事にインポートが完了すると、下図のように Projects 内の Assets フォルダ下に UnityChan というフォルダが作成されます。

Unity ちゃんを表示してみよう

UnityChan -> Models の中に unitychan というモデルがみつかるので、それをクリックしてください。次のように右側に inspector が表示されるので、Rig 内の Animation TypeHumanoid になっていることを確認してください。(もし Humanoid になっていなければ、Humanoid 変更して、Apply ボタンを忘れずに押してください。)

左上のタブを Scene に切り替え、unitychan を Hierarchy ビューにドラッグ&ドロップして Unity ちゃんを表示させましょう。

※シーンビューのアングルの調整方法は、こちらの公式チュートリアルを参考にしてください

Unity ちゃんをしゃべらせよう

Unity ちゃんをしゃべらせるために、WatsonAPI の「Speech To Text」と「Text To Speech」、「Conversation Service」を使います。話しかけたときの音声データを「Speech To Text」で文字に変換し、「Conversation Service」で解釈し、返ってきた言葉を「Text To Speech」を使って音声で返す、というものです。

UnitySDK のダウンロード

Watson には、Unity から WatsonAPI を簡単に呼び出せる「Unity-SDK」が用意されています。

こちらのページより Sourse code (zip) ファイルをダウンロードしてください。2017/8/29 現在、v0.13.0 が最新版なので、本記事ではこの Version を使います。

ダウンロード -> 解凍したファイルは、Project ビューの、Assets ファイルの下にドラッグ&ドロップしましょう。ファイル名は、Watson に Rename しておきます。

Asset の適用が完了すると上部のメニューや、Project ビュー内の Assets の中のフォルダに「Watson」というフォルダが追加されます。

Speech to text を Unity に適用する

Bluemix にログインし、ダッシュボードを開き、左上のメニューから Watson を選択しましょう。

カタログの中から、「Speech To Text」を見つけてクリックすると次のように表示されるので、サービス名を STT-Unity-Chan など自身が分かりやすいように設定し「作成」ボタンを押してください。

サービスの作成ができたら、次のような画面が表示されるので、左サイドのメニューから「サービス資格情報」を選択してください。

続いて、「資格情報の表示」をクリックすると表示される json 形式のデータが表示されるのでこちらをコピーします。

Unity の画面に戻ります。先ほど出てきた上部メニューの Watson をクリックし、Configuration Editor を選択してください。

次のような「Config Editor」のウインドウが開くので、スクロールし、下の方にある「PASTE CREDENTIALS」という欄に先ほどの json を貼り付け「ApplyCredentials」をクリックしましょう。

Complete と表示されれば完了です。

「Service Speech To Text CONFIGURED」と緑で表示されるようになります。

Speech to Text を試してみよう。

公式のサンプルコードを参考にしながら Speech to Text を試してみましょう。

Project の Assets -> UnityChan -> Scripts のフォルダ直下に、「Create▼」から「C# Script」を選択し、ファイル名を生成します。ファイル名は「SampleSpeechToText」などとしておきます。

SampleSpeechToText.cs には、先のサンプルコードをベースに、マイクから集音できるように改変します。下記のようになります。

※create で C#ファイルを作成するとき、デフォルトでは「NewBehaviourScript」という名前がついていますが、このまま作成してしまうと、下記コードの public class SampleSpeechToText : MonoBehaviour { ... } の部分が public class NewBehaviourScript : MonoBehaviour { ... } となってしまいます。ファイル作成後に「NewBehaviourScript」という名前を変更する(該当がいるを右クリック -> Rename で変更可能)際は、コード内の「NewBehaviourScript」も書き換えることに注意してください。

//SampleSpeechToText.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using IBM.Watson.DeveloperCloud.Services.SpeechToText.v1;

public class SampleSpeechToText : MonoBehaviour {

	[SerializeField]
	private AudioClip m_AudioClip = new AudioClip();
	private SpeechToText m_SpeechToText = new SpeechToText();

	// Use this for initialization
	IEnumerator Start()
	{
		// 音声をマイクから 3 秒間取得する
		Debug.Log ("Start record"); //集音開始
		var audioSource = GetComponent<AudioSource>();
		audioSource.clip = Microphone.Start(null, true, 10, 44100);
		audioSource.loop = false;
		audioSource.spatialBlend = 0.0f;
		yield return new WaitForSeconds (3f);
		Microphone.End (null); //集音終了
		Debug.Log ("Finish record");

		// ためしに録音内容を再生してみる
		audioSource.Play ();

		// SpeechToText を日本語指定して、録音音声をテキストに変換
		m_SpeechToText.RecognizeModel = "ja-JP_BroadbandModel";
		m_SpeechToText.Recognize(audioSource.clip, HandleOnRecognize);
	}

	void HandleOnRecognize(SpeechRecognitionEvent result)
	{
		if (result != null && result.results.Length > 0)
		{
			foreach (var res in result.results)
			{
				foreach (var alt in res.alternatives)
				{
					string text = alt.transcript;
					Debug.Log(string.Format("{0} ({1}, {2:0.00})\n", text, res.final ? "Final" : "Interim", alt.confidence));
				}
			}
		}
	}
	
	// Update is called once per frame
	void Update () {
		
	}
}

作成した SampleSpeechToText.cs を Hierarchy ビューの unitychan にドラッグ&ドロップしましょう。unitychan をクリックし、その Inspector を見ると SampleSpeechToText が Component に加わっているのが分かります。

SampleSpeechToText.cs では、マイクから集音しているので、unitychan に AudioSource の Component を付け加える必要があります。unitychan 内の Inspector の「Add Component」より、Audio -> Audio Source をクリックしてください。

これで準備完了です。Unity 画面上部の再生ボタン「▶︎」をクリックして、PC に向けて話しかけてみてください。話しかけた内容がそのまま録音され再生されます。また、Console 部分には話しかけた内容が文字で表示されます。

Text to Speech を試してみよう。

先ほどと同様の手順で Text to Speech も試して見ましょう。Bluemix のダッシュボードにログインし、カタログから Text to Speech を選択し、サービス名を「TTS-Unity-Chan」などとして作成します。「資格情報の表示」の json ファイルをコピーしたら、Unity 画面を開き、上部メニューの Watson -> Config Editor を開き、「PASTE CREDENTIALS」の欄に貼り付けて「ApplyCredentials」をクリックです。

公式のサンプルコードを参考にしながら Text to Speech を試してみましょう。

Project の Assets -> UnityChan -> Scripts のフォルダ直下に、「Create▼」から「C# Script」を選択し、ファイルを生成します。ファイル名は「SampleTextToSpeech」としておきます。

SampleTextToSpeech.cs のソースは下記となります。

//SampleTextToSpeech.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using IBM.Watson.DeveloperCloud.Services.TextToSpeech.v1;

public class SampleTextToSpeech : MonoBehaviour {

	TextToSpeech m_TextToSpeech = new TextToSpeech();
	string m_TestString = "おはようございます。漢字も読めます。";

	// Use this for initialization
	void Start ()
	{
		m_TextToSpeech.Voice = VoiceType.ja_JP_Emi;
		m_TextToSpeech.ToSpeech(m_TestString, HandleToSpeechCallback);
	}

	void HandleToSpeechCallback (AudioClip clip)
	{
		PlayClip(clip);
	}

	private void PlayClip(AudioClip clip)
	{
		if (Application.isPlaying && clip != null)
		{
			GameObject audioObject = new GameObject("AudioObject");
			AudioSource source = audioObject.AddComponent<AudioSource>();
			source.spatialBlend = 0.0f;
			source.loop = false;
			source.clip = clip;
			source.Play();

			GameObject.Destroy(audioObject, clip.length);
		}
	}

	// Update is called once per frame
	void Update () {

	}

}

コードが完成したら、先ほどと同様に SampleTextToSpeech.cs を Hierarchy ビュー内の unitychan にドラッグ&ドロップしてください。unitychan の Inspector から、さきほど追加した SampleSpeechToText のチェックははずしておきます。

再生ボタン「▶︎」をクリックしましょう。「おはようございます。漢字も読めます。」という音声が流れば OK です。動作が確認できたら、unitychan の Inspector から、SampleTextToSpeech のチェックもはずしておきしょう。

Conversation Service を試してみよう。

Conversation Service を Unity に適用させる

さて次は Conversation Service を試してみます。Watson の Conversation API では、こちら側が話しかけた内容に対して、適切な返答を返してくれるよう学習できるものです。

では Conversation API を Unity に適用させていきましょう。途中までの手順はこれまでと同じで、Bluemix のダッシュボードにログインし、カタログから Conversation を選択し、サービス名を「Conv-Unity-Chan」などとして作成します。「資格情報の表示」の json ファイルをコピーしたら、Unity 画面を開き、上部メニューの Watson -> Config Editor を開き、「PASTE CREDENTIALS」の欄に貼り付けて「ApplyCredentials」をクリックです。

Conversation Service の設定

次に、コードを書く前に Conversation の設定をしていきます。Conversation を使うには、初期の設定として、どういった問いかけに対して、どのように返答していくかをある程度決める必要があります。それをベースに学習させていき、よりスムーズな会話ができるようになっていくのですが、あまり詳しく説明すると膨大な文量になるため、今回はシンプルにあいさつに対してあいさつを返す程度に止めておこうと思います。

Conversation を設定するには Launch Tool というものを使います。自身の Bluemix アカウントのダッシュボードから、先ほど作成した「Conv-Unity-Chan」を選択しましょう。次のような画面となるので、「Launch Tool」をクリックしてください。

Workspaces に移動するので、create を押しましょう。

Name は「Hello-Unity-Chan」などとし、Description には自身が分かりやすいように記入したあと、create をクリックしてください。

Workspace を開くと、「Intents」「Entities」「Dialog」のという 3 つの項目が表示されます。まずは Intents から設定しましょう。Intents とは「意図」のことです。ユーザーが、Conversation Service に対して話しかけてくるであろう言葉や質問を、その意図ごとに区分けしておく機能が Intents です。たとえば「あいさつ」を意図として話しかけられるであろう言葉といえば、「おはよう」や「こんにちは」、「こんばんわ」、「やぁ」、「ハロー」などがあるので、これらを「あいさつ」の Intents としてまとめて登録します。ではまず、「Create new」をクリックしてください。

「Intent name」には「あいさつ」と入力し、「User example」に思いついたあいさつの言葉をどんどん入れていきます。入れ終えたら「Done」をクリックします。

今回のアプリを完成させるには、これだけでも十分なのですが、後々Conversation でもう少し複雑な会話も設定できるようにもう 1 個登録してみます。「Intent name」を「食事」として、「User example」に食事をしたいときに Conversation Service に話しかけそうな言葉を入れてください。

次に Entities の設定を行いましょう。Entities は Entity(実態)の複数系ですが、「目的語」といったイメージを持っていてください。例えばさきほどの「食事をしたい」と言われたら、何を食べたいかを聞きたくなりますよね?その「何を」にあたるのが Entity です。

ではさっそく Entity を登録してみましょう。左上のメニューを「Entities」に切り替え、「Create new」をクリックします。

Entity を「食事メニュー」とし、Value に思いついた食事メニューを入力していきましょう。記入が完了したら、「Done」をクリックします。

それでは最後に「Dialog」です。ここで実際の会話のフローを設定していきます。「こんにち」はとあいさつされたらあいさつを返す、「お腹がすいた」と言われたら「何を食べたいですか?」ときき返す... などです。 さっそく設定してみます。左上のメニューを「Dialog」に切り替え、「Create」をクリックします。

まずは「welcome」というのと「anything_else」というのが表示されます。「welcome」は、一番最初に Conversation Service が返す言葉(デフォルトは「いらっしゃいませ。ご用件を入力してください。」)が設定されており、「anything_else」では、自分がまだ設定(あるいは学習)していない質問や言葉を投げかけられたときに Conversation Service が返す言葉(デフォルトでは、「解釈できませんでした。申し訳ありませんが違う表現を試していただけますか。」など)が設定されています。

さて、ここに少し付け加えていきましょう。左上の「Add node」をクリックしてください。すると「welcome」と「anything_else」の間に「No Condition Set」と書かれた node が追加され、右にその node の設定画面が表示されます。右部を大まかに説明します。「Name this node...」の部分にはこの node の名前を記入します。「If bot recognizes:」の部分には、この node が反応する条件を書きます。例えば、ここに「#あいさつ」と記入しておくと、Intents の「#あいさつ」で設定した「こんにちは」や「おはよう」などの言葉を Conversation Service が受け取ると反応します。「Enter a response」には、この node に反応した際に返す言葉を記入します。

今回は簡易的に、Intent「#あいさつ」に設定された言葉に対して、「やっほー」と返答する node を 1 つ作成することとします。下記のように記入し、右上の「×」ボタンを押しましょう。また、その上の吹き出しアイコンをクリックすると動作確認ができるので、押してみましょう。

右下赤枠で囲んだ部分に「おはよう」などの「#あいさつ」Intent に登録した言葉を入力し、エンターを押してみてくさい。「おはよう」が「#あいさつ」Intent として認識され、「やっほー!」と返されるので、正常に動作していることが確認できます。

なお、「Entities」を活用したり、「child node」を作成し、会話に応じてレスポンスを条件分岐させていくことで、よりインタラクティブな会話が楽しめるようになります。より詳しい使い方が気になる方は、こちらのページの動画デモや「Conversation API 詳細資料を見る」ボタンのリンク先で閲覧できる資料などをご参考ください。

Unity 内で Conversation Service を動かしてみる

まずは今作成した Hello-Unity-Chan の「Workspace ID」を確認しましょう。Workspaces 画面を開いてください。(先ほどの Dialog 画面でからだと、左上の「Watson Conversation / Hello-Unity-Chan / Build」の「Watson Conversation」の文字をクリックすると Workspaces に戻ることができます。)Workspaces の Hello-Unity-Chan 内にある縦並びの 3 つのドットをクリックし、その中から「View details」を選択してください。

すると、Workspace ID が表示されるので、こちらをコピーしてください。

続けてコードを書いていきます。公式のサンプルコードを参考にしましょう。Project の Assets -> UnityChan -> Scripts のフォルダ直下に、「Create▼」から「C# Script」を選択し、ファイルを生成します。ファイル名は「SampleConversation」などとしておきます。

SampleConversation.cs のソースは下記となります。先程コピーした Workspace ID は、private string m_WorkspaceID = "(ここには各々の Workspace ID が入ります)"; 部分に使用してください。

//SampleConversation.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using IBM.Watson.DeveloperCloud.Services.Conversation.v1;

public class SampleConversation : MonoBehaviour {

	private Conversation m_Conversation = new Conversation();
	private string m_WorkspaceID = "(ここには各々の Workspace ID が入ります)"; //各自変更してください
	private string m_Input = "おはよう";

	// Use this for initialization
	void Start () {
		Debug.Log("User: " + m_Input);
		m_Conversation.Message(OnMessage, m_WorkspaceID, m_Input);
	}

	void OnMessage (MessageResponse resp, string customData)
	{
		foreach(Intent mi in resp.intents)
			Debug.Log("intent: " + mi.intent + ", confidence: " + mi.confidence);

		Debug.Log("response: " + resp.output.text.[0]);
	}
	
	// Update is called once per frame
	void Update () {
		
	}
}

コードが完成したら、先ほどと同様に SampleTextToSpeech.cs を Hierarchy ビュー内の unitychan にドラッグ&ドロップしてください。そして再生ボタン「▶︎」をクリックしましょう。Console 部分に下図のように表示されれば成功です。 ※unitychan の Inspector から、さきほど追加した SampleSpeechToText と SampleTextToSpeech のチェックが外れていることを確認して再生「▶︎」しましょう。

Unity ちゃんと会話ができるようにしよう

さて、今試した 3 つの Watson API、「Speech to Text」と「Text to Speech」と「Conversation Service」を組み合わせて、「おはよう」と話しかけたら「やっほー!」と返してくれるようにしましょう。 Project ビューの Assets -> UnityChan -> Script に、「C# Script」を作成してください。ファイル名は「WatsonConversation」としておきましょう。

コードは下記となります。

//WatsonConversation.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using IBM.Watson.DeveloperCloud.Services.TextToSpeech.v1;
using IBM.Watson.DeveloperCloud.Services.SpeechToText.v1;
using IBM.Watson.DeveloperCloud.Services.Conversation.v1;

public class WatsonConversation : MonoBehaviour {

	[SerializeField]
	SpeechToText m_SpeechToText = new SpeechToText();
	TextToSpeech m_TextToSpeech = new TextToSpeech();
	private Conversation m_Conversation = new Conversation();
	private string m_WorkspaceID = "(ここには各々の Workspace ID が入ります)"; //各自変更してください

	// Use this for initialization
	IEnumerator Start() {
		var audioSource = GetComponent<AudioSource>();
		while (true) {
			yield return RecMic(audioSource);
		}
		yield return null;
	}

	IEnumerator RecMic(AudioSource audioSource) {
		Debug.Log ("Start record");
		audioSource.clip = Microphone.Start(null, true, 10, 44100);
		audioSource.loop = false;
		audioSource.spatialBlend = 0.0f;
		yield return new WaitForSeconds (2.0f);
		Microphone.End (null);
		Debug.Log ("Finish record");

		// 音声の認識言語を日本語に指定
		m_SpeechToText.RecognizeModel = "ja-JP_BroadbandModel";
		// 音声をテキストに変換し、関数:HandleOnRecognize()を呼ぶ
		m_SpeechToText.Recognize(audioSource.clip, HandleOnRecognize);

	}

	void HandleOnRecognize(SpeechRecognitionEvent result){
		if (result != null && result.results.Length > 0) {
			foreach (var res in result.results) {
				foreach (var alt in res.alternatives) {
					//集音した音声データを文字化したものを text に格納
					string text = alt.transcript;
					Debug.Log (string.Format ("{0} ({1}, {2:0.00})\n", text, res.final ? "Final" : "Interim", alt.confidence));

					//text を Conversation Service に送って処理
					m_Conversation.Message(OnMessage, m_WorkspaceID, text);
				}
			}
		} else {
			//音声ファイルが空あった場合の処理
			Debug.Log ("何も聞き取ってくれないときもある");
		}
	}

	void OnMessage (MessageResponse resp, string customData)
	{
		if (resp != null) {
			foreach (Intent mi in resp.intents)
				Debug.Log ("intent: " + mi.intent + ", confidence: " + mi.confidence);

			//TextToSpeech の音声タイプを指定
			m_TextToSpeech.Voice = VoiceType.ja_JP_Emi;
			//Conversation Service から返された文字列を TextToSpeech にて発音
			m_TextToSpeech.ToSpeech (resp.output.text[0], HandleToSpeechCallback);

			Debug.Log ("response: " + resp.output.text[0]);
		}
	}

	void HandleToSpeechCallback (AudioClip clip) {
		PlayClip(clip);
	}

	private void PlayClip(AudioClip clip) {
		if (Application.isPlaying && clip != null) {
			GameObject audioObject = new GameObject("AudioObject");
			AudioSource source = audioObject.AddComponent<AudioSource>();
			source.spatialBlend = 0.0f;
			source.loop = false;
			source.clip = clip;
			source.Play();

			GameObject.Destroy(audioObject, clip.length);
		}
	}

	// Update is called once per frame
	void Update () {

	}
}

コードが完成したら、WatsonConversation.cs を Hierarchy ビュー内の unitychan にドラッグ&ドロップしましょう。unitychan の Inspector のチェックを WatsonConversation.cs だけにして、再生ボタン「▶︎」をクリックしましょう。「おはよう」などと話しかけて、「やっほー」と音声で返ってきたら成功です。(console にも表示されます。)

Unity ちゃんに動きをつけよう

さて「おはよう」と返してくれるようにはなりましたが、これでは Unity ちゃんが「おはよう」と言ってくれるようには到底思えません。そこで Unity ちゃんがちゃんと話してるかのようにするため、おはようと言うタイミングで Unity ちゃんに動きをつけてみましょう。

Unity ちゃんのデフォルトの動きを確認しよう。

Unity ちゃんにはデフォルトでいくつかの動きが用意されているので、今回はこの動きを活用します。まずはその動きを確認してみましょう。Projects 内の Assets -> UnityChan -> Animations の中にたくさんのアニメーションが格納されています。その中のどれでもいいのでダブルクリックしてみましょう。右下にモデルを確認する領域が表示されます。

再生ボタン「▶︎」をクリックすると一応動きは確認できるのですが、このままではアニメーションの動きがわかりづらいので Unity ちゃんに登場してもらいましょう。上図の右下あたりの赤丸で囲んだ人の上半身のようなアイコン (?) をクリック -> Others を選択してください。すると、右上あたりに Asetts が表示されるので、その中から Unitychan を選択しましょう。右下の領域に Unity ちゃんが表示されます。

あとは、各アニメーションの動きを試してみてください。今回は unitychan_WATE03 という動きを使います。最後に顔に手をかざすところが、全力で「やっほー!」って言ってるような気がします。デフォルトの状態もただ単に立ってるだけというのも寂しいので、通常の「待ち」状態のときは unitychan_WATE02 を使って、手をぶらぶらさせておくこととします。

モーションをつくる

State の作成と State の遷移の設定 ではさっそくモーションをつくっていきます。今回は単純に、デフォルトの「待ち」の状態(unitychan_WATE02 で手をぶらぶらさせた状態) -> 「やっほー!」と発生するときに unitychan_WATE03 の動きをするというモーションです。

Assets -> UnityChan -> Animators の中に新たにファイルを作成します。create -> Animator Controller を選択してください。ファイル名は Greeting としておきます。

ファイルを生成したら、そのファイルをダブルクリックしてください。下記のように右上に Animator 画面が表示されます。ここで設定していきます。この一つひとつの箱のことを State といって、それぞれが 3D モデルの状態を表します。

*「AnyState」は今回は使いません。

今回は「待ち」と「あいさつ」の 2 つの状態(State)を作ります。Animator 画面内で右クリックを押し、Create State -> Empty とを選択してください。「New State」というオレンジの四角が表示されると思います。これをダブルクリックして、Inspopector を表示、名前を「Wait」に変更してください。

同様にもう 1 つ Staete を作成し、名前を「Greet」とします。下図のようになるかと思いますが、続いて状態遷移を設定していきましょう。「Wait」State 上で右クリックし、Make Transition をクリックしてください。「Wait」から矢印が伸びてくるので、それを「Greet」に繋げましょう。

同様に「Greet」から「Wait」にも矢印を繋げてください。これで State の作成と State の遷移の設定は完了です。

State にアニメーションを設定する

各 State にアニメーションを紐付けていきます。「Wait」をクリックし、Inspector を表示させましょう。Motion という項目があるので、その横の「○」をクリックしてください。左上に様々なモーションが表示されるので、「unitychan_WATE02」を選択しましょう。

同様に「Greet」には、「WATE03」を選択してください。

Parameter の設定

各 State のへ遷移を管理するために、どの State なのかを表すパラメータを用意します。左上の Parameters をクリック、「+」から Bool を選択しましょう。

「New Bool」というのが現れるので、名前を「isGreet」に変更しておきます。

次に「Wait」から「Greet」に向かっている矢印をクリックしてください。Inspector に Conditions という項目があるかと思いますが、ここの「+」から「isGreet」が「true」というのを選択してください。これにより、「isGreet」が「true」になると、「Wait」のアニメーション(unitychan_WAIT02)から「Greet」のアニメーション(unitychan_WAIT03)に遷移するという設定が完了します。また、Inspector の Settings を調整することで、Parameter が変更になったタイミングからどれくらいの時間で遷移先の State のアニメーションを実行するか、どれくらいの時間をかけて遷移するのかなど設定できるので、調整してみてください。

同様の手順で「Greet」から「Wait」に向う矢印の Inspector の Conditions に、「isGreet」の「false」を設定してください。これにより、「isGreet」が「false」になると、「Greet」のアニメーションから「Wait」のアニメーションに遷移します。

作成した Animator を適用する。

Hierarchy 内 unitychan をクリックし Inspector を表示させましょう。Animator という項目下に Controller があるので、右端の「○」をクリックし、今作成した「GoodMorning」を選択しましょう。

スクリプトで状態を切り替えよう

最後の仕上げです。下記のように、WatsonConversation クラス内の初期宣言と HandleOnRecognize() 内に一部コードをかき加えましょう。

//WatsonConversation.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using IBM.Watson.DeveloperCloud.Services.TextToSpeech.v1;
using IBM.Watson.DeveloperCloud.Services.SpeechToText.v1;
using IBM.Watson.DeveloperCloud.Services.Conversation.v1;

public class WatsonConversation : MonoBehaviour {

	[SerializeField]
	SpeechToText m_SpeechToText = new SpeechToText();
	TextToSpeech m_TextToSpeech = new TextToSpeech();
	private Conversation m_Conversation = new Conversation();
	private string m_WorkspaceID = "(ここには各々の Workspace ID が入ります)";

	private Animator animator; //ここを追加
	private const string key_isGreet = "isGreet"; //ここを追加

	// Use this for initialization
	IEnumerator Start() {
		this.animator = GetComponent<Animator>(); //ここを追加
		var audioSource = GetComponent<AudioSource>();

		while (true) {
			yield return RecMic(audioSource);
		}
		yield return null;
	}

	IEnumerator RecMic(AudioSource audioSource) {
		Debug.Log ("Start record");
		audioSource.clip = Microphone.Start(null, true, 10, 44100);
		audioSource.loop = false;
		audioSource.spatialBlend = 0.0f;
		yield return new WaitForSeconds (2.0f);
		Microphone.End (null);
		Debug.Log ("Finish record");

		// 音声の認識言語を日本語に指定
		m_SpeechToText.RecognizeModel = "ja-JP_BroadbandModel";
		// 音声をテキストに変換し、関数:HandleOnRecognize()を呼ぶ
		m_SpeechToText.Recognize(audioSource.clip, HandleOnRecognize);

	}

	void HandleOnRecognize(SpeechRecognitionEvent result){
		if (result != null && result.results.Length > 0) {
			foreach (var res in result.results) {
				foreach (var alt in res.alternatives) {
					//集音した音声データを文字化したものを text に格納
					string text = alt.transcript;
					Debug.Log (string.Format ("{0} ({1}, {2:0.00})\n", text, res.final ? "Final" : "Interim", alt.confidence));

					//text を Conversation Service に送って処理
					m_Conversation.Message(OnMessage, m_WorkspaceID, text);
				}
			}
		} else {
			//音声ファイルが空あった場合の処理
			Debug.Log ("何も聞き取ってくれないときもある");
		}
	}

	void OnMessage (MessageResponse resp, string customData)
	{
		if (resp != null) {
			foreach (Intent mi in resp.intents)
				Debug.Log ("intent: " + mi.intent + ", confidence: " + mi.confidence);

			if (resp.output.text [0].Contains ("やっほー")) {
				this.animator.SetBool (key_isGreet, true);
			}

			//TextToSpeech の音声タイプを指定
			m_TextToSpeech.Voice = VoiceType.ja_JP_Emi;
			//Conversation Service から返された文字列を TextToSpeech にて発音
			m_TextToSpeech.ToSpeech (resp.output.text[0], HandleToSpeechCallback);

			Debug.Log ("response: " + resp.output.text[0]);
		}
	}

	void HandleToSpeechCallback (AudioClip clip) {
		PlayClip(clip);
	}

	private void PlayClip(AudioClip clip) {
		if (Application.isPlaying && clip != null) {
			GameObject audioObject = new GameObject("AudioObject");
			AudioSource source = audioObject.AddComponent<AudioSource>();
			source.spatialBlend = 0.0f;
			source.loop = false;
			source.clip = clip;
			source.Play();

			GameObject.Destroy(audioObject, clip.length);
		}
	}

	// Update is called once per frame
	void Update () {

	}
}

完了したら、再生ボタンを押して動作確認をしましょう。「おはよう」などと声をかけた際に、音声だけでなく、動きも確認できたら成功です。

動作確認中の画面を GIF アニメで見る

※声と動作の基本最初はタイミングがズレるので、細かいチューニングが必要になってきます。

VR 対応にしよう

最後に、スマホで見る場合を想定して、スマホのジャイロセンサーに反応するようにしましょう Project の UnityChan -> Scripts の中に、create -> C# Script で、gyro.cs を作成してください。そして下記のように付け加えます。

//gyro.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class gyro : MonoBehaviour {

	// Use this for initialization
	void Start () {
		Input.gyro.enabled = true;
	}
	
	// Update is called once per frame
	void Update () {
		transform.rotation = Quaternion.AngleAxis(90.0f,Vector3.right)*Input.gyro.attitude*Quaternion.AngleAxis(180.0f,Vector3.forward);
	}
}

なお、本記事では、スマホのジャイロセンサーの反応を ON にすることで、簡易的なスマホ VR を試せるようにしましたが、Unity には VR 用の Assets も多数用意されております。それらを活用することで、簡単に VR 用に画面分割するなど、高度な設定もできるようになりますので、ぜひ試してみてください。

実機で確認しよう

左上メニューの File -> Build Settings... を選択してください。

下記のようなウィンドウが開かれるので、ご自身がお使いの実機を選択し、「Build And Run」を選択しましょう。

なお、実機での Build については、実機側の設定や、iOS だと Developer 登録等も必要になってくるため、ここでは詳細は割愛させていただきますが、参考サイトして、下記サイトをご覧ください。

おわりに

いかがでしたでしょうか?今回は Unity を使って簡単に 3D キャラクターの設定手順と、「Speech To Text」「Text To Speech」「Conversation Service」の組み込み方をご紹介しました。ここで紹介した方法で、3D モデルの動きを強化したり、Conversation の会話パターンをさらにつくり込むことで、自分の理想の 3D モデルへと成長させていくことができるかと思います。ぜひいろいろ試してみてください。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Cloud computing
ArticleID=1049516
ArticleTitle=Watson×Unity!初心者でもできる、VR 空間で Unity ちゃんとおしゃべりアプリ!
publish-date=09142017