Unity_PostProcessing機能の有効化

あるシーンが、「PostProcessingのエフェクトが適用されているシーンのはずなのに自分のPCで開くと見た目が通常と変わらない。」
上記のような場合は、Unity PostProcessing Stackがインストールされているかをチェックしてみてください。

確認方法は下記のとおりです。
1.メニューバーのWindow->Package Manager をクリック。

inst_PostProcessing_Stack01_Image
inst_PostProcessing_Stack01_Image
Image_of_inst_PostProcessing_Stack02
inst_PostProcessing_Stack02_Image

2.Allのタブ(①)をクリックし、スクロールダウンしてPost Processing(②)を選択します。
3.右上のInstallボタン(③)を押してインストールします。

この手順でシーンのカメラに設定された、Post Processingの効果が確認できると思います。

(Unity3D)ダイナミックボタンアクション

あるゲームのUIを作っている間にボタンに関する問題に遭遇しました。選択されたエンティティによって、表示されているボタンが変わるようにしたいと思いました。

もちろん一つずつのエンティティのGameObjectを準備して場合によってSetActive()trueかfalseにしてもいいですが、スケーラビリティは?エンティティを追加しようとする毎に新しいGameObjectを準備しますか?そんな面倒なことは勘弁してほしいですよね。

ということでスケーラビリティのため、エンティティを選択する時にボタンが編集され、ちょっとしたアルゴリズムを書きました。 

こういうシステムが入っているUIを作る人がいて参考になればと思い、分かりやすいバージョンを準備して下記にそのケースを紹介します。 

想定ケース: 

1.エンティティによる、ボタンの数が異なる場合でもOK。 

2.ボタンの見た目を編集可能にする。 

3.ボタンのアクションがstringの引数を受け取れる。 

4.簡単にするため、ボタンの最大数は10にします。 

先ずはボタンの情報をまとめるクラスActivityButtonをつくります 

public class ActionButton {
    public UnityAction<string> theAction;
    public string argument;
    public Sprite sprite;
    public ActionButton(UnityAction<string> act, Sprite sprite, string arg=""){
        theAction = act;
        argument=arg;
        this.sprite = sprite;
    }
}

UIマネージャーにはButton、Image、GameObjectの配列を必要です。パブリックなGameObjectの配列を作ってシーンからボタンをドラッグして、Start()でButtonとImageの配列を作りました 

public class MyEpicUIManager : MonoBehaviour {
    Button[] actionBtns;
    Image[] actionImgs;
    public GameObject[] actionBtnObjs;

    void Start () { 
        // Action Panel Setup
        actionBtns = new Button[actionBtnObjs.Length];
        actionImgs = new Image[actionBtnObjs.Length];
        for(int i=0; i<actionBtnObjs.Length; i++){
            actionBtns[i]=actionBtnObjs[i].GetComponent<Button>();
            actionImgs[i]=actionBtnObjs[i].GetComponent<Image>();
        } 
    }
}

ボタンをゲットしたので、次はActionButtonのリストを取得しボタンを編集するメソッドを作りました。そしてボタンをクリアするメソッドも必要です。 

public void SetActions(List<ActionButton> btnActions){
    ClearActions();
    for(int i=0; i<btnActions.Count; i++){
        actionBtnObjs[i].SetActive(true); 
        UnityAction<string> action = btnActions[i].theAction;
        string arg = btnActions[i].argument;
        actionBtns[i].onClick.AddListener(()=>action(arg)); 
        actionImgs[i].sprite = btnActions[i].sprite; 
    } 
}

public void ClearActions(){
    for(int i = 0; i<actionBtnObjs.Length; i++){
        actionBtns[i].onClick.RemoveAllListeners();
        actionBtnObjs[i].SetActive(false);
    }
}

これでUIマネージャーが完了です。Start()でClearActionsを呼べば、ゲームを起動する際にボタンクリアできます 

エンティティにはそれそれに自分のActionButtonリストが必要です。UIマネージャーのSetActionsを呼べるようにする必要があります。そしてアクション自体も必要です。

public class MyEntity1 : MonoBehaviour {
 
    public MyEpicUIManager ui;
    List<ActionButton> uiActions = new List<ActionButton>();

    void Start(){
        uiActions.Add(new ActionButton(Action1,Resources.Load<Sprite>("Sprites/E1A1"))); 
        uiActions.Add(new ActionButton(Action2,Resources.Load<Sprite>("Sprites/E1A2"), "Test argument 1")); 
        uiActions.Add(new ActionButton(Action2,Resources.Load<Sprite>("Sprites/E1A2"), "Test argument 2")); 
        uiActions.Add(new ActionButton(Action3,Resources.Load<Sprite>("Sprites/E1A3"), "3"));
        uiActions.Add(new ActionButton(Action3,Resources.Load<Sprite>("Sprites/E1A3"), "5")); 
    }

