テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】新・新しいInput Systemの使い方(Inputsystem ver 1.0版)

以前書いた新しいInput Systemの記事の書き直しです。

新しいInput System(1.0)

 Unity 2019.3にて、新しいInput Systemのバージョンが1.0になりました。まぁ、まだPreviewなんですが。とはいえ1.0になったのでソコまでAPIが変化することは無いだろうと期待して、使い方的な記事を書いてみます。

f:id:tsubaki_t1:20191012195650j:plain
InputSystemもついにVer 1.0に…

導入

  1. Window > Package Managerでパッケージマネージャーを開く
  2. AdvanceShow Preview Packagesを有効にする
  3. Input System を選択して Installを押す
  4. PlayerSetting > Player > Active Input HandlingInput Manager(Old)からInput System Package に変更
  5. Unityエディターを再起動

f:id:tsubaki_t1:20191012200534j:plain
InputSystemの切り替えは勝手に行われている事もある

作るもの

 左右に移動してジャンプする…という超簡単な動作を作ります。

f:id:tsubaki_t1:20191013023755g:plain
左右に動いてジャンプするだけ

基本的な流れは下の通り。

  1. InputActionで、プレイヤーが行う操作とキーの割り当てを行う
  2. スクリプトでキー操作を受け取る処理を記述

以前の「キーの入力状態を取得して操作を記述する」と比較すると少し抽象的になっています。

手順1:Input Actionsを作る

 まずInputActionsを作ります。無くても使おうと思えば使えますが(例えばUnityEngine.InputSystem.Gamepad.current.leftStick等で)これをベースに作ると途中から辛くなってくるので、最初にInput Actionsを作ってしまいます。

 Input Actionsは、特定のアクションにどういった操作を割り当てるのかを定義するファイルです。InputSystemではInputActionsで定義したアクションに対して、スクリプトを割り当てるイメージで使えます。

f:id:tsubaki_t1:20191012203506j:plain
InputActionの定義内容

 まずはファイルを生成します。

  1. Assets > Create > Input ActionsでInputActionsを作成。ファイル名はPlayerActにする。
  2. PlayerActiを選択し、Generate C# Classにチェックを入れる。
  3. PlayerActiEdit Assetを選択。

 中身を設定していきます。アクション名を登録し、ActionTypeで入力が返す値を設定する感じです。

  1. ActionMap+をクリック。名前は横スクロールの操作なのでPlatformActionに設定。
  2. Actions+をクリックしてアクションを二つ作成、名前は移動操作の「Move」とジャンプの「Jump」に設定。
  3. MoveのActionTypeをValueに変更、Control TypeはVector2を設定。
  4. JumpのActionTypeをValueに変更、ControlTypeはButtonを設定。

f:id:tsubaki_t1:20191013031329j:plain
アクションを作成

 アクションにキー操作を登録します。今回はキーボード入力操作とゲームパッドの操作を登録します。キーボード入力は複数のキー入力を一つの入力に統合する2D Vector Compositeを使ってまとめます。

  1. Moveの右にある+を押しAdd Bindingを選択。BindingのPathをD-Pad[GamePad]を選択。
  2. Moveの右にある+を押しAdd 2D Vector Compositeを選択。
    UpW [Keyboard]を選択。 DownS [Keyboard]を選択。
    LeftA [Keyboard]を選択。 RightD [Keyboard]を選択。
  3. Jumpの右にある+を押し、Add Bindingを選択。
    BindingのPathにButton West[GamePad]を選択。
  4. Jumpの右にある+を押し、Add Bindingを選択。
    BindingのPathにSpace [Keyboard]を選択。
  5. Save Assetを選択

f:id:tsubaki_t1:20191013032046j:plain
InputActionsの設定

 次は作成した設定を使用してキャラクターを動かします。

手順2:キャラクターを動かす(コールバックで動かす場合)

 まずコールバックベースで動かすアプローチについてです。コールバックはInputActionsが自動で生成してくれるコードを使用して実現します。コードは指定が無ければInputActionと同じフォルダに生成されます。

 コードにはファイル名+ActionMapというインターフェースが含まれており、これを継承したクラスをActionMapに登録すれば、入力が入る度にコールバックが呼ばれるようになります。入力時のパラメーターはcontext.ReadValue<T>()で取得します。TがInputActionsのControlTypeと一致していないと動かないので注意が必要です。またControlTypeは実態と型が一致していない事もあるので、そのあたりも注意が必要です。例えばAxisやButtonはfloatです。

 新しいインプットシステムは、基本的にinput.Enable()input.Disable()が必要です。それと破棄時にはinput.Dispose()した方が良さそな気配があります。

public class MovePlayer : MonoBehaviour, PlayerAct.IPlatformActionActions
{
    PlayerAct.PlatformActionActions input;

    [SerializeField] MoveComponent move;
    float horizontal;

    void Awake()
    {
        // インプットを生成して、自身をコールバックとして登録
        input = new PlayerAct.PlatformActionActions(new PlayerAct());
        input.SetCallbacks(this);
    }

