前回、ついに『持ち上げる処理』の実装を全て見終えました。
しかし、これまで見た処理はあくまで『持ち上げる』というだけの処理です。
今回は、『持ち上げたものを離す』処理を最後まで見ていきます。
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/pick-23.png)
■ Un-link – Release
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/pick-131.png)
赤の部分は『トリガーが離された時』に実行されています。
画像だとやや見づらいので、
この画像を更に黄色・オレンジに区切って詳細に見ていきます。
①離したコントローラがリンクされているかチェック
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/pick-14.png)
まずは、持ち上げている状態かどうかを表す変数『is_linked』が
true(持ち上げている状態)なのかをチェック、
『ユニットを持ち上げているコントローラ』と『トリガーを離したコントローラ』が同一かもチェックします。
②コントローラとのリンクを外し、加速度を設定する
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/pick-15.png)
続いて、『SteamVR Unlink Node From Tracker』ノードで
ユニットとリンクしている対象(コントローラの持つ持ち上げ関数)とのリンクを外します。
その後は『SteamVR Set Actor Kinematic』で自由に動かせないようにします。
直後の『Set Actor Velocity』ノードには
前々回に登場した変数『wand_velocity』の値をセットしています。
『Set Actor Velocity』ノードは引数のユニットのアクタに対して引数の分だけの速度を設定します。
変数『wand_velocity』はコントローラの持つ加速度を表しているため、
離した時点での加速度がそのままユニットの速度になっているということになります。
加速度の設定が終わったら変数『is_linked』をfalseに変更、
ユニット自身の『Unlinked』イベントを実行しています。
『持ち上げたものを離す』という処理はこのように実装されていました。
一応、この先にもいくつか処理が残ってはいますが、『離す』処理はここで完了です。
■ Hide – Unhide the Controller
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/pick-16.png)
ここでの処理は『物を離した後、コントローラを可視状態にする』というものです。
これはVRテンプレートのバットのユニットフローを見ないとわからないのですが、
一部のユニットは『linked』イベントの処理で
『コントローラを不可視にする』という実装がされています。
ここで可視状態にするという処理を行っていない場合、
バットを離した後でもコントローラが見えないままという問題が発生するため、
この実装が行われています。
ちなみに、ここで使用されている『Set Unit Visibility』は以前使用した時とは異なり、
ユニットそのものを引数で設定しているため、ユニット全体の可視・不可視を変更できています。
■ set_invisable
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/pick-17.png)
その下にある『Event for Hiding the Wand』から続く処理は
『External In Event』ノードから始まる、独立したイベントです。
先ほどの説明で出てきた『コントローラを不可視にする』という処理はここで行われています。
つまり、
コントローラによってバットが持ち上げられる
→バットの持つlinkedイベントが実行される
→バットのlinkedイベントの中でコントローラのset_invisableイベントが実行される
という処理の流れになっています。
一旦両方のコントローラを可視状態にしてから、
不可視に設定するコントローラだけ不可視にしています。
使用しているノードは可視の時から変わりません。
以上で、コントローラの持ち上げ処理は全て見終えることができました。
残っているコントローラ関連の処理はテレポートのみとなります。
残念ながら、StingrayのVRテンプレート調査はこれで終わりですが、
ここまで基礎を理解することができれば、
きっとテレポートの処理を理解することも簡単だと思います。
今まで、ありがとうございました。
今回からは、前回の最後に登場した『function_pickup』ユニットのユニットフローを見ていきます。
コントローラのユニットフローを見てもわかる通り、
『function_pickup』ユニットには『物を持ち上げる』という処理が実装されています。
早速、function_pickupユニットを見ていきましょう。
アセットブラウザから『vr_steam』->『models』->『functionality_pickup』の中にあるユニットを開きましょう。
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/pick-1.png)
なお、画像の赤四角のようなアイコンはユニットフロー単体を表しています。
こちらのアイコンをダブルクリックして開くとユニットエディタとは異なる
ユニットフローを編集するための『FlowEditor』が開かれます。
ユニットフロー以外の要素がなく、
ユニットエディタを開く必要がない場合はこちらを開いてもいいかもしれません。
そうして開かれた『functionality_pickup』のユニットフローが以下の画像です。
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/pick-2.png)
非常に膨大な処理ではありますが、少しずつ進めていきます。
今回、説明していく箇所は、以下の画像で赤・青・緑の枠の部分です。
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/pick-21.png)
■ 『Set Variables on Spawn』
青色の枠の箇所です。
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/pick-4.png)
『Unit Spawned』から始まっていることからわかるかもしれませんが、
ここでは一番最初に行うべき『変数の設定』を行っています。
以下の変数がここで設定されています。
————————————————
スコープ:型:名前
————————————————
ローカル:bool:touch_tracker:False
ローカル:bool:laser_on:False
ローカル:string:my_global_var:wand_extras_1 or 2
グローバル:unit:wand_extras_1 or 2:unit
グローバル:bool:keep_my_rotation_and_position:True
————————————————
■ 『Wand Velocity』
赤色の枠の箇所です。
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/pick-3.png)
『Level Update』にて常に行うべき処理が実装されています。
『Get Unit World Position』を使用して自分のワールド座標を取得し、
その結果を変数『wand_current_frame_pos』に設定しています。
変数『wand_current_frame_pos』は現在位置を表しています。
この部分では変数『wand_current_frame_pos』から
変数『wand_last_frame_pos』の値を減算した値に
『Get Last Delta Time』で取得した時間を除算、
その結果をユニットが持つスクリプトデータの『wand_velocity』と
変数の『wand_velocity』に代入しています。
この値はコントローラの加速度を表しています。
ちなみに、まだ値をセットしている個所の説明をしていませんが、
変数『wand_last_frame_pos』は直前のコントローラの位置をセットしています。
また、『Get Last Delta Time』は
前回の更新から今回の更新までの間に経過した秒数を返します。
つまり、ここの計算は直前と現在のコントローラ位置を比較し、
その差の分を経過秒数で割り、1秒あたりの加速度を計算しています。
最後に、現在のコントローラ位置を
変数『wand_last_frame_pos』にセットしています。
■ 『Collision Events and Variables』
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/pick-5.png)
緑色の枠の箇所です。
『コントローラが特定のユニットに触れている間の処理』が実装されています。
ここの処理の始まりは『Physics Trigger』というノードです。
『Physics Trigger』ノードは『引数に指定したメッシュが特定の対象に触れた時』に呼ばれます。
また、その際に触れているユニットなどを返します。
ここでは、特定のユニットに触れた場合、下記の処理を一気に実行しています。
————————————————
触れた対象が持つ『hilight_on』イベントの実行、
触れている状態を示す変数『wand_is_touching』をTrueに変更、
触れているユニットをユニット変数『touching_unit』に格納、
触れているコントローラを表すグローバル変数『controller_touch_index』を設定。
————————————————
また、ユニットから離れた場合も下記の処理を実行しています。
————————————————
触れた対象が持つ『hilight_off』イベントの実行、
触れている状態を示す変数『wand_is_touching』をFalseに変更。
————————————————
これは、触れているユニットが目で見てわかるようにするための処理となっています。
触れている状態かどうかのフラグもここで立てているため、
ここまで実装できてようやく『物を掴む』処理の準備が整ったことになります。
次回はいよいよ本題となる『物を掴む処理』について見ていきます。
前々回、前回と続いてきた
StingrayVRテンプレートにおけるコントローラの実装調査ですが、
いよいよ今回で最後です。
最後ということで、キーになることも多いです。
ただし、ここで覚えることが
StingrayにおけるVR開発において最も重要なことになります。
最後はこの3つのグループになりますが、
実際は右2つのグループB,Cは左のグループAに繋がっているので、
大きな1つのグループと見ることができます。
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/cont-333.png)
一見ややこしいように見えますが、処理の内容自体はシンプルです。
※『link controllers』
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/cont-10.png)
画像内のグループAで、ここでの処理が終わると、
下で説明している2つのグループB,Cへと続きます。
①外部イベントの作成
ここの処理の始まりとなっているのは『External In Event』です。
このノードは独自にイベントを作ることができ、
外部からこのイベントが呼ばれた際に以後の処理が呼ばれるようになります。
(UnrealEngine4のカスタムイベントなどが近いです)
つまり、
『ここより後の処理はコントローラのユニットフロー単体では動作せず、
外部よりこのイベント(link_controller)が呼ばれた時にのみ実行される』
という事になります。
ちなみに、このVRテンプレートの場合、link_controllerの呼び出し元は
『steam_vr』という名前のLuaスクリプトになります。
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/cont-11.png)
それ以外でも『Level Unit』などのノードからも呼び出すことができます。
②ユニットとコントローラのリンク
続いては『SteamVR Link Node To Tracker』ノードです。
このノードは『Link to』に設定されたHMDやコントローラの位置に
引数に指定したユニットのメッシュをリンクさせる(くっつける)処理です。
これまで、何気なくVR画面でコントローラを動かしていましたが、
VR画面でコントローラが見えていたのはこの処理があったおかげだったのです。
この先ではグループB,グループCに処理が分かれますが、
『どちらかを行う』などではなく、両方の処理を行います。
※『Spawn Pickup Unit to get the Pickup Functionality』
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/cont-12.png)
画像内のグループBです。
ここでは『物を持ち上げる為の前準備』を行っています。
①スクリプトデータをチェック
最初は『Branch』ノードが実行されます。
『Branch』ノードは引数として受け取ったbool型の結果によって
TrueかFalseに処理を分岐させるというノードです。
一般的なプログラムにおけるif文であり、
他のビジュアルスクリプティングにおいても同名で使用されているなど
これなしでプログラムは成り立たないほどの基本的なノードです。
今回はTrueなら処理を続け、Falseなら処理が終了する、といった形になっています。
②持ち上げ処理のスポーン
Trueから続く処理は『Spawn Unit on Position』ノードです。
このノードは引数のUnitに指定したユニットをスポーンさせるという処理を行います。
PositionやRotationをセットするとスポーンさせる位置や向きを指定できます。
ここでスポーンしているのは『functionality_pickup』というユニットになります。
このユニットについてはまた後で説明しますが、
簡単に言うと『対象を持ち上げる処理』になります。
スポーンしたユニットに『Set Unit String Data』を使用してユニット変数controller_indexを設定します。
③スポーンしたユニットとリンク
最後に使用するノードは『SteamVR Link Node To Tracker』です。
今回はコントローラではなく、
先ほどスポーンしたfunctionality_pickupとリンクさせています。
つまり、ここでの処理は
『持ち上げる為の処理をスポーンさせ、コントローラの位置にリンクさせる』
という物です。
※『Spawn Teleport Unit to get the Teleport Functionality』
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/cont-13.png)
画像内のグループCです。
こちらのグループでは『プレイヤーのテレポート処理の前準備』を行っています。
①~③までの処理は②でスポーンしているユニットが
『functionality_teleport』である以外は全く同じです。
④キー入力の取得
更に下側の処理は『Level Update』によって実行されています。
キー入力を取得しており、前々回でも登場した『SteamVR Touch』を使用しています。
ただし、今回は入力された座標が欲しいわけではないため、使用する返り値は
入力した時/離した時を表すPressed/Releasedのみです。
⑤外部イベントの呼び出し
Pressed/Releasedの両方から、『Unit Flow Event』に繋がっています。
『Unit Flow Event』はユニットが持つ外部イベントを呼び出すノードです。
つまり、
Pressedの場合はfunctionality_teleportが持つ『press_teleport』イベント、
Releasedの場合は同じくfunctionality_teleportが持つ『release_teleport』イベント
へと処理が続きます。
これで、コントローラのユニットフローの処理は一通り見ることができました。。
しかし、今回の調査で新しくfunctionality_pickupとfunctionality_teleportという新しいユニットが出てきました。
次回からはこの2つのユニットフローについて、ご説明していきます。
前回から引き続き、今回もコントローラの内部処理(ユニットフロー)を見ていきます。
今回はこの2つのグループの処理を見ていきます。
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/cont-32.png)
※『Create Unit Variable on Spawn – wand_1 or wand_2』
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/cont-8.png)
このグループではコントローラが『一番最初に行うべき処理』が実装されています。
①スポーン直後に待機する
処理の開始位置となっている『Unit Spawned』は『ユニットが生成されたタイミング』を表しています。
この場合であれば『Viveコントローラが認識され、レベルに出てきたタイミング』です。
『Unit Spawned』からは『Delay』ノードに繋がっています。
Delayノードは引数に設定された時間だけ処理を止めるという処理です。
無くてもいいと感じるかもしれませんが、
この先のフローが何らかの形で本来先に実行される処理よりも
先に実行されてしまうと、問題が発生する場合などに用いられます。
②ユニット変数を作成
続いて実行される『Set Unit Variable』で
ユニットを格納するための変数を作成します。
変数名は前回にも触れたcontroller_indexに『wand_』という文字列を繋げた物です。
③ボールを不可視に
最後は『Set Unit Visibility』で最初は表示されたままだったボールを不可視にしています。
つまり、ここでは
『一番最初に、コントローラによってユニットに
識別用に異なる名前を付け、トラックパッド上のボールを不可視にする』
という初期化の処理をしています。
※『pull trigger』
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/cont-9.png)
このグループは、前回のトラックボールと同じように入力に関係した処理を行っています。
①トリガーの入力を取得する
基本的な入力の取得方法は前回と同じです。
ただし、今回は使用するノードが『SteamVR Touch』ではなく、『SteamVR Button』になっています。
この二つの違いは、入力を取得する対象が『トラックパッドの位置』か、それとも『それ以外のボタン入力』かという点のみです。
(一応Buttonの方でもトラックパッドの入力は取得できますが、位置までは拾えません)
②トリガーの入力を基に回転値の計算
続いて、『SteamVR Button』のValue値を乗算しています。
これも前回と同じですね。
ただし、『SteamVR Button』の入力範囲は0~1なので、
計算する際には注意してください。
(Touchの場合はX/Yそれぞれ-1~1の範囲)
ここでの乗算は-30ですが、これで最小値0、最大値-30の結果が得られます。
最後にこの結果を『Rotation From Components』のXにセットして、回転値にします。
(ここでは一方向にだけ回転させることが目的なので、X以外の値は0で固定です。)
③回転値のセット
最後に『Set Unit Local Rotation』でこのユニットが持つ『trigger』メッシュのローカル回転値を②の結果に設定しています。
ここまで来ればわかるかもしれませんが、ここでの処理は
『コントローラのトリガーがどれだけ引かれているかを取得し、
引かれている分だけ画面内のトリガーを回転させる(引く)』
という処理になります。
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/tr.gif)
今回はここまでです。
いつもよりも簡単な箇所でしたので物足りなかったかもしれません。
次回はコントローラのユニットフローを最後まで見ていきます。
Stingrayのビジュアルスクリプティング機能、『Flow』では、
最初のテンプレートの選択によってVRに特化したノードを使用することができるため、
簡易的な物であれば建築分野用のVRデモなどを実装することもできます。
今回は、VR特化のノードについて、用途ごとに以下にまとめてみることにします。
ちなみにSteamVR(HTC Vive)用のノードを例にして挙げていますが、
StingrayにはOculus/GoogleVR/GearVR用のノードもあります。
ただし、どのHMDでも内容はほぼSteamVRと同一の為、割愛します。
最初に注意点ですが、
VR用ノードはStingrayのVRテンプレート実行時に同時に作成されるという仕様のため、
プロジェクト作成時に『VR HTC Vive』テンプレートを選択しないと、下記のノードが使用できません。
(使用するHMDによってテンプレートを選択してください)
※Viveコントローラの入力を取得したい
・SteamVR Button
![画像1](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/str-1-300x169.png)
このノードはUpdateピンに接続されたタイミングで
『Controller Index』に設定されたコントローラの
『Button Name』に設定されているボタンが押されたかどうかを取得し、
処理を分岐させています。
ボタンの割り当てはViveの公式ドキュメントを参考にしてください。
(尚、システムボタンだけどういうわけか反応がありませんでした)
『Pressed』は最初にボタンが押された時、
『Held』はボタンを押し続けている時、
『Released』はボタンから指を離した時にそれぞれ呼ばれます。
『Value』は入力の状態を0~1の範囲で返します。
(指を離している時が0、完全に押し込んだ時が1。)
以下はトリガーの入力の範囲をログに出力するサンプルです。
画像のようにノードを接続しています。
![](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/nr.gif)
![画像2](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/str-2-300x144.png)
・SteamVR Touch
こちらのノードは上述したButtonの『Touch Up』~『Touch Right』までをより詳細にしたノードです。
Buttonの方と同じ、『Pressed』『Held』『Released』の他、
タッチパッドに触れている間呼ばれ続ける『Touched』と
タッチパッドから指を離したときに呼ばれる『Untouched』が追加されています。
X/Yは指先が触れている座標を中央を0として1~-1の範囲で返します。
ちなみに、どちらも『SteamVR』->『Input』の中にあります。
※Viveコントローラに振動を与えたい
・SteamVR Controller Feedback
![画像3](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/str-3-300x129.png)
このノードは『Controller Index』に設定されたコントローラに対し、
『Seconds』秒間の振動を与えます。
ただし、0.003999以上の値を設定すると、
強制的に0.003999に合わせられてしまいます。
VRのデモなどで『何かに触れた』という事を表す場合は単体で使用すればよいのですが、
ゲームなどの演出のように、長期的に振動させたい場合は、
画像のように連続で呼ばれるような処理を作る必要があります。
※HMDの画面をフェードさせたい
・SteamVR Fade In
・SteamVR Fade Out
![画像4](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/str-4-300x126.png)
シーン移動や演出の為に画面にフェードを入れたい場合はこれらのノードを使用します。
『Color』には何色にフェードするか、
『Seconds』には何秒でフェードが完了するかを設定します。
基本的には『Fade In』と『Fade Out』をセットで使用すると思います。
なお、フェードするのはHMDの画面だけですので、
HMDではない通常の画面をフェードさせたい場合は、別途処理を追加する必要があります。
※HMDとの接続やトラッキング状態をチェックしたい
・SteamVR Is Enabled
・SteamVR Is Tracked
![画像5](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/str-5-300x118.png)
『Is Enabled』はViveが有効に接続されているかどうかをチェックします。
あくまで、『有効であるか』だけをチェックするため、『トラッキングされているか』は考慮されません。
『トラッキングされているか』をチェックしたい場合、『Is Tracked』の方を利用します。
引数に設定した対象がトラッキングされているかどうかをチェックします。
※コントローラやHMDの位置を取得したい
・SteamVR HMD Pose
・SteamVR Controller Pose
![画像6](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/str-6-300x139.png)
『HMD Pose』はHMDの頭や左右の目の位置の座標や回転、
『Controller Pose』は各種コントローラの位置や回転を取得できます。
どちらもワールド・ローカルを選択できます。
![画像0](http://mankindinc.jp/wp01/wp-content/uploads/2017/08/str-0-300x70.png)
また、このブログで触れたノードは全てLuaによる実装が行われています。
更に踏み込んだ実装の調査をしたい場合は、直接Luaのソースコードをチェックしてみてください。
Oculus もお手頃な価格になってきましたし、以前より気軽に試すことができる環境が整ってきました。
ただ安くはない買い物ですし、自分のPCで動作するかを事前に確認したいですよね。NvidiaとかGeForceとか何それ。よくわからない。知りたいのはVR Readyなの? Readyじゃないのといったところかと思います。
さすがOculus!ツールをしっかり用意してくれています。
https://ocul.us/compat-tool
チェックしてくれる項目は
-Graphics Card
-Processor
-Memory
-Operating System
-USB< 各項目が動作に必要なスペックを満たしているかどうかを知らせてくれます。 ![](http://mankindinc.jp/wp01/wp-content/uploads/2017/06/vr_not_ready-200x300.png)
インストールが必要ですが、実行するだけでVR readyかどうか判定してくれて大変便利です。
Oculus Riftを購入を検討中であればお持ちのPCで一度試してみられるのもいいかもしれません。
推奨、最小スペックなどは下記のURLに記載があります。
https://support.oculus.com/1639441692997293