    // An action that doesn't really use the string provided 
    public void Action1(string s =""){
        print("Entity 1 Action 1");
    }

    // An action that uses the string
    public void Action2(string s =""){
        print("Entity 1 Action 2 Argument: " + s);
    }

    // An action that changes the string to an int
    public void Action3(string s =""){
        string msg = "Entity 1 Action 3 ->"+s+" hashes: ";
        int n = 0;
        int.TryParse(s, out n);
        for(int i=0; i <n; i++) msg+="#";
        print(msg);
    }

    public void OnSelect(){
        ui.SetActions(uiActions);
    }
} 
public class MyEntity2 : MonoBehaviour {
 
    public MyEpicUIManager ui;
    List<ActionButton> uiActions = new List<ActionButton>();

    void Start(){
        uiActions.Add(new ActionButton(Action1,Resources.Load<Sprite>("Sprites/E2A1"))); 
        uiActions.Add(new ActionButton(Action2,Resources.Load<Sprite>("Sprites/E2A2"), "Test argument 1")); 
        uiActions.Add(new ActionButton(Action2,Resources.Load<Sprite>("Sprites/E2A2"), "Test argument 2")); 
        uiActions.Add(new ActionButton(Action2,Resources.Load<Sprite>("Sprites/E2A2"), "Test argument 3"));
        uiActions.Add(new ActionButton(Action3,Resources.Load<Sprite>("Sprites/E2A3"), "3"));
        uiActions.Add(new ActionButton(Action3,Resources.Load<Sprite>("Sprites/E2A3"), "5")); 
        uiActions.Add(new ActionButton(Action3,Resources.Load<Sprite>("Sprites/E2A3"), "7")); 
    }

    // An action that doesn't really use the string provided 
    public void Action1(string s =""){
        print("Entity 2 Action 1");
    }

    // An action that uses the string
    public void Action2(string s =""){
        print("Entity 2 Action 2 Argument: " + s);
    }

    // An action that changes the string to an int
    public void Action3(string s =""){
        string msg = "Entity 2 Action 3 ->"+s+" asteriscs: ";
        int n = 0;
        int.TryParse(s, out n);
        for(int i=0; i <n; i++) msg+="*";
        print(msg);
    }

    public void OnSelect(){
        ui.SetActions(uiActions);
    }
}

こちらはエンティティのサンプルです。OnSelectはキーボードかシーン上のボタンで試してみてください。このサンプルを動かすため “Assets/Resources/Sprites”に、正しい名前のスプライトを入れてください。そしてスプライトのImport SettingsのTexture Typeは “sprite (2D and UI)”にする必要があります。 

シーンに必要なものはCanvasと7つ以上のボタンです。UIマネージャーをシーンに追加して、インスペクターでボタンをドラッグします。エンティティもシーンに追加してインスペクターでUIマネージャーをドラッグしてください。 

それで完了です。短くて簡単な例となりますが、これでエンティティを追加ときにいちいち新しいパネルを準備する必要がなくなります。そしてアクションを追加したり削除する場合でも、リストから追加したり削除することで実現できます。

Stingray(VRテンプレート)の持ち上げ処理を調べてみる
(離す処理)


前回、ついに『持ち上げる処理』の実装を全て見終えました。
しかし、これまで見た処理はあくまで『持ち上げる』というだけの処理です。

今回は、『持ち上げたものを離す』処理を最後まで見ていきます。



■ Un-link – Release



赤の部分は『トリガーが離された時』に実行されています。
画像だとやや見づらいので、
この画像を更に黄色・オレンジに区切って詳細に見ていきます。

①離したコントローラがリンクされているかチェック



まずは、持ち上げている状態かどうかを表す変数『is_linked』
true(持ち上げている状態)なのかをチェック、
『ユニットを持ち上げているコントローラ』『トリガーを離したコントローラ』が同一かもチェックします。

②コントローラとのリンクを外し、加速度を設定する



続いて、『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



ここでの処理は『物を離した後、コントローラを可視状態にする』というものです。

これはVRテンプレートのバットのユニットフローを見ないとわからないのですが、
一部のユニットは『linked』イベントの処理で
『コントローラを不可視にする』
という実装がされています。
ここで可視状態にするという処理を行っていない場合、
バットを離した後でもコントローラが見えないままという問題が発生するため、
この実装が行われています。

ちなみに、ここで使用されている『Set Unit Visibility』は以前使用した時とは異なり、
ユニットそのものを引数で設定しているため、ユニット全体の可視・不可視を変更できています。



■ set_invisable



その下にある『Event for Hiding the Wand』から続く処理は
『External In Event』ノードから始まる、独立したイベントです。

先ほどの説明で出てきた『コントローラを不可視にする』という処理はここで行われています。
つまり、
コントローラによってバットが持ち上げられる
→バットの持つlinkedイベントが実行される
→バットのlinkedイベントの中でコントローラのset_invisableイベントが実行される
という処理の流れになっています。