    // インプットの有効・無効化
    void OnDestroy() => input.Disable();
    void OnEnable() => input.Enable();


    void OnDisable() => input.Disable();
    void Update() => move.MoveHorizontal(horizontal);

    // --------------
    // コールバック
    // --------------
    public void OnJump(InputAction.CallbackContext context)
    {
        move.Jump();
    }

    public void OnMove(InputAction.CallbackContext context)
    {
        // 押しっぱなしの動作は、直接オブジェクトを動かすのではなく方向性のみを登録する
        horizontal = context.ReadValue<Vector2>().x;
    }
}

 ここで注意すべきは、このイベントは「値の変化時に呼ばれるっぽい」という点です。そのためMoveアクション(WASDキーにバインド)のような常に押し続ける操作はすぐに動きを停止してしまいます。これは値の変化を変数に格納し、後程Updateで反映することで回避出来ます。これバグかと思ったら仕様っぽいです。

 またコールバックは「一フレームに複数呼ばれる」事があります。New Input Systemはフレームの間の入力も取得する事ができます。コールバックは設定のタイミングで一気に処理されますが、入力時の時間はcontext.timeで確認出来ます。これをうまく使うと、基本的にフレームを落としても滑らかな操作といった事が可能かもしれません。

https://cdn-ak.f.st-hatena.com/images/fotolife/t/tsubaki_t1/20190108/20190108222131.gif

手順2:キャラクターを動かす(ポーリングして動かす場合)

 コールバックの動作は便利ではありますが面倒くさいという点も確かにあります。いくつかのゲームは普通にUpdateのタイミングでプレイヤーが責任持って入力を取得する…といったモノの方が好ましいです。ということで、今度はポーリングスタイルで入力を取得します。

 使う場合は単純にActionMapのActionからReadValue<T>()で値を取得するだけです。

public class MovePlayer2 : MonoBehaviour
{
    [SerializeField] MoveComponent move;

    // インプットの登録と破棄
    PlayerAct input;
    void Awake() => input = new PlayerAct();
    void OnDisable() => input.Disable();

    // インプットの有効・無効化
    void OnDestroy() => input.Disable();
    void OnEnable() => input.Enable();


    void Update()
    {
        // スティックの移動を取得して動かす
        var velocity = input.PlatformAction.Move.ReadValue<Vector2>();
        move.MoveHorizontal(velocity.x);

        // ジャンプボタンが押されているか判定して動かす
        var isJumpButtonPressed = (input.PlatformAction.Jump.ReadValue<float>() >= InputSystem.settings.defaultButtonPressPoint);
        if (isJumpButtonPressed)
            move.Jump();
    }
}

 仕様かバグなのか微妙ですが、一つ注意点として「Interactions」という入力の動作をフィルタリングして特定の動作を行わないとアクションを呼ばない設定があるのですが、これが設定されてるとうまく動かない事があります。

f:id:tsubaki_t1:20191013040348j:plain
Jumpの場合は付けてると便利だけど、ポーリングに使うとジャンプ出来なくなる設定

 もしコールバックのように一フレーム内で起こった入力をすべて取得したい場合、下のような記述で取得できます。InputStateHistory recordsで観測するアクションを指定し、records.StartRecordingでアクションを格納していきます。なおInteractionsのようなアクションをフィルタする機能は使えないっぽいです。ストリームの値を読んでるだけなので是非もないね。

public class MovePlayer3 : MonoBehaviour
{
    [SerializeField] MoveComponent move;

    // インプットの登録と破棄
    PlayerAct input;
    InputStateHistory records;

    void Awake()
    {
        input = new PlayerAct();
        records = new InputStateHistory(input.PlatformAction.Jump.controls);
        records.historyDepth = 16;
    }
    void OnDestroy()
    {
        records.Dispose();
        input.Disable();
    }

    // インプットの有効・無効化
    void OnEnable() => records.StartRecording();
    void OnDisable() => records.StopRecording();

    void Update()
    {
        foreach (var record in records)
        {
            var isJumpPressed = record.ReadValue<float>() >= InputSystem.settings.defaultButtonPressPoint;
            if (isJumpPressed)
                move.Jump();
        }
    }
}

 以前はUnsafeを要求していたので、それと比べれば大分楽に使えるようになりましたが、2D Vector Compositeで使用するとうまく動作しなかったり、時々シャックリを起こしたように入力が取れなかったり、何となく妙な癖があります。

キーコンフィグ

動的にアクションに割り当てたキー操作を変更したり出来ます。

// ジャンプの操作にFキーを追加
input = new PlayerAction();
input.Move.Jump.AddBinding("<Keyboard>/f");

補足

 なおPlayerInputという簡単に使用できるハイレベルAPIが用意されていますが、これはUnity 2019.3では期待通りに動作しませんでした。正確にはUnityEventを使用するケースで入力内容を取得できません。同梱のサンプルも動作しないのでバグと思われます(2019.2では動作します)。

