Unityでオブジェクトの アウトラインを発光させてサイバー感を演出する

下の画像は今作っているVR音ゲーのSSなのですが、ステージのアウトラインが発光しており、サイバー感がでている。。。と自分では思っています。
自分では結構お気に入りの演出で、今回の題材にしようと思います。

https://c10.patreonusercontent.com/3/eyJ3Ijo2MjB9/patreon-media/p/post/23677643/f395bc7a2e754c5292fba47aff8a536f/1?token-time=2145916800&token-hash=ooQW8wO2pPlUgSQefLf7jS-30jCS-6d5xywH8PWcyTk%3D

以下動画の4:20位にジャンプすると、上記SSのシーンに飛べます。
www.nicovideo.jp

まずは、アウトラインを設定できるシェーダーをマテリアルに設定する必要があります。
以下はUnityちゃんトゥーンシェーダー2.0(以下UTS2.0)の設定で、今回はこれを使って説明します。
「Outline_Width」、「Outline_Color」を設定するとアウトラインが生成されます。
f:id:rins64th:20190120222753p:plain

がしかし、「Outline_Color」には発光用のインスペクタが用意されていません。
f:id:rins64th:20190120223049p:plain

「Emissive_Color」では以下のようにHDR設定が可能ですが、これはシェーダーの記述法によるようです。
f:id:rins64th:20190120223411p:plain

UTS2.0ではそれぞれのプロパティは以下のように記述されています。

[HDR]_Emissive_Color ("Emissive_Color", Color) = (0,0,0,1)
_Outline_Color ("Outline_Color", Color) = (0.5,0.5,0.5,1)

解決方法としてはシェーダー上で「Outline_Color」にも「HDR」属性をつけてしまえばよいかもしれませんが、今回はあえてそれは実施しません。
まず第一に、自分で作っているわけでもないUTS2.0を直接改造したくありません。
また、インスペクター上で直接カラーをいじると、動画のように発光していない状態から徐々に発行させたり、発光に強弱を与えたり、発光色を変えたりといったことができないためです。
ので、ここではスクリプトからいじれるようにすることで、汎用性を出します。

スクリプトからシェーダープロパティを編集するざっくり手順です。
①対象オブジェクトのマテリアルを取得しておく。
②上記マテリアルに対し、SetXXXメソッドでシェーダープロパティを保存する。
※以下サンプルではオブジェクトのマテリアルを取得する処理を端折っています(いつか別記事にする予定)

    private Material[] _Materials;
    private int _OutlineId;
    private Color? _OutlineColor;
    private float _OutlineEmission;

    private void Awake()
    {
        _OutlineId = Shader.PropertyToID("_Outline_Color");
    }

    private void RelectMeshes()
    {
        for(int i = 0; i < _Materials.Length; i++)
        {
            if (_OutlineColor == null) _Materials[i].SetColor(_OutlineId, _Materials[i].GetColor(_OutlineId) * _OutlineEmission);
            else _Materials[i].SetColor(_OutlineId, _OutlineColor.Value * _OutlineEmission);
            _Materials[i].SetFloat(_OutlineWidthId, _OutlineWidth);
        }
    }

肝はSetColorメソッド実行時、カラー引数に_OutlineColorと_OutlineEmissionかけ合わせていることです。
これで_OutlineEmissionに1以上を指定することで_OutlineColor色で発光します。
あとはこれをupdateメソッド等で_OutlineEmissionをインクリメントしながらRelectMeshesを呼び出せば、徐々に発行するようスクリプトを組めます。

おまけ

マテリアルにSetXXXメソッドを適用する際、引数にはプロパティ名(string)で渡すよりも、ID値(int)で渡すほうが処理負荷が軽いようです。
結局内部的にはプロパティ名(string)からID値(int)に変換するらしいので。


また、今回はUTS2.0で説明しましたが、他のシェーダーでも使えると思います。(UTS2.0は重いです)
その際、プロパティ名は異なるため、実際のシェーダー上で確認してください。
以下のように定義されているはずなので、インスペクタ上の名前から実際のプロパティ名を確認できます。