一旦両方のコントローラを可視状態にしてから、
不可視に設定するコントローラだけ不可視にしています。
使用しているノードは可視の時から変わりません。



以上で、コントローラの持ち上げ処理は全て見終えることができました。
残っているコントローラ関連の処理はテレポートのみとなります。
残念ながら、StingrayのVRテンプレート調査はこれで終わりですが、
ここまで基礎を理解することができれば、
きっとテレポートの処理を理解することも簡単だと思います。

今まで、ありがとうございました。

Stingray(VRテンプレート)の持ち上げ処理を調べてみる
(持ち上げ編)


今回も引き続き、『物を掴む処理』を見ていきます。
次回を含め、覚えることが盛りだくさんです。



画像の中の青い部分は前回にやった『物に触れている間の処理』です。
緑の部分はまだ特に触れてはいませんが、
基本的にいつも通りの入力(トリガー)を拾う処理の為、割愛します。



■ 状態のチェック

コントローラのトリガーを引いた際にオレンジの部分の処理が行われます。



ここでは、触れている物の状態をチェックし、『持ち上げることができるか』を判定しています。

◯ Is the Wand Touching an Object?

最初に、変数『wand_is_touching』の値で『Branch』ノードを実行しています。
この変数は前回の『Physics Trigger』の処理で何かに触れている時にTrueに変更されています。

つまり、『何かに触れているか』をチェックしています。

◯ check for no pick up in unit data

Trueならば今度は変数『touching_unit』の値が持つ『pick_up』のデータと『no』を
『Compare Objects』ノードで比較しています。

『Compare Objects』ノードは、A・Bに渡された値が同じであるかどうかを返します。

まとめると、ここでは
『触れているユニットが持つ持ち上げられる物体かどうかのデータを見て、その内容がnoであるかどうか』
をチェックしています。

◯ Is the Actor Dynamic?

上記処理で等しくなかった(noではなかった)場合、
『Is Actor Dynamic』ノードの結果がTrueであるかという処理を行っています。

『Is Actor Dynamic』ノードは、『Actor』に指定された物体が動的であるかどうかを返します。

つまり、『持ち上げようとしている物体が動かせるものか』という確認になります。

ここまでの処理で、『物体を持ち上げるまでの確認』が完了しました。



■ Attach the Object to the Wand



続いて、物体を持ち上げる処理を見ていきます。
画像の中の黄色のエリアですが、
かなり量が多いので幾つかのグループに分割して処理を見ていきます。

①対象を動かせるようにする



まず、『SteamVR Set Actor Kinematic』を使用して、対象を自由に動かせるようにします。

②スナップをきかせるかどうかをチェック



続いて、現在触れているユニットがスナップをきかせるような物(バット)であるかをチェックするために、
触れているユニットが持つ『snap』というスクリプトデータが『yes』かどうかをチェックしています。



『snap』が『yes』である場合、
『preserve_world』をFalseに変更し、
ユニットのローカル位置とローカル回転を0に変更しています。
こうすることで、どんな状態の物を拾っても必ず同じ位置、同じ向きに向くようになります。

『snap』が『yes』以外であった場合、
『preserve_world』をTrueに変更します。

どちらの場合でも終了後は次の処理に遷移します。

③リンク付けを行う



次は『SteamVR Unlink Node From Tracker』を使用して、
現在手に触れている物のリンクを外しています。

その後、コントローラに対してユニットのリンク付けを行います。

④各種イベントの実行と変数の設定



最後に、リンク付け後に必要な処理を行っています。
コントローラがリンク中であるかを示す変数『is_linked』をTrueにしてから
『Sequence』ノードに続いています。
『Sequence』ノードは上から順に繋げられた処理を実行するというものです。
実装に必須な処理というわけではありませんが、
『Flow』の可読性向上に役立つことが多いです。

持ち上げたユニットの『pickup_sound』イベントの実行、
持ち上げられたユニットにコントローラの情報をセット、
持ち上げたユニットの『Linked』イベントの実行、
持ち上げたユニットの『hilight_off』イベントの実行。
という順に行っています。

こうすることで、『対象を持ち上げる処理』は実装されています。
しかし、これだけではまだ『対象を手放す』事はできません。



次回は、『対象を手放す処理』を見ていきます。

Stingray(VRテンプレート)のコントローラ処理を調べてみる
(リンクとスポーン)

前々回前回と続いてきた
StingrayVRテンプレートにおけるコントローラの実装調査ですが、
いよいよ今回で最後です。


最後ということで、キーになることも多いです。
ただし、ここで覚えることが
StingrayにおけるVR開発において最も重要なことになります。

最後はこの3つのグループになりますが、
実際は右2つのグループB,Cは左のグループAに繋がっているので、
大きな1つのグループと見ることができます。