Unity 2019.3 b7だと正常に動作しました

関連

今回の記事が面倒くさいと感じた人向け

tsubakit1.hateblo.jp

【Unity】Burstコンパイラでルックアップテーブルを使用する

f:id:tsubaki_t1:20191011215417j:plain

ルックアップテーブルを使おう

ルックアップテーブル:複雑な計算処理を単純な配列の参照処理で置き換えて効率化を図るために作られた、配列や連想配列などのデータ構造のことをいう。(Wikipediaより)

 事前計算を使用するというのは割とありがたいアプローチの一つです。例えば角度からベクトルを計算したい時、角度をラジアンに変換して云々という処理を毎回じっこうせずとも、特定の要素にアクセスすれば値を得られるという形にできます。当然、値の制度は非常に低い物になるでしょうが、それが必要な場合は十分とも言えます。

// 毎回計算する場合
var rad = math.radians(angle);
var velocity = new Vector3(math.cos(rad), math.sin(rad));

// 事前計算した結果を使用する場合
var velocity = AngleToVelocity[angle]

 これをBurstでも使いたいと思いますが、一つ問題があります。Burstはマネージドメモリを使用できないという点です。そのためNativeArrayで定義する必要がありそうに見えます。これは問題ないと言えば問題ないかもしれませんが、やる場合には通常の配列を定義してNativeArrayに変換する流れが必要になってくるので、あまりイケてないように見えます。

