『Spark AR Studio』で作ろう!⑥後編
皆さん、こんにちは!
皆様、GWはいかがお過ごしでしたでしょうか?
私は、家族が体調を崩してどこにも行けませんでした。。。
コロナじゃなかったのは幸いでしたが。
そんな悲しい気持ちを引きずりつつ、前回の続きからです!
前回で、インポートした3Dモデルが、各ボタンに対応したアニメーションで再生されるようになりました。
次に、オブジェクトタップで別のアニメーションが再生されるように編集していきます。
「Patch Editor」で「Object Tap」パッチを追加し、「Scene」パネルでキャラクターのオブジェクトをドラッグアンドドロップで「Patch Editor」に追加します。
それらを繫げばオブジェクトタップを検知してくれるようになります。
「Animation」パッチと「Animation Player」パッチを追加し、「FBXファイル」のアニメーションデータをドラッグアンドドロップで「Patch Editor」に追加します。
「Animation」パッチの「Duration」をアニメーションデータと同じ値にします。
「Duration」はアニメーションの速度で、「Assets」パネルにある「FBXファイル」のアニメーションデータを選択すれば、「Inspector」で確認できます。
下図のように各パッチを繋ぎます。
続いて、「Switch」パッチと「If Then Else」パッチを追加します。
「If Then Else」パッチのドロップダウンリストから「Animation Data」を選択します。
「Option Picker」パッチが、キャラクターのアニメーションプロパティのパッチと繋がっているので、それらを解除して「If Then Else」パッチと繋ぎます。
その他のパッチは下図のように繋ぎました。
これで各ボタンに対応したアニメーションの再生と、オブジェクトタップに対応したアニメーションの再生が実装できました。
解説しますと、まずオブジェクトをタップした時に「Object Tap」パッチから「Animation」パッチの「Play」と「Reset」に信号を送ります。
「Animation」パッチの「Progress」から「Animation Player」パッチに信号を送り、「Animation Asset」に接続しているアニメーションデータを「If Then Else」パッチの「Then」に送ります。
また、「Object Tap」パッチから「Switch」パッチの「Turn On」に信号が送られているので、「Switch」パッチがオンになり、「If Then Else」パッチの「Condition」もオンになり「Then」の信号が「Jellyfish_Pig_anim」に送られる事によって「mechanim-rig|TapAction」のアニメーションが再生されます。
アニメーションが終了すると、「Animation」パッチの「Completed」から「Switch」パッチの「Turn Off」に信号が送られ「Switch」パッチがオフになり、
「If Then Else」パッチの「Condition」もオフになり、「Else」に接続されている信号が「Jellyfish_Pig_anim」に送られ、各ボタンに対応したアニメーションが再生されます。
自分で解説してて、何を言っているのか意味が分からなくなってきますが、この辺は、実際に一つ一つ動作を確認しながら進めていった方が分かりやすいかと思います。
これで完成でもいいのですが、もう少しユーザーに対して分かりやすいように機能を実装したいと思います。
このエフェクトは、バックカメラの時に機能するエフェクトですが、現状、フロントカメラにした時にもボタンが表示され続けています。
まあ、気にしなければ特に問題はないのですが、簡単になおせるのでなおしていきます。
やり方はいろいろありますが、今回は、平面を検出し、スクリーンタップでオブジェクトが表示されるタイミングでボタンも表示されるようにします。
必要なパッチは、パッチグループ化した「Manipulation」の中に揃っています。
「Patch Editor」で「Manipulation」を右クリックするか、歯車アイコンをクリックして「Group Properties」を選択します。
パッチグループのプロパティを編集できるウィンドウが表示されるので、「Outputs」の右にある「+」をクリックして新しい出力先を追加します。
「Name」は「PlaneTrackerFound(任意)」、「Type」を「Boolean」にします。
「Manipulation」パッチに新しい出力先が追加されました。
「Manipulation」パッチの右にある矢印アイコンをクリックし、パッチグループを開きます。
新しく「PlaneTrackerFound」パッチが追加されています。
これが追加した出力先になります。
「Plane Tracker」パッチの「Found」と「PlaneTrackerFound」パッチを繋ぎます。
メインの「Patch Editor」に戻り、「Manipulation」パッチの「PlaneTrackerFound」と「Picker UI」パッチの「Visible」を繋ぎます。
続いて、「Scene」パネルの「planeTracker0」を選択し、「Inspector」で「Auto Start」をオフにします。
これで、バックカメラで画面をタップしない限り、オブジェクトとボタンは表示されなくなりました。
最後に、オブジェクトタップを促すサインを実装します。
新たに「FBXファイル」とテクスチャをインポートし、「placer」オブジェクトの下に配置、サイズを調整、マテリアルを編集し、下図のオブジェクトを作成しました。
マテリアルの「Advanced Render Options」の「Use Depth Test」をオフにして、常に前面に描画されるようにしておきます。
サインオブジェクトの「Position」を「Patch Editor」に追加します。
「Loop Animation」パッチ、「Transition」パッチを追加し、値を編集、下図のように各パッチを繋ぎます。
↓↓完成したループアニメーション。
次に、ループアニメーションが一定回数に達すると消えるようにします。
パッと消えてもいいのですが、見た目をよくするためにフェードイン・フェードアウトを実装しましょう。
サインマテリアルの「Texture」の左にある矢印をクリックして「Patch Editor」に追加します。
「Assets」パネルにあるテクスチャを「Patch Editor」にドラッグアンドドロップして追加します。
「Animation」パッチ、「Transition」パッチ、「Mix」パッチを追加し、各パッチを繋ぎます。
「Manipulation」パッチの「PlaneTrackerFound」と「Animation」パッチの「Play」と「Reset」を繋げば(「Pulse」パッチが自動で追加されます)、オブジェクトが表示されるタイミングで、サインオブジェクトがフェードインするようになります。
フェードアウトはこれを逆再生すればいいのですが、まず、「Counter」パッチを追加し、「Loop Animation」パッチの「Looped」と「Counter」パッチの「Increase」を繋いで、ループアニメーションのループ回数をカウントできるようにします。
「Maximum Count」は「11」にし、11回目のループでカウントが0にリセットされるようにします。
次に、「Greater or Equal」パッチを追加し、ドロップダウンリストから「Number」を選択、「Counter」パッチと「Greater or Equal」パッチの「First Input」を繋ぎます。
「Second Input」の値は「10」にしておきます。
「Greater or Equal」パッチと「Animation」パッチの「Reverse」と「Stop」を繋げば(「Pulse」パッチが自動で追加されます)、10回目のループで逆再生し、その後はアニメーションされません。
「Manipulation」パッチの「PlaneTrackerFound」と「Loop Animation」パッチの「Enable」を繋ぎ、オブジェクトが表示されるタイミングでループアニメーションがスタートするようにします。
これでフェードインとループアニメーションのスタートが同じになります。
最後に、「Manipulation」パッチと「Animation」パッチを繋いだ時に自動で追加された「Pulse」パッチの「Turned On」と、「Loop Animation」パッチの「Reset」、「Counter」パッチの「Jump」を繋げば、オブジェクトが表示されるタイミングでループアニメーションがリセット、カウントも0にリセットされます。
「Counter」パッチの「Jump to Number」の値は「0」にしておかないといけません。
↓↓完成したループアニメーション。フェードイン・フェードアウトします。
仕上げに、サインオブジェクトが常にカメラの方に向くようなスクリプトを作成します。
「Add Asset +」→「Script」→「JavaScript」を選択し、スクリプトを追加します。
下記のように記入します。
const S = require("Scene");
Promise.all([
S.root.findFirst('SignPlane'),
S.root.findFirst('planeTracker0'),
S.root.findFirst('Camera')
]).then(function(objects){
const Sign = objects[0];
const followNull = objects[1];
const targetNull = objects[2];
Sign.worldTransform.rotation = followNull.worldTransform.lookAt(targetNull.worldTransform.position).rotation;
});
スクリプトの書き方も以前と変わりましたね。
以上で完成です!
下のQRコードからぜひ試してみてください!
それではまた次回!
(Cole!Cole!クリエイターU)