一見ややこしいように見えますが、処理の内容自体はシンプルです。



※『link controllers』



画像内のグループAで、ここでの処理が終わると、
下で説明している2つのグループB,Cへと続きます。

①外部イベントの作成

ここの処理の始まりとなっているのは『External In Event』です。
このノードは独自にイベントを作ることができ、
外部からこのイベントが呼ばれた際に以後の処理が呼ばれるようになります。
(UnrealEngine4のカスタムイベントなどが近いです)

つまり、
『ここより後の処理はコントローラのユニットフロー単体では動作せず、
外部よりこのイベント(link_controller)が呼ばれた時にのみ実行される』

という事になります。

ちなみに、このVRテンプレートの場合、link_controllerの呼び出し元は
『steam_vr』という名前のLuaスクリプトになります。



それ以外でも『Level Unit』などのノードからも呼び出すことができます

②ユニットとコントローラのリンク

続いては『SteamVR Link Node To Tracker』ノードです。
このノードは『Link to』に設定されたHMDやコントローラの位置に
引数に指定したユニットのメッシュをリンクさせる(くっつける)処理です。

これまで、何気なくVR画面でコントローラを動かしていましたが、
VR画面でコントローラが見えていたのはこの処理があったおかげだったのです。

この先ではグループB,グループCに処理が分かれますが、
『どちらかを行う』などではなく、両方の処理を行います。



※『Spawn Pickup Unit to get the Pickup Functionality』



画像内のグループ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』



画像内のグループ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_pickupfunctionality_teleportという新しいユニットが出てきました。
次回からはこの2つのユニットフローについて、ご説明していきます。

Stingray(VRテンプレート)のコントローラ処理を調べてみる
(初期化とトリガー)


前回から引き続き、今回もコントローラの内部処理(ユニットフロー)を見ていきます。

今回はこの2つのグループの処理を見ていきます。



※『Create Unit Variable on Spawn – wand_1 or wand_2』



このグループではコントローラが『一番最初に行うべき処理』が実装されています。

①スポーン直後に待機する

処理の開始位置となっている『Unit Spawned』『ユニットが生成されたタイミング』を表しています。
この場合であれば『Viveコントローラが認識され、レベルに出てきたタイミング』です。

『Unit Spawned』からは『Delay』ノードに繋がっています。
Delayノードは引数に設定された時間だけ処理を止めるという処理です。

無くてもいいと感じるかもしれませんが、
この先のフローが何らかの形で本来先に実行される処理よりも
先に実行されてしまうと、問題が発生する場合などに用いられます。

②ユニット変数を作成

続いて実行される『Set Unit Variable』
ユニットを格納するための変数を作成します。
変数名は前回にも触れたcontroller_indexに『wand_』という文字列を繋げた物です。

③ボールを不可視に

最後は『Set Unit Visibility』で最初は表示されたままだったボールを不可視にしています。

つまり、ここでは
『一番最初に、コントローラによってユニットに
識別用に異なる名前を付け、トラックパッド上のボールを不可視にする』

という初期化の処理をしています。



※『pull trigger』



このグループは、前回のトラックボールと同じように入力に関係した処理を行っています。

①トリガーの入力を取得する

基本的な入力の取得方法は前回と同じです。

ただし、今回は使用するノードが『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』メッシュのローカル回転値を②の結果に設定しています。

ここまで来ればわかるかもしれませんが、ここでの処理は
『コントローラのトリガーがどれだけ引かれているかを取得し、
引かれている分だけ画面内のトリガーを回転させる(引く)』

という処理になります。



今回はここまでです。
いつもよりも簡単な箇所でしたので物足りなかったかもしれません。

次回はコントローラのユニットフローを最後まで見ていきます。

Stingray(VRテンプレート)のコントローラ処理を調べてみる
(トラックパッドとユニットフロー)

前回は『Flow』による簡易的なプログラムを組んでみました。
今回からは本格的な要素に入ります。


StingrayのVRテンプレートでは
非常に軽い建築デモ程度であればそのまま使えてしまえるような機能が最初から実装されています。

それらの機能がどのように実装されているのか、少しずつ処理の解説を交えつつ、見ていきましょう。

今回、見ていく処理は『コントローラの処理』になります。

さて、前回ではFlowの一種である『レベルフロー』を見ていきましたが、
いくらレベルフローを見てみたとしても、コントローラの処理と思しきものはどこにもありません。

なぜなら、コントローラの処理はコントローラ自身にあるためです。

まずは、どこでコントローラ自身の処理が見られるのか、についてです。

エディタの画面の下側にあるタブを見てみましょう。

これは『アセットブラウザ』と呼ばれ、
現在開いているプロジェクトの中にあるモデルや音などのアセットを見ることができます。

この中に、コントローラのモデルがあります。
アセットブラウザの左側にあるリストから
『VR_steam』->『models』->『controller』を選択します。
すると、コントローラのモデルが見つかるはずです。