Burstでルックアップテーブルを使おう

 先日のUniteの講演で気づいたのですが、どうやら通常のフィールドとして定義した配列を使用できる方法があるみたいです。

 利用できる条件は単純で static readonly な配列は使用できるみたいです。例えば下のように定義しておくと、Burstでも使用することが出来ました。

    public static readonly float2[] AngleToVelocity = new float2[] {
        new float2(0f, 1f),
        new float2(-0.01745241f, 0.9998477f),
        new float2(-0.0348995f, 0.9993908f),
        new float2(-0.05233596f, 0.9986295f),
       .
       .
       .

 注意点としては、BurstとC#で少し挙動が変わるという点です。C#の動作では static readonlyな配列は、中身を変更することが可能です。しかしBurstの場合は変更した中身を無視して最初に定義した数値を使用します。この問題はエディターだと分かりやすく、Burstコンパイルが完了するまでは*1値を書き換えることが可能ですが、Burstのコンパイル完了後はコードに記述した値が使用されます。

f:id:tsubaki_t1:20191011215915j:plain
定義

サンプル

角度の方向に向かってGameObjectを進めます。

using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Jobs;
using Unity.Burst;
using Unity.Jobs;
using Unity.Collections;

public class MoveByAngle : MonoBehaviour
{
    [Range(0, 359)]
    public int angle;

    [BurstCompile]
    struct MoveTransform : IJobParallelForTransform
    {
        public int angle;
        public void Execute(int index, TransformAccess transform)
        {
            var velocity2D = AngleToVelocity[angle] * 0.1f;
            transform.position += new Vector3(velocity2D.x, velocity2D.y);
        }
    }

    JobHandle handle;

    TransformAccessArray transforms;

    void OnEnable()
    {
        transforms = new TransformAccessArray(1);
        transforms.Add(transform);
    }

    void OnDisable()
    {
        handle.Complete();
        transforms.Dispose();
    }

    void Update()
    {
        handle.Complete();
        handle = new MoveTransform { angle = angle }.Schedule(transforms, handle);
        JobHandle.ScheduleBatchedJobs();
    }

    public static readonly float2[] AngleToVelocity = new float2[] {
        new float2(0f, 1f),
        new float2(-0.01745241f, 0.9998477f),
        new float2(-0.0348995f, 0.9993908f),
        new float2(-0.05233596f, 0.9986295f),
        new float2(-0.06975648f, 0.9975641f),
        new float2(-0.08715575f, 0.9961947f),
        new float2(-0.1045285f, 0.9945219f),
        new float2(-0.1218694f, 0.9925461f),
        new float2(-0.1391731f, 0.9902681f),
        new float2(-0.1564345f, 0.9876884f),
        new float2(-0.1736482f, 0.9848077f),
        new float2(-0.190809f, 0.9816272f),
        new float2(-0.2079117f, 0.9781476f),
        new float2(-0.2249511f, 0.9743701f),
        new float2(-0.2419219f, 0.9702957f),
        new float2(-0.2588191f, 0.9659258f),
        new float2(-0.2756374f, 0.9612617f),
        new float2(-0.2923717f, 0.9563047f),
        new float2(-0.309017f, 0.9510565f),
        new float2(-0.3255681f, 0.9455186f),
        new float2(-0.3420202f, 0.9396926f),
        new float2(-0.3583679f, 0.9335804f),
        new float2(-0.3746066f, 0.9271839f),
        new float2(-0.3907311f, 0.9205049f),
        new float2(-0.4067367f, 0.9135454f),
        new float2(-0.4226183f, 0.9063078f),
        new float2(-0.4383712f, 0.8987941f),
        new float2(-0.4539905f, 0.8910065f),
        new float2(-0.4694716f, 0.8829476f),
        new float2(-0.4848097f, 0.8746197f),
        new float2(-0.5f, 0.8660254f),
        new float2(-0.5150381f, 0.8571673f),
        new float2(-0.5299193f, 0.8480481f),
        new float2(-0.5446391f, 0.8386706f),
        new float2(-0.5591929f, 0.8290375f),
        new float2(-0.5735765f, 0.819152f),
        new float2(-0.5877853f, 0.809017f),
        new float2(-0.601815f, 0.7986355f),
        new float2(-0.6156614f, 0.7880108f),
        new float2(-0.6293204f, 0.7771459f),
        new float2(-0.6427876f, 0.7660444f),
        new float2(-0.6560591f, 0.7547096f),
        new float2(-0.6691306f, 0.7431449f),
        new float2(-0.6819984f, 0.7313536f),
        new float2(-0.6946583f, 0.7193398f),
        new float2(-0.7071068f, 0.7071067f),
        new float2(-0.7193398f, 0.6946583f),
        new float2(-0.7313538f, 0.6819984f),
        new float2(-0.7431449f, 0.6691306f),
        new float2(-0.7547097f, 0.656059f),
        new float2(-0.7660445f, 0.6427876f),
        new float2(-0.777146f, 0.6293204f),
        new float2(-0.7880108f, 0.6156614f),
        new float2(-0.7986355f, 0.601815f),
        new float2(-0.8090171f, 0.5877851f),
        new float2(-0.819152f, 0.5735765f),
        new float2(-0.8290376f, 0.5591928f),
        new float2(-0.8386706f, 0.544639f),
        new float2(-0.8480482f, 0.5299191f),
        new float2(-0.8571673f, 0.5150381f),
        new float2(-0.8660254f, 0.5f),
        new float2(-0.8746197f, 0.4848096f),
        new float2(-0.8829477f, 0.4694715f),
        new float2(-0.8910065f, 0.4539905f),
        new float2(-0.8987942f, 0.438371f),
        new float2(-0.9063078f, 0.4226182f),
        new float2(-0.9135455f, 0.4067366f),
        new float2(-0.9205048f, 0.3907312f),
        new float2(-0.9271839f, 0.3746065f),
        new float2(-0.9335805f, 0.3583679f),
        new float2(-0.9396927f, 0.34202f),
        new float2(-0.9455186f, 0.3255681f),
        new float2(-0.9510565f, 0.309017f),
        new float2(-0.9563048f, 0.2923716f),
        new float2(-0.9612617f, 0.2756373f),
        new float2(-0.9659258f, 0.258819f),
        new float2(-0.9702958f, 0.2419218f),
        new float2(-0.9743701f, 0.224951f),
        new float2(-0.9781476f, 0.2079117f),
        new float2(-0.9816272f, 0.190809f),
        new float2(-0.9848078f, 0.1736481f),
        new float2(-0.9876883f, 0.1564345f),
        new float2(-0.9902681f, 0.1391731f),
        new float2(-0.9925462f, 0.1218693f),
        new float2(-0.9945219f, 0.1045284f),
        new float2(-0.9961946f, 0.08715588f),
        new float2(-0.9975641f, 0.06975645f),
        new float2(-0.9986296f, 0.05233604f),
        new float2(-0.9993908f, 0.03489941f),
        new float2(-0.9998477f, 0.01745242f),
        new float2(-0.9999999f, 5.960464E-08f),
        new float2(-0.9998477f, -0.01745248f),
        new float2(-0.9993908f, -0.03489959f),
        new float2(-0.9986296f, -0.05233586f),
        new float2(-0.9975641f, -0.06975651f),
        new float2(-0.9961947f, -0.08715594f),
        new float2(-0.9945219f, -0.1045285f),
        new float2(-0.9925462f, -0.1218693f),
        new float2(-0.990268f, -0.1391732f),
        new float2(-0.9876884f, -0.1564347f),
        new float2(-0.9848078f, -0.1736484f),
        new float2(-0.9816272f, -0.1908089f),
        new float2(-0.9781476f, -0.2079117f),
        new float2(-0.97437f, -0.224951f),
        new float2(-0.9702957f, -0.241922f),
        new float2(-0.9659258f, -0.258819f),
        new float2(-0.9612617f, -0.2756375f),
        new float2(-0.9563047f, -0.2923716f),
        new float2(-0.9510565f, -0.3090172f),
        new float2(-0.9455186f, -0.3255682f),
        new float2(-0.9396927f, -0.3420202f),
        new float2(-0.9335804f, -0.3583682f),
        new float2(-0.9271838f, -0.3746067f),
        new float2(-0.9205049f, -0.3907312f),
        new float2(-0.9135454f, -0.4067367f),
        new float2(-0.9063078f, -0.4226184f),
        new float2(-0.8987939f, -0.4383713f),
        new float2(-0.8910066f, -0.4539905f),
        new float2(-0.8829476f, -0.4694716f),
        new float2(-0.8746197f, -0.4848098f),
        new float2(-0.8660254f, -0.5000001f),
        new float2(-0.8571673f, -0.515038f),
        new float2(-0.848048f, -0.5299193f),
        new float2(-0.8386706f, -0.5446391f),
        new float2(-0.8290375f, -0.559193f),
        new float2(-0.8191521f, -0.5735766f),
        new float2(-0.8090171f, -0.5877852f),
        new float2(-0.7986354f, -0.601815f),
        new float2(-0.7880107f, -0.6156617f),
        new float2(-0.777146f, -0.6293204f),
        new float2(-0.7660444f, -0.6427877f),
        new float2(-0.7547095f, -0.656059f),
        new float2(-0.7431448f, -0.6691307f),
        new float2(-0.7313538f, -0.6819984f),
        new float2(-0.7193397f, -0.6946584f),
        new float2(-0.7071068f, -0.7071067f),
        new float2(-0.6946582f, -0.7193398f),
        new float2(-0.6819984f, -0.7313538f),
        new float2(-0.6691306f, -0.7431448f),
        new float2(-0.656059f, -0.7547096f),
        new float2(-0.6427875f, -0.7660446f),
        new float2(-0.6293203f, -0.777146f),
        new float2(-0.6156614f, -0.7880107f),
        new float2(-0.6018149f, -0.7986356f),
        new float2(-0.5877852f, -0.8090171f),
        new float2(-0.5735763f, -0.8191522f),
        new float2(-0.5591928f, -0.8290377f),
        new float2(-0.544639f, -0.8386706f),
        new float2(-0.5299191f, -0.8480481f),
        new float2(-0.515038f, -0.8571672f),
        new float2(-0.5000001f, -0.8660253f),
        new float2(-0.4848095f, -0.8746197f),
        new float2(-0.4694716f, -0.8829476f),
        new float2(-0.4539904f, -0.8910065f),
        new float2(-0.4383711f, -0.8987941f),
        new float2(-0.4226183f, -0.9063078f),
        new float2(-0.4067366f, -0.9135456f),
        new float2(-0.3907309f, -0.9205049f),
        new float2(-0.3746065f, -0.9271837f),
        new float2(-0.3583679f, -0.9335804f),
        new float2(-0.34202f, -0.9396927f),
        new float2(-0.3255681f, -0.9455187f),
        new float2(-0.3090171f, -0.9510566f),
        new float2(-0.2923716f, -0.9563048f),
        new float2(-0.2756374f, -0.9612616f),
        new float2(-0.2588189f, -0.9659259f),
        new float2(-0.2419219f, -0.9702957f),
        new float2(-0.2249511f, -0.9743701f),
        new float2(-0.2079116f, -0.9781476f),
        new float2(-0.1908088f, -0.9816272f),
        new float2(-0.1736483f, -0.9848078f),
        new float2(-0.1564344f, -0.9876882f),
        new float2(-0.139173f, -0.9902682f),
        new float2(-0.1218693f, -0.9925461f),
        new float2(-0.1045285f, -0.9945219f),
        new float2(-0.08715564f, -0.9961947f),
        new float2(-0.06975647f, -0.9975641f),
        new float2(-0.05233581f, -0.9986296f),
        new float2(-0.03489945f, -0.9993908f),
        new float2(-0.01745246f, -0.9998477f),
        new float2(8.742278E-08f, -1f),
        new float2(0.01745239f, -0.9998477f),
        new float2(0.03489963f, -0.9993908f),
        new float2(0.05233599f, -0.9986296f),
        new float2(0.06975664f, -0.9975641f),
        new float2(0.08715582f, -0.9961947f),
        new float2(0.1045284f, -0.9945219f),
        new float2(0.1218695f, -0.9925461f),
        new float2(0.1391731f, -0.9902682f),
        new float2(0.1564344f, -0.9876882f),
        new float2(0.1736485f, -0.9848076f),
        new float2(0.190809f, -0.9816272f),
        new float2(0.207912f, -0.9781474f),
        new float2(0.2249513f, -0.9743699f),
        new float2(0.2419218f, -0.9702957f),
        new float2(0.2588193f, -0.9659257f),
        new float2(0.2756375f, -0.9612616f),
        new float2(0.2923715f, -0.9563048f),
        new float2(0.3090172f, -0.9510564f),
        new float2(0.3255683f, -0.9455185f),
        new float2(0.3420204f, -0.9396925f),
        new float2(0.3583681f, -0.9335804f),
        new float2(0.3746066f, -0.9271837f),
        new float2(0.3907313f, -0.9205048f),
        new float2(0.4067367f, -0.9135454f),
        new float2(0.4226183f, -0.9063078f),
        new float2(0.4383713f, -0.8987941f),
        new float2(0.4539905f, -0.8910065f),
        new float2(0.4694717f, -0.8829476f),
        new float2(0.4848097f, -0.8746197f),
        new float2(0.5f, -0.8660253f),
        new float2(0.5150382f, -0.8571672f),
        new float2(0.5299193f, -0.8480481f),
        new float2(0.5446389f, -0.8386706f),
        new float2(0.559193f, -0.8290374f),
        new float2(0.5735764f, -0.819152f),
        new float2(0.5877855f, -0.8090168f),
        new float2(0.601815f, -0.7986356f),
        new float2(0.6156614f, -0.7880108f),
        new float2(0.6293206f, -0.7771457f),
        new float2(0.6427876f, -0.7660444f),
        new float2(0.6560589f, -0.7547096f),
        new float2(0.6691308f, -0.7431448f),
        new float2(0.6819984f, -0.7313536f),
        new float2(0.6946586f, -0.7193396f),
        new float2(0.7071069f, -0.7071067f),
        new float2(0.7193398f, -0.6946584f),
        new float2(0.7313538f, -0.6819981f),
        new float2(0.7431449f, -0.6691306f),
        new float2(0.7547097f, -0.6560589f),
        new float2(0.7660446f, -0.6427875f),
        new float2(0.777146f, -0.6293204f),
        new float2(0.788011f, -0.615661f),
        new float2(0.7986357f, -0.6018147f),
        new float2(0.8090169f, -0.5877855f),
        new float2(0.8191521f, -0.5735763f),
        new float2(0.8290375f, -0.5591928f),
        new float2(0.8386708f, -0.5446388f),
        new float2(0.8480482f, -0.5299189f),
        new float2(0.8571674f, -0.515038f),
        new float2(0.8660255f, -0.5f),
        new float2(0.8746197f, -0.4848095f),
        new float2(0.8829475f, -0.4694716f),
        new float2(0.8910066f, -0.4539902f),
        new float2(0.8987941f, -0.4383709f),
        new float2(0.9063078f, -0.4226182f),
        new float2(0.9135455f, -0.4067366f),
        new float2(0.9205048f, -0.3907312f),
        new float2(0.9271839f, -0.3746064f),
        new float2(0.9335805f, -0.3583677f),
        new float2(0.9396926f, -0.34202f),
        new float2(0.9455186f, -0.3255682f),
        new float2(0.9510564f, -0.3090171f),
        new float2(0.9563048f, -0.2923715f),
        new float2(0.9612618f, -0.2756373f),
        new float2(0.9659258f, -0.258819f),
        new float2(0.9702958f, -0.2419214f),
        new float2(0.9743701f, -0.2249513f),
        new float2(0.9781476f, -0.207912f),
        new float2(0.9816273f, -0.1908089f),
        new float2(0.9848078f, -0.1736481f),
        new float2(0.9876884f, -0.1564341f),
        new float2(0.9902681f, -0.1391728f),
        new float2(0.9925462f, -0.1218692f),
        new float2(0.994522f, -0.1045284f),
        new float2(0.9961947f, -0.0871557f),
        new float2(0.997564f, -0.06975651f),
        new float2(0.9986296f, -0.05233574f),
        new float2(0.9993908f, -0.03489923f),
        new float2(0.9998477f, -0.01745224f),
        new float2(0.9999999f, 5.960464E-08f),
        new float2(0.9998477f, 0.01745224f),
        new float2(0.9993908f, 0.03489977f),
        new float2(0.9986295f, 0.05233622f),
        new float2(0.9975641f, 0.06975663f),
        new float2(0.9961947f, 0.0871557f),
        new float2(0.9945219f, 0.1045284f),
        new float2(0.9925461f, 0.1218696f),
        new float2(0.9902681f, 0.1391733f),
        new float2(0.9876884f, 0.1564345f),
        new float2(0.9848077f, 0.1736486f),
        new float2(0.9816272f, 0.190809f),
        new float2(0.9781475f, 0.207912f),
        new float2(0.97437f, 0.2249513f),
        new float2(0.9702957f, 0.241922f),
        new float2(0.9659258f, 0.2588195f),
        new float2(0.9612616f, 0.2756377f),
        new float2(0.9563048f, 0.2923715f),
        new float2(0.9510565f, 0.3090172f),
        new float2(0.9455186f, 0.3255681f),
        new float2(0.9396925f, 0.3420205f),
        new float2(0.9335804f, 0.3583682f),
        new float2(0.9271838f, 0.3746067f),
        new float2(0.9205048f, 0.3907313f),
        new float2(0.9135455f, 0.4067366f),
        new float2(0.9063078f, 0.4226182f),
        new float2(0.8987939f, 0.4383714f),
        new float2(0.8910065f, 0.4539906f),
        new float2(0.8829475f, 0.4694717f),
        new float2(0.8746198f, 0.4848096f),
        new float2(0.8660255f, 0.4999999f),
        new float2(0.8571672f, 0.5150383f),
        new float2(0.848048f, 0.5299194f),
        new float2(0.8386706f, 0.5446391f),
        new float2(0.8290375f, 0.5591929f),
        new float2(0.8191521f, 0.5735763f),
        new float2(0.8090168f, 0.5877855f),
        new float2(0.7986354f, 0.6018151f),
        new float2(0.7880107f, 0.6156615f),
        new float2(0.7771457f, 0.6293207f),
        new float2(0.7660446f, 0.6427875f),
        new float2(0.7547097f, 0.6560588f),
        new float2(0.7431448f, 0.6691307f),
        new float2(0.7313537f, 0.6819984f),
        new float2(0.7193395f, 0.6946587f),
        new float2(0.7071066f, 0.707107f),
        new float2(0.6946582f, 0.71934f),
        new float2(0.6819983f, 0.7313538f),
        new float2(0.6691306f, 0.7431449f),
        new float2(0.6560587f, 0.7547098f),
        new float2(0.6427874f, 0.7660446f),
        new float2(0.6293203f, 0.7771461f),
        new float2(0.6156614f, 0.7880108f),
        new float2(0.601815f, 0.7986355f),
        new float2(0.5877853f, 0.8090169f),
        new float2(0.5735762f, 0.8191522f),
        new float2(0.5591927f, 0.8290377f),
        new float2(0.5446389f, 0.8386706f),
        new float2(0.5299193f, 0.8480481f),
        new float2(0.5150382f, 0.8571672f),
        new float2(0.4999998f, 0.8660255f),
        new float2(0.4848095f, 0.8746198f),
        new float2(0.4694715f, 0.8829476f),
        new float2(0.4539901f, 0.8910067f),
        new float2(0.4383713f, 0.898794f),
        new float2(0.422618f, 0.9063079f)
    };
}

関連

www.youtube.com

*1:エディターでBurstを実行する場合、コンパイル完了まで通常のC#の処理が実行される

【Unity】LWRPで特定のモデルのみポストプロセスがかからないようにする

f:id:tsubaki_t1:20191010195816j:plain
一部のモデルにだけ、色あせるポストプロセスをかけない
昨日の応用で、一部のモデルにだけポストプロセスがかからないようにします。

一部のモデルだけポストプロセスの影響をかけないようにする

 以前に紹介した方法はカメラのスタックが現在使えない関係上、使用できなくなりました。そのため、一部にのみポストプロセスをかけないといった設定を実現するには、少しアプローチを変える必要があります。

 とはいえ悪い話ではありません。以前のアプローチはレイヤーを何度も変える関係上、パフォーマンス(特にPhysics関連のコンポーネントを持っている場合)に影響がある可能性がありましたが、今回はレイヤーを何度も変えないので多分問題は無いでしょう。

 基本的には昨日のアプローチと殆ど同じです。つまり レンダリングしてポストプロセス描画後に特定のレイヤーに所属するメッシュを描画する という事です。ただし今回は不透明を指定しCameraのDepthを上書きしません。これにより 奥行判定も綺麗に出る事が期待出来ます。

f:id:tsubaki_t1:20191010200823j:plain
ポストプロセスの影響を受けるモデルにさえぎられても、ちゃんと描画できている

手順

 手順は殆どが昨日の焼き直しです。

  1. Create > Rendering > ***Pipeline > Forward Renderer でCustom Forward Rendererアセットを作ります。その後、Lightweight Renderer Pipeline AssetのRender TypeをCustomに設定し、Custom Forward Rendererアセットを登録。
  2. Project Settings> Tag and Layer を選択し、WithoutPostProcess(任意の名前)的なレイヤーを作る。
  3. ポストプロセス対象外にしたいGameObjectをWithoutPostProcess所属にする
  4. 1で作成したCustom Forward Rendererアセットを選択。
  5. Default Layer Mask から WithoutPostProcess を外す。
  6. Render Features+ を押す。追加するパスは Rendere Object を選択。
  7. NameWOPP(任意)に変更。
  8. EventAfter Rendering に変更。

f:id:tsubaki_t1:20191010201459p:plain
レイヤーを追加

f:id:tsubaki_t1:20191010201922j:plain
Custom Forward Rendererの設定を変更

 半透明も使用したい場合、追加でRenderer Feature+を押し、パスを追加。上の手順の7.8.を設定後、Filters>QueueTransparentにすればよいです。

f:id:tsubaki_t1:20191010202410j:plain
半透明がある場合でも問題なく表現出来ている

注意点

「ポストプロセスの影響を受けない」は、単純なカラーコレクション等なら多分問題はないのですが、DOFやBloomといった色を滲ませる表現がある場合は微妙な表現になるかもしれません。

【Unity】LWRPでポストプロセスを使用しつつUIの手前にパーティクルを表示する

f:id:tsubaki_t1:20191009221926g:plain

PCを新しくしてからの初更新です。

環境:Unity 2019.2f8、LightWeight RP 6.9.1

LWRPはカメラのスタックができない

 いろいろと便利なLWRPですが、一つだけよく言われる致命的な問題があります。 カメラを複数使用して描画する事ができない という点です。 RenderTexture に描画結果を出力して後でまとめるといった事は可能なのですが、今まで使ってきた 複数のカメラを使って描画する事が出来ないのは、非常にもどかしいです。

 特に問題になりやすいのはUIとパーティクルの描画です。 よくある演出として UIの手前にエフェクトを表示する があります。これは大抵の場合「ゲームを描画するカメラ」「UIだけを表示するカメラ」の二つに分けて描画し、「UIだけを表示するカメラ」にパーティクルを描画させることで実現していました。  ただしLWRPになりカメラのスタックが出来なくなったので、専用カメラが使用できません。よって異なる方法を考える必要があります。

 難しいのが、まず ScreenSpaceOverlay は使えません。UIの手前にパーティクルを描画出来ない為です。   また ScreenSpace-Camera でも単純には上手くいきません。単純に処理すればUIがポストプロセスの影響を受けるので、特にカラーコレクションを使用すると盛大に色合いが変わってしまいます。またBloomやDOFの影響を受けるのはひどいです。同様にPlaneDistanceの設置でUIがステージにめり込む事もあり得ます。この設定をいくら小さくしても、手前で爆発するなど何らかの理由でUIよりステージオブジェクトが手前に描画される事があるのは問題でしょう。

f:id:tsubaki_t1:20191009223546p:plain
UIがポストプロセスの影響を受けてしまっているケース

f:id:tsubaki_t1:20191009223652p:plain
UIがステージにめり込んでしまっているケース。ScreenSpace-CameraだとPlaneDistance設定で起こりえる

PostProcessingの後にUIとパーティクルを描画する

 一番手っ取り早いアプローチは Custom Forward Render を使用して、UIとパーティクルを描画する事です。 このアプローチではUIをポストプロセスの影響を受けないようにしつつパーティクルをUIの手前に描画出来ます。また Screen Space Camera を使いつつもステージやキャラクターの後ろにUIが表示されるといった事も回避できます。
 この手順のアイディアは非常に単純で 任意のレイヤーに所属するオブジェクトを、ポストプロセスの後に描画しよう というものです。

 実際の手順はこんな感じです。

 まず最初にUIは ScreenSpace-Camera を使用する必要があります。 CanvasのRender ModeをScreen space-Cameraに設定します。またCanvas GameObjectのレイヤーはUIに設定します。パーティクルのGameObjectもUIに設定します。
 パーティクルをUIの手前に描画したいので、Order in Layerを使用してUIの手前にパーティクルを描画するように設定します。 UIの場合はCanvasに、パーティクルの場合はRendererにあります。

f:id:tsubaki_t1:20191009225200j:plain
Canvasの設定

f:id:tsubaki_t1:20191009225813p:plain
ParticleのOrder In layerを設定する場所

 レンダラー側の設定を行います。まずは Create > Rendering > ***Pipeline > Forward Renderer でCustom Forward Rendererアセットを作ります。その後、Lightweight Renderer Pipeline AssetのRender TypeをCustomに設定し、Custom Forward Rendererアセットを登録します。

f:id:tsubaki_t1:20191009230101p:plain
Custom Forward Rendererを作る

f:id:tsubaki_t1:20191009230506j:plain
Custom Forward Rendererを使用する設定

 次にCustom Forward Rendererの設定を行います。ここは少し手順が多いので、箇条書きします。

  1. Default Layer Mask から UI を外す。
  2. Render Features+ を押す。追加するパスは Rendere Object を選択
  3. NameUIに変更(任意)
  4. EventAfter Rendering に変更
  5. Filters > QueueTransparent に変更
  6. Filters > Layer MaskUI を選択
  7. Override > Depth にチェックを入れ、Depth TestDisabledに変更

f:id:tsubaki_t1:20191009231723g:plain
手順

これでUIの手前にパーティクルを描画出来ました。

UIの間にパーティクルを挟む

 今回の手順では描画順は完全にOrder In Layer順になっています。なのでパーティクルの所属するOrder In LayerをCanvasの間に挟んでやれば、UIとUIの間にパーティクルを挟む事も可能です。

f:id:tsubaki_t1:20191009232807j:plain
UIとUIの間にパーティクルを挟む

注意点

 これはあくまでもパーティクルがTransparentを使用している前提の使い方なので成立しています(つまりDepth Testを使用していない事が重要)。もしUIの手前に複数のSubMeshを持つオブジェクトを描画するといった場合はRenderTextureをオフスクリーンで描画する方が理にかなっていると言えるかもしれません。

 今回の手順はURPでも使用できました。HDRPは不明です。

 ScreenSpace-Cameraを使用する関係上、編集する場合にはPrefabモードが便利です。ただし、その場合ScreenSpace-Overlayになるので(PrefabからScene上のカメラを参照出来ない為)描画順回りは少し混乱するかもしれません。

 カメラのスタックはロードマップには載っているみたいです。現状は未実装なので、このトリックが必要という感じで。