_Outline_Color ("Outline_Color", Color) = (0.5,0.5,0.5,1)

今回は以上です。

UnityでVRコントローラを使ったUIについて(ボタン入力編)

UIといっても色々ありますが、今回はボタン入力について記載します。
なお、前提としてSteamVR Pluginをスクリプトから操作することを目的としています。
ノンコーディングで手軽にやりたい方はVRTK等で調べられるのが良いかと思います。

ボタン入力イベントのフック

以下動画冒頭のように、ボタンを押したらメニューを表示、回転を行えるようボタンイベントをフックします。
www.nicovideo.jp

SteamVR_TrackedController.csではボタン入力イベントが以下のようにデリゲートとして用意されています。(抜粋)

public delegate void ClickedEventHandler(object sender, ClickedEventArgs e);

public event ClickedEventHandler MenuButtonClicked;
public event ClickedEventHandler MenuButtonClicked;
public event ClickedEventHandler MenuButtonUnclicked;
public event ClickedEventHandler TriggerClicked;
public event ClickedEventHandler TriggerUnclicked;
public event ClickedEventHandler SteamClicked;
public event ClickedEventHandler PadClicked;
public event ClickedEventHandler PadUnclicked;
public event ClickedEventHandler PadTouched;
public event ClickedEventHandler PadUntouched;
public event ClickedEventHandler Gripped;
public event ClickedEventHandler Ungripped;

 
なので、以下のように押されたときに呼び出したいメソッドをイベント登録しておきます。
以下はメニューボタンが押されたときのイベントを登録しています。

    private SteamVR_TrackedController _TrackedController;

    private void Awake()
    {
        _TrackedController = GetComponent<SteamVR_TrackedController>();
    }

    void Start()
    {
        _TrackedController.MenuButtonClicked += new ClickedEventHandler(_CheckMenuHoldOnclick);
        _TrackedController.MenuButtonUnclicked += new ClickedEventHandler(_CheckMenuHoldOnunclick);
    }

     void _CheckMenuHoldOnclick(object sender, ClickedEventArgs e)
     {
         // XXX
     }

 

また、円状のタッチパッド については以下のように上下左右どの箇所が押されたか判定できます。

    public static FORWORD CheckPadForword(ClickedEventArgs e)
    {
        if (e.padY / e.padX > 1 || e.padY / e.padX < -1)
        {
            if (e.padY > 0)
            {
                return FORWORD.UP;
            }
            else
            {
                return FORWORD.DOWN;
            }
        }
        else
        {
            if (e.padX > 0)
            {
                return FORWORD.RIGHT;
            }
            else
            {
                return FORWORD.LEFT;
            }
        }
    }

VRでの移動方法やメニュー(uGUI)との連動方法については次回以降に記事にしたいと思います。

UnityでVR音ゲーを作ってみる

はじめまして。

rinと申します。

 

趣味で作っているUnityアプリやSE職で得た技術的な知見等を、つらつら書いていこうと思います。

unityは半年ほど前から趣味で使っていますが、ゲーム開発とかド素人なので本職の方からするとスタンダードに反している箇所が多々あるかと思いますが、ご容赦ください。

(ご指摘いただけるとありがたいです)

 

今日のお題はタイトル通り、VR音ゲーを作ってみる話です。

以下は製作中のもので、これをベースに書き連ねていきます。

www.nicovideo.jp

 

もともとコンシューマの「初音ミクProject Diva」が好きでそれをある程度ベースにしているつもりです。

今現在、機能として実現しているのは以下の通り。

リズムゲームモード。

・ダンサー、ステージギミック。

・リズム譜面のエディットモード。

・ステージギミックのエディットモード。

・上記すべてをVR上で実装。

 

リズムに合わせて〇×マークのオブジェクトが落ちてきて、タイミングよくボタンをVRコントローラで押すと判定できるようになっています。

なお、音楽センス0なので、譜面がいけていないのもご容赦ください。

 

かけることはたくさんあるので、実装するにあたって特に調べたところや工夫した個所などをこれから書いていこうかと思います。

よろしくお願いいたします。