このモデルをダブルクリックしましょう。



※ユニットエディタとユニット

モデルをダブルクリックすると、画像のような画面が開かれます。



この画面は『ユニットエディタ』といい、『ユニット』を編集する画面です。

『ユニット』とは、レベルに配置されるものの名前であり、
一つ一つがメッシュや各種プロパティを持っています。

また、ユニット自身がFlowを持つこともでき、
ユニットが所持するFlowは『ユニットフロー』と呼ばれます。

そして、ユニットエディタではユニットのプロパティの変更や、
ユニットフローの編集などを行うことができます。

画面の下側にある『Unit Flow』タブをクリックして開いてください。



こうして開かれるのがユニットフローの画面です。
細かな点や用途に違いはありますが、基本的な部分はレベルフローと変わりません。

今回は、ここに実装されている処理の内容を調べていきましょう。

コントローラのユニットフローを見てみると、
複数のノードが一つのブロックに囲まれているのがわかるかと思います。

これは『グループ化』といい、いくつかのノードを一つのグループにまとめ、
一括で削除したり、移動したりできるようにする機能です。
また、グループには名前を付けることができ、
Flowの可読性を向上させるという事もできます。

コントローラのユニットフローでは6つのグループがあります。

この記事では、このうちの1つのグループの処理について調べていきます。



※『Tracking dot on the track pad.』



このグループでは『トラックパッド上のボールの移動』が実装されています。



プレイ中、コントローラを見てみるとトラックパッドを操作している間、
指を触れている個所にボールが出現しているはずです。

試しに、このグループを削除してからプレイしてみると、ボールが出現しなくなります。
ちなみに、グループをまるごと削除するためには、グループのタイトルの部分をクリックしてからDeleteキーを入力します。

①トラックパッドの入力を取得



『Get Unit String Data』ノードは
ユニットに設定されているKeyと同名のスクリプトデータを取得します。

『スクリプトデータ』とはユニットがそれぞれ持つ数値などで、
プログラムでいうところの『変数』のような役割を持ちます。

ユニットエディタの右側にある『Script Data』から、追加や削除ができます。

コントローラのスクリプトデータを確認してみると、
『Get Unit String Data』で指定されている
『controller_index』というキーが見つかるはずです。
このキーはコントローラの番号を示しています。

controller_indexの値は『Level Update』に接続された
『SteamVR Touch』ノードの引数に用いられています。

これで『番号で指定されたコントローラのトラックパッドの入力を取得する』という処理になります。

②ボールの出現位置の計算
『SteamVR Touch』のX/Yの値は、トラックパッドで入力されている座標を1~-1の範囲で表しています。
この値を『Multiplication』ノードで乗算しています。
これは、そのままX/Yの座標を使用してしまうと、値が大きすぎてトラックパッドからボールが離れてしまうためです。
乗算の結果は『Vector From Components』で使用され、ベクトルになります。
このベクトルは最終的にボールの出現位置のローカル座標となりますが、
ここではYの値をYではなくZに代入する必要があるため要注意です。

最終的なYの値になるのは、先ほどの計算結果に更に乗算を重ねたものとなります。
この結果がトラックパッド上のボールの高さとなります。

③ボールのメッシュの可視・不可視を変更
『トラックパッドに指が触れた』事を表す『Touched』と接続しているのは
『Set Unit Visibility』ノードです。
このノードは引数のユニット内の指定したグループに該当するメッシュの可視性を変更するという処理を行います。
この場合の『グループ』は『ビジビリティグループ』の事であり、ユニットフローのノードの『グループ』とは異なります


『ビジビリティグループ』とは、
ユニットが持つメッシュをひとまとめにした物であり、
メッシュの可視・不可視を一括で変更したりする場合に役立ちます

ビジビリティグループはユニットエディタ右下の『Visibility Groups』から
変更や新規追加、確認が可能です。
また、ユニットが持つメッシュは画面左側の『Outliner』から確認できます。

コントローラのビジビリティグループを確認してみると、
『trackpad_touch』というグループだけが見つかるはずです。
グループ名をクリックすると、そのグループに含まれるメッシュが確認できます
『trackpad_touch』のグループには
『trackpad_touch』というメッシュだけが含まれています。

画面左側のアウトライナから『trackpad_touch』というメッシュをクリックし、
画面下側の『Viewport』タブを選択すると、
『trackpad_touch』がトラックパッド上のボールを示していることがわかります。



再度ユニットフローを見てみると、同じノードが『トラックパッドから指が離れた』事を表す『Untouched』と接続されています。
先ほどの『Set Unit Visibility』と異なるのは、引数のVisibleがこちらではFalseになっているという点です。

この時点で、『指が触れるとボールが出現し、離れるとボールが消える』という処理になっていることがわかるはずです。

④ボールを移動
最後にボールを出現させる処理から繋がっている『Set Unit Local Position』です。
このノードは引数に設定されたユニットのオブジェクトのローカル座標をPositionの値に変更します。
今回は、trackpad_touchメッシュを②の結果に変更しています。
この部分で『ボールを指に触れた場所へ移動させる』という処理が実装されています。

つまり、このグループ全体では
『トラックパッドに指が触れている間、ボールを可視にし、指が触れている箇所にボールを移動させる。
トラックパッドから指が離れたら、ボールを不可視にする』

という実装が組まれていることになります。



若干中途半端ですが、今回はここまでです。
次回は、このコントローラのユニットフローの中で、
2つか3つのグループの処理を説明していきます。

StingrayVRテンプレートのVR向けノードをまとめてみた


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

このノードはUpdateピンに接続されたタイミングで
『Controller Index』に設定されたコントローラの
『Button Name』に設定されているボタンが押されたかどうかを取得し、
処理を分岐させています。
ボタンの割り当てはViveの公式ドキュメントを参考にしてください。
(尚、システムボタンだけどういうわけか反応がありませんでした)

『Pressed』は最初にボタンが押された時
『Held』ボタンを押し続けている時
『Released』ボタンから指を離した時にそれぞれ呼ばれます。
『Value』入力の状態を0~1の範囲で返します。
(指を離している時が0、完全に押し込んだ時が1。)

以下はトリガーの入力の範囲をログに出力するサンプルです。
画像のようにノードを接続しています。



画像2

・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

このノードは『Controller Index』に設定されたコントローラに対し、
『Seconds』秒間の振動を与えます
ただし、0.003999以上の値を設定すると、
強制的に0.003999に合わせられてしまいます。


VRのデモなどで『何かに触れた』という事を表す場合は単体で使用すればよいのですが、
ゲームなどの演出のように、長期的に振動させたい場合は、
画像のように連続で呼ばれるような処理を作る必要があります。



※HMDの画面をフェードさせたい


・SteamVR Fade In
・SteamVR Fade Out


画像4

シーン移動や演出の為に画面にフェードを入れたい場合はこれらのノードを使用します。
『Color』には何色にフェードするか、
『Seconds』には何秒でフェードが完了するかを設定します。
基本的には『Fade In』と『Fade Out』をセットで使用すると思います。

なお、フェードするのはHMDの画面だけですので、
HMDではない通常の画面をフェードさせたい場合は、別途処理を追加する必要があります。



※HMDとの接続やトラッキング状態をチェックしたい


・SteamVR Is Enabled
・SteamVR Is Tracked


画像5

『Is Enabled』はViveが有効に接続されているかどうかをチェックします。
あくまで、『有効であるか』だけをチェックするため、『トラッキングされているか』は考慮されません

『トラッキングされているか』をチェックしたい場合、『Is Tracked』の方を利用します。
引数に設定した対象がトラッキングされているかどうかをチェックします。



※コントローラやHMDの位置を取得したい


・SteamVR HMD Pose
・SteamVR Controller Pose


画像6

『HMD Pose』はHMDの頭や左右の目の位置の座標や回転
『Controller Pose』は各種コントローラの位置や回転を取得できます。
どちらもワールド・ローカルを選択できます。

画像0



また、このブログで触れたノードは全てLuaによる実装が行われています。
更に踏み込んだ実装の調査をしたい場合は、直接Luaのソースコードをチェックしてみてください。

Flowの基礎について


前回は、Stingrayの基本と、テストプレイまで紹介しました。
今回はStingrayによる開発で、最も重要になると思われる
『Flow』についてご紹介します。


1.Flowとは何か

『Flow』とは、Stingrayに基本搭載されているビジュアルスクリプティング機能です。
そもそも、ビジュアルスクリプティングとは『視覚的にプログラムが組める機能』といった感じです。
有名なものでいえば、UnrealEngine4の『Blueprint』や、初心者向けのプログラミング言語の『Scratch』などがありますね。

ビジュアルスクリプティングの利点として、
『プログラムに触れたことのない初心者に優しい』『一目でどのような処理かわかりやすい』という点があります。
もちろん、普通のプログラムができないわけではなく、StingrayではLuaにてプログラミングが行えます


2.フローの開きかた

今回はまず、前回に作成したプロジェクトのFlowを開いてみます。
VRテンプレートのエディタの『Level Viewport』のタブのすぐ右側にある『Level Flow』タブを開きましょう。
『Level Flow』タブが見つからない場合は、『Window』のドロップダウンメニューを開き、
『Level Flow』を選択してください。


画像1

すると、画像のようなエディタが開かれるはずです。
これは『レベルフロー』といい、Flowの一種です。

たくさんのブロックが線で繋がっているのが見えます。
これがビジュアルスクリプティングにおけるプログラムになります。


3.Flowの基礎(ピンとノード)

Flowにおけるブロックは『ノード』と呼ばれ、
『特定の値を拾う』『操作を受け付ける』等といった機能が、ブロックごとに設定されています。
Stingrayではこのブロックとブロックを線で繋ぎ、プログラミングをやっていきます。

今のままでは、画面がよく見えないため、Flowを拡大しましょう。
Flowの拡大/縮小はマウスホイールで行えます。
また、ホイールクリックでFlowの移動もできます。



画像は先ほどのFlowの左上の部分を拡大したものです。
ノードにいくつかの○があるのが見えます。
この○は『ピン』といい、ノードに入力する値(引数)か、
ノードから出力される値(返り値)を表します。
左側の○が引数、右側の○が返り値となります。
線はこのピンから伸び、また別のノードのピンに繋がります。

線とピンにはそれぞれ色がついています。
この色は、その線とピンが『何を表しているか』を示しています。
どの色が何を表すか、については今後必要に応じて説明するため、
現時点では、『白い線で繋がっているノードの順に実行される』ということだけ覚えておけば大丈夫です。


4.処理の始まりのノード

先ほどの画像では、『Level Update』というノードから白い線が始まっているのがわかります。
つまり、ここが処理の始まりの部分となるわけです。

『Level Update』というノードは『更新の度にout以降の処理を行う』というものです。
つまり、『Level Update』の『out』から繋がったノードは、一定の間隔で実行されるということです。
何度も実行したい処理はこのノードに繋げます。

この他にも、『処理の始まり』となるノードは幾つも存在します。
そのうちの一つが、『Level Loaded』ノードです。
このノードは『レベルのロード時のみ』に呼ばれます。
分かりづらいという方は『一番最初に一度だけ呼ばれる』と覚えておけば、今の時点では問題ありません。

また、その逆で『レベルの終了時』、つまり『一番最後に一度だけ呼ばれる』
『Level Shutdown』ノードも存在します。


5.Flowへのノード追加方法

さて、まずはFlowに慣れるために、非常に簡単なプログラムを作ってみます。
作成するプログラムは『終了時に”おしまい”とログに出力する』というものです。

『終了時』ということは先ほど説明した『Level Shutdown』ノードが必要ですね。
しかし、先ほど開いたレベルフローの中を探してみても、『Level Shutdown』ノードはどこにもありません。
自分で追加する必要があります。

レベルフローの中で右クリックをすると、ズラーっとたくさんの項目が出てきます。
ズラーっと出てこなかった場合はフローの四角形の外で右クリックをするようにしてください。

この項目の中から『Event』→『Level Shutdown』と選択します。
こうすることで、レベルフローの中に新たに『Level Shutdown』ノードが追加されます。
Flowへのノードの追加は、このように行います。

画像3


6.ログへの出力

続いては、『ログに出力する』という処理のノードを追加します。
先ほどと同じように右クリック、『Debug』→『Debug Print』の順に選択します。
『Debug Print』ノードは『Label』と『Text』に設定された値をログに出力します。
赤いピンは『文字列』を表しています。

画像4

それでは、『Level Shutdown』と『Debug Print』を繋いでみましょう。
白いピン同士を繋げると以下の画像のようになります。

画像5

これで、『終了時にログに文字列を出力する』という処理自体は完成です。


7.引数への設定

しかし、これではまだ”おしまい”というログを出力できません。
『Label』、もしくは『Text』に文字列を設定する必要があります。

文字列を設定する方法は、ピンに”おしまい”を出力するピンから線を繋げるという方法と、
直接”おしまい”という文字列を設定する方法の2種類がありますが、今回は後者の方法を利用します。

『Debug Print』ノードの『Label』か『Text』の右側にある四角をクリックしてください。
すると、画像のような編集画面が出てきます。
この編集画面に入力した値が、クリックした項目にセットされます。
ここで”おしまい”という文字を入力してからOKを押しましょう。

画像6

画像のように『Debug Print』内に”おしまい”の文字がセットされたのがわかるはずです。
(下の方の四角をクリックした場合はTextの横に”おしまい”と入ります)

画像8

これで処理は完成です。


8.実装の確認テスト

Ctrl+Sキーで保存してから、プレイを始めて動作を確認しましょう。
プレイ前に『Log Console』タブを開くのを忘れないでください。
『Log Console』タブはデフォルトでは画面下側にあります。
見つからない場合は『Window』→『Log Console』とクリックしてください。

また、コンソール画面は様々なチェックで用いられるため、常に開いておくようにしましょう。

ここまでの実装に問題がなければ、プレイの終了時(ESCキー入力時)にコンソール画面に画像のように”おしまい”と表示されるはずです。

画像7


これで、最初のFlowプログラミングは完了です。
次回は、いよいよ本格的なVR用のノードをご紹介します。

Stingrayに触れてみよう



近年、VR/AR技術はゲーム業界のみならず、医療分野やその他の分野でも利用されるようになりました。
特に建築分野では、ウォークスルーアニメーションのプレゼンムービー等、
VIVEコントローラーによる入力を伴ったビジュアライゼーションの現場で活用されています。
液晶画面上に(内覧用の)モデルルームを表示したいとき、あるいは室内の家具の配置を考えるときに、VR/AR技術は有用です。

なぜなら実際の建築物・家具を設置する必要がなく、
以前より制作会社に蓄積されたCGアセットを活用でき、大幅な省力化が図れるからです。
この点は、建築分野においてVR/AR技術が注目を集めている大きな理由です。

通常、建築系のVRのコンテンツ開発にはゲームエンジンが用いられます。
代表的なゲームエンジンとして、UnityやUnrealEngine4が挙げられます。

ゲームエンジンとは文字通り、『ゲームを作るためのエンジン』です。
(近頃は建築などゲーム以外の用途にも使われることも増えています。)

さて、話は変わりますが、『Stingray』というゲームエンジンがあります。
Stingrayは2年前にAutodesk社がリリースしたゲームエンジンで、
プログラマでない方にも親しみやすく、3D機能に非常に優れています。

拡張性の高いシステムに、一目でわかるビジュアルスクリプティングが特徴です。
また、Mayaや3dsMaxで有名なAutodesk社がリリースしたエンジンであるため
上記の3Dデザインツールとの連携も容易というメリットがあります。

ただ、UnityやUnrealEngineに比べると情報が少ないのが難点です
Autodesk公式が運営しているチュートリアルと、
Stingrayそのもののヘルプページを除くと、Stingrayについての情報を見つけるのはかなり難しいと思います。

前置きが長くなりましたが、
数回に分けてStingrayについて、このブログに書いていくことにします。

Stingray自体がデザイナー向けのエンジンという事もあり、
ビジュアルスクリプティングをメインに書いていく予定です。



—————————————————–
・Stingrayに興味があるが触ったことのない方
・あまりゲーム開発やゲームエンジンにあまり詳しくない方
・HTC Viveのセットアップが既にできている方
・プログラムが全く分からない方
—————————————————–

このページは上記のような方々を対象にしています。

今回は、『Stingrayの起動』から、『VRテンプレートのプレイ』までを書いていきます。


1.まずはプロジェクトを作成を行う


最初はプロジェクトの作成を行います。
StingrayのランチャーからStingrayを起動します。
起動直後の画面では、いくつかのテンプレートが表示されているはずです。
(表示されていない場合、画面のタブから『Templete』を選択してください)
このテンプレートの中から、使用したい物を選びます。


今回はHTC Viveで動かすため、『VR HTC Vive』のテンプレートを使用します。
『VR HTC Vive』のテンプレートをクリックして、右下の『Create』ボタンをクリックしましょう。

すると、下の画像にあるようなウィンドウが出て来ます。



『Name』はプロジェクトの名前なので好きな名前にしましょう。
『Directry』はファイルを保存する場所ですが、何かしらのこだわりがない限りはそのままで大丈夫です。
設定が終わったら『Create』ボタンをクリックします。

これで新規プロジェクトの作成は完了です。


2.プロジェクトをプレイする


しばらく待つと、上の画像にあるような画面が表示されます。
これがStingrayのメイン画面になります。

お気付きの方もいるかもしれませんが、
Stingrayはいくつものタブの組み合わせによって構成されています。
タブは閉じたり、追加したり、別のウィンドウに表示したりもできるため、
自分が使いやすいようにカスタマイズができます。
ちなみに、タブはドラッグによって動かせます。

『Level Viewport』というタブに部屋のようなものが映し出されているはずです。
このタブが、Stingrayのメインとなるもので、現在開いているレベルを操作することができます
まずは、この状態でプレイしてみます。

画面左側の緑色の三角形をクリックするとプレイが始まります。

HMDを被ってみると、部屋の中にいることがわかるはずです。
部屋にいないように見える場合や、画面が真っ暗な場合は、
そもそもHTC Viveが接続されているか確認してください。


この時、頭の位置が普通の高さにある事を確認してください。
床の上にあるように感じたり、もしくは明らかに高い位置にいるように感じた場合は、
HTC Viveのトラッキングに失敗しているため、再度トラッキングを行ってください。


親指の位置にあるボタンを押すと、向いている方向に移動、
ボールなどの物に近づいて人差し指のトリガーを引くと、物を拾うことができます。
物の位置をリセットしたい場合は、『Reset』のボタンに近づいて、人差し指トリガーを引いてください。

尚、コントローラが見えない場合は、コントローラの電源ボタンを再度押してください。

キーボードのESCキーでプレイを終了します。


『VR HTC Vive』テンプレートの機能は以上です。

さて、いかがでしたでしょうか。

次回は、『Stingray』の大きな機能の一つである『Flow』と、
テンプレートですでに用意されている機能について触れます。