MRが楽しい

MRやVRについて学習したことを書き残す

HoloLens特化のホロ恋子モデルを作成する その35(UVマッピング)

本日はホロ恋子モデル2の作成枠です。
テクスチャのマッピング作業を開始するに辺り、UVマッピングについてまとめます。
f:id:bluebirdofoz:20190213084826j:plain

UVマッピングは3次元的なメッシュの座標と2次元的なテクスチャの座標の対応付けを行う機能です。
テクスチャの座標軸はXYZ軸ではなく、U軸(横軸)とV軸(縦軸)と呼ぶため、UVマッピングと呼ばれます。

UVマップの作成

メッシュオブジェクトはデフォルトではUVマッピングが行われていません。
このため、まずは「UVマップ」を作成する必要があります。

説明のため、追加 -> メッシュ -> 平面 で平面オブジェクトを作成しました。
これを使ってUVマップの作成と利用方法を確認します。
f:id:bluebirdofoz:20190213084837j:plain

UVマップを確認するため、画面分割を行い、[UV/画像エディター]の画面を準備します。
f:id:bluebirdofoz:20190213084846j:plain

早速、UVマップを作成してみます。
平面オブジェクトの[編集モード]に入り、UVマッピングを行うメッシュ部分を選択します。
この状態でメニューから メッシュ -> UV展開 -> 展開 を実行します。
f:id:bluebirdofoz:20190213084901j:plain

すると[UV/画像エディター]にUVマップが展開されます。
今回は正方形の平面オブジェクトを展開したため、画像側のマップもそのまま綺麗に展開されました。
UVマップを作成すると[データ]タブの[UVマップ]パネルの一覧に、作成したUVマップが追加されます。
f:id:bluebirdofoz:20190213084912j:plain

UVマップを利用してテクスチャを展開する

では作成したUVマップを利用してオブジェクトにテクスチャを張り付けてみます。
[マテリアル]タブを開き、[新規]ボタンをクリックして新規マテリアルを作成します。
f:id:bluebirdofoz:20190213084923j:plain

マテリアルを作成したら、これを選択した状態で[テクスチャ]タブをクリックします。
f:id:bluebirdofoz:20190213084939j:plain

こちらも[新規]ボタンをクリックして新規テクスチャを作成します。
f:id:bluebirdofoz:20190213084952j:plain

新しいテクスチャが作成されます。
[画像]パネルの[開く]から外部の画像ファイルを選択することでテクスチャ画像を選択できます。
もう一つ、ここで注目すべきは[マッピング]パネルです。
「座標:UV、マップ:UVMap」という指定がされています。
これにより、ここで設定したテクスチャは先ほど作成したUVマップに従って平面オブジェクトに展開されることになります。
f:id:bluebirdofoz:20190213085004j:plain

試しに以下の画像を読み込んでみました。
f:id:bluebirdofoz:20190213085014j:plain

平面オブジェクトにUVマップの対応通り、展開されていることが分かります。
f:id:bluebirdofoz:20190213085025j:plain

色々試してみる

試しにUVマップを編集してみます。
UVマップを左上の方に寄せてみると、平面オブジェクトには画像の左上しか反映されなくなることが分かります。
UVマップは[UV/画像エディター]上で、メッシュなどと同様、移動(Gキー)、回転(Rキー)、拡縮(Sキー)による編集が可能です。
f:id:bluebirdofoz:20190213085203j:plain

次はUVマップを削除してみました。(「-」ボタン押下)
テクスチャの座標とメッシュの座標のマッピングが取れなくなったため、メッシュに画像が反映されなくなることが分かります。
f:id:bluebirdofoz:20190213085221j:plain

因みに[マッピング]パネルの[マップ]設定はデフォルトだと空欄になります。
空欄でも対象オブジェクトがUVマップを持っていれば、自動的にマップが利用されるようです。
オブジェクトが複数のUVマップを保持していれば1つ目のUVマップが利用されます。
f:id:bluebirdofoz:20190213085232j:plain

次は[UV/画像エディター]と[3Dビュー]についてです。
bluebirdofoz.hatenablog.com

HoloLens特化のホロ恋子モデルを作成する その34(マテリアルの作成)

本日はホロ恋子モデル2の作成枠です。
前回でモデルのリギング、スキニングが完了しました。
f:id:bluebirdofoz:20190212090049j:plain

今回からモデルの着色を行っていきます。
モデルを着色するにはマテリアルを設定していきます。
マテリアルは質感に関する設定を指します。

マテリアルの作成

マテリアルの設定を行うには、マテリアルを作成する必要があります。
メッシュオブジェクトを選択し、[マテリアル]タブを開きます。
[新規]ボタンをクリックしてマテリアルを作成します。
f:id:bluebirdofoz:20190212090100j:plain

すると、新規のマテリアル(質感)の設定がリストに追加されます。
メッシュオブジェクトで初めて作成したマテリアルはメッシュ全体にその設定が反映されます。
f:id:bluebirdofoz:20190212090211j:plain

試しに、ディフューズ(拡散色)の設定を変更してみます。
設定に合わせてモデルの色合いが変わることが確認できます。
f:id:bluebirdofoz:20190212090226j:plain

3Dビューのシェーディング設定

モデルの着色を始める前に、メッシュの色合いを確認できるよう3Dビューの設定を行います。
デフォルトの[3Dビューのシェーディング]は[ソリッド]に設定されています。

[ソリッド]はデフォルトのライト設定の元での陰影を確認するモードです。
このモードはモデルがデフォルトのライトに照らされた状態で表示されるため、シーン内にライト設定がなくてもモデルがはっきりと照らし出されます。
ディフューズ(拡散色)などは見た目に反映される一方で、一部のマテリアルの設定(テクスチャ設定など)は見た目に反映されません。
モデルに光があたったとき、どのような陰影が発生するかを確認するモードと言えます。
f:id:bluebirdofoz:20190212090238j:plain

このままではモデルの見た目が正確に着色されないので、3Dビューのメニューから[3Dビューのシェーディング]プルダウンを開き、[マテリアル]を選択します。

[マテリアル]はテクスチャを含めたマテリアル設定を見た目に反映するモードです。
このモードはソリッドと異なり、デフォルトのライト設定がなく、シーン内のライト設定でモデルが照らし出されます。
このため、適切なライト設定を行っていないとモデルが暗く映ります。
シーン内でモデルがどのように発色するかを確認するモードと言えます。
f:id:bluebirdofoz:20190212090248j:plain

以降、基本的に着色の作業を行う際は[3Dビューのシェーディング]に[マテリアル]を用います。

ライティングまたは発色の設定

前述の通り、[マテリアル]モードの見た目はシーン内のライト設定の影響を受けてしまいます。
このため、色合いを確認するにはライティングの設定を考慮する必要があります。

ライト設定で最も手軽なのは[環境照明]を設定してしまう事です。
環境照明は一定方向からの照明ではなく、シーン全体を一律に明るくします。
[ワールド]タブを開き、[環境照明]パネルのチェックボックスをチェックします。
f:id:bluebirdofoz:20190212090303j:plain

[エネルギー]の項目で光の強さを、[環境照明カラー]のプルダウンで環境照明のライトの設定を変更できます。
f:id:bluebirdofoz:20190212090315j:plain

[環境照明]はライトの設定なので、強くし過ぎると色が白く飛ぶなどの問題が起こります。
マテリアルの本来の色合いを確認したい場合はマテリアルの設定を開き、[シェーディング]パネルから[陰影なし]にチェックを入れます。
これでマテリアルの色合いがそのまま表示されるようになります。テクスチャの確認を行う際などに便利です。
f:id:bluebirdofoz:20190212090325j:plain

ただし[陰影なし]の設定はシーンのライト設定ではなく、マテリアル(質感)の設定になります。
モデルの出力方法によってはモデルの質感設定としてそのまま出力されてしまいます。
他の環境にモデルを持ち込んだ際に、その環境でも照明の影響を受けない場合があるので気を付ける必要があります。

次はUVマッピングについてです。
bluebirdofoz.hatenablog.com

BlenderでVROIDモデル(VRMファイル)を読み込む(VRM_IMPORTERアドオン)

本日は VROID と Blender の技術調査枠です。
VROIDで出力したモデル(VRMファイル)を Blender で読み込むアドオンを試してみます。

VRM_IMPORTER は以下の GitHub で公開されています。
github.com

バージョンについて

2019/02/11現在、Blender2.79向けの更新・サポートは終了したようです。
github.com

VRMはまだまだアップデートが多く行われているフォーマットなので、本記事の手順はすぐに過去のものとなる可能性が高いです。
エラーが発生する場合は、利用中の各ツールのバージョンについて調べてみてください。

今回、私は以下のバージョン環境で作業を実施しています。
Blender:2.79
・VROID:0.5.4
VRM_IMPORTER:Blender2.79向け_2019/02/06最終コミット版

アドオンのインストール

GitHubの[Clone or download]を開き、[Download ZIP]をクリックしてファイルをダウンロードします。
f:id:bluebirdofoz:20190211151427j:plain
github.com

ダウンロードした VRM_IMPORTER_for_Blender2_79-master.zip を任意のフォルダに置いておきます。
Blender を起動し、メニューから ファイル -> ユーザー設定 を開きます。
f:id:bluebirdofoz:20190211151446j:plain

Blenderユーザー設定ダイアログが開くので、[アドオン]タブを選択します。
[サポートレベル]の[テスト中]を選択し、[ファイルからアドオンをインストール]ボタンをクリックします。
f:id:bluebirdofoz:20190211151456j:plain

ファイル選択画面が開くので、先ほどダウンロードした VRM_IMPORTER_for_Blender2_79-master.zip を選択します。
[ファイルからアドオンをインストール]ボタンをクリックします。
f:id:bluebirdofoz:20190211151509j:plain

すると、アドオンの一覧に戻り、VRM_IMPORTER が表示されます。
チェックボックスにチェックを入れて、[ユーザー設定の保存]ボタンをクリックします。
f:id:bluebirdofoz:20190211151519j:plain

ユーザー設定ダイアログを閉じ、メニューから ファイル -> インポート を開きます。
[VRM(.vrm)]の項目が追加されていればインストールは完了です。
f:id:bluebirdofoz:20190211151529j:plain

VROIDモデル(VRMファイル)の読み込み

早速、VROIDモデル(VRMファイル)の読み込みを試してみます。
VROIDで任意のモデルを出力し、VRMファイルを作成します。
f:id:bluebirdofoz:20190211151541j:plain

VRM_IMPORTER はVRMファイル読み込みの際、同じディレクトリにテクスチャファイルを全て展開します。
Blenderがバイナリから直接画像ファイルを読み込めないため)
このため、読み込むVRMファイルはなるべく単独のディレクトリに保存しておくのが望ましいです。
f:id:bluebirdofoz:20190211151626j:plain

Blenderに戻り、ファイル -> インポート -> VRM(.vrm) を選択します。
ファイル選択画面で先ほど出力したVRMファイルを指定し、[import VRM]ボタンをクリックします。
f:id:bluebirdofoz:20190211151635j:plain

モデルが表示されれば読み込み成功です。
f:id:bluebirdofoz:20190211151644j:plain

シェーディングを[マテリアル]に切り替えればテクスチャ色が表示されます。
マテリアルがデフォルトで[陰影なし]になっているのでライト設定は不要です。
f:id:bluebirdofoz:20190211151654j:plain

Blenderが警告無しに強制終了する問題に対処する(Blenderのデバッグログの確認)

本日は Blender の調査枠です。
最近、ユーザ設定の[システム]タブを開こうとしたり、アドオンによるファイル読み込みを行おうとすると、Blenderが何の警告も無しに強制終了する事象が発生するようになりました。
f:id:bluebirdofoz:20190210204856j:plain

今回はこういった事象の調査方法と、私のケースの解決方法をまとめます。
調査方法では Blender 操作中の強制終了の他、起動時に即座に終了してしまうケースでもログを確認できます。

Blenderデバッグログの確認

以下の手順で Blender を起動すると、コマンドライン上で Blenderデバッグログを確認できます。

1.Blender.exe のあるディレクトリで[SHIFTキー + 左クリック] -> PowerShell ウィンドウをここに開く を選択する。
f:id:bluebirdofoz:20190210204906j:plain

2.以下のコマンドで Blender.exe を起動する。
・.\blender.exe --debug-all
f:id:bluebirdofoz:20190210205010j:plain

3.この状態で Blender を操作すると、PowerShellデバッグログが表示される。
f:id:bluebirdofoz:20190210205020j:plain

エラーの確認と対処

デバッグログを開いた状態で、ユーザ設定の[システム]タブを開いてみました。
すると、Blender が強制終了し、PowerShell には以下のエラーログが表示されていました。
f:id:bluebirdofoz:20190210205032j:plain

I0210 20:31:08.962450 52544 device_cuda.cpp:2096] CUEW initialization succeeded
I0210 20:31:08.963430 52544 device_cuda.cpp:2098] Found precompiled kernels
I0210 20:31:09.077450 52544 device_opencl.cpp:58] CLEW initialization succeeded.
Error: EXCEPTION_ACCESS_VIOLATION

device_opencl.cpp のコードで EXCEPTION_ACCESS_VIOLATION のエラーが発生しているらしい。

調べてみると、以下の記事がヒットしました。
qiita.com

記事にある通り、以下の内容の Blender.bat を作成してみます。
Blender.bat

cd C:\Program Files\Blender Foundation\Blender
set CYCLES_OPENCL_TEST=NONE
start blender.exe
pause

f:id:bluebirdofoz:20190210205053j:plain

作成した Blender.bat を実行して Blender を起動し、ユーザ設定の[システム]タブを開いてみると……。
f:id:bluebirdofoz:20190210205101j:plain
無事、[システム]タブを開くことができました。
しかし参考記事にもある通り、何故こうなったか、何故テストを無効化すると問題なくなるのかは調べてもよく分からず……。
起動時ではなく、[システム]タブを開いた時に発生するのはグラボの情報取得辺りが原因?

アプリMicrosoftHoloLensでHoloLensを操作する

本日は HoloLens の調査枠です。
HoloLensにPCからアクセスするアプリ「Microsoft HoloLens」を試してみます。

MicrosoftHoloLensのインストール

Microsoft HoloLens は HoloLens をPC側からアプリを起動および停止したり、ライブストリームの表示などを行うアプリです。
Microsoft HoloLens は以下のURLからダウンロード可能です。
www.microsoft.com
f:id:bluebirdofoz:20190209132459j:plain

ブラウザの[入手]ボタンをクリックすると、Store アプリが開きます。
Microsoftアカウントでログインして、Storeアプリ内の[入手]ボタンをクリックします。
f:id:bluebirdofoz:20190209132509j:plain

ダウンロードが開始され、しばらくするとインストールが完了します。
メニューに「Microsoft HoloLens」が追加されているので、これをクリックして起動できます。
f:id:bluebirdofoz:20190209132518j:plain

MicrosoftHoloLensの使い方

Microsoft HoloLens」を起動すると、初回起動時は以下のような[Add a device]ボタンのみが表示されます。
f:id:bluebirdofoz:20190209132546j:plain

[Add a device]ボタンをクリックすると、接続する HoloLens のIPアドレスを要求されます。
IPアドレスを入力して[connect]ボタンをクリックします。
f:id:bluebirdofoz:20190209132558j:plain

接続に成功すると、Hololens の DevicePortal のアカウント名とパスワードを要求されます。
アカウント名とパスワードを入力して[Done]ボタンをクリックします。
f:id:bluebirdofoz:20190209132613j:plain

これで「Microsoft HoloLens」からの HoloLens の操作が可能になります。
一度接続した HoloLens の情報は保持され、一覧に表示されるようになります。
操作したい HoloLens を選択します。
f:id:bluebirdofoz:20190209132629j:plain

ライブストリームを試してみます。
HoloLens に接続すると以下のアイコンが表示されるので[Live stream]をクリックします。
f:id:bluebirdofoz:20190209132640j:plain

HoloLens で見ている映像がリアルタイムで表示されました。
ライブストリームはRS5で追加されたプロジェクションではなく、DevicePortalのライブプレビューの機能を利用しているようです。
f:id:bluebirdofoz:20190209132650j:plain

本アプリでは DevicePortal でアクセスして利用する機能の多くがそのまま利用可能です。
アクセス先を保存しておけるので、複数のHololensを管理する際に役立ちます。

UnityEventを使ってInspectorビューから実行処理を指定する その2(引数の指定)

本日は Unity の技術調査枠です。
前回、UnityEventの設定方法をまとめました。
bluebirdofoz.hatenablog.com


今回はUnityEventに引数を設定する方法についてまとめます。
f:id:bluebirdofoz:20190208072017j:plain

Inspectorビューから引数を渡す

UnityEventで関数を指定する際、引数の指定が必要な関数も利用可能です。
以下のようなオブジェクトの拡大倍率を引数で指定する関数を追加します。
・ChangeScale.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ChangeScale : MonoBehaviour {
    public void ToDouble()
    {
        // オブジェクトを2倍の大きさに変更
        transform.localScale = transform.localScale * 2.0f;
    }
    public void ToChangeScale(int scale)
    {
        // オブジェクトを任意の倍率に変更
        transform.localScale = transform.localScale * scale;
    }
}

この状態で、UnityEvent の Inspector ビューから関数を検索します。
すると、以下のように引数付きの関数も一覧に表示され、選択が可能になっています。
f:id:bluebirdofoz:20190208072031j:plain

関数を指定し、Inspector ビューを改めて確認すると、以下のように引数の値を設定する欄が表示されています。
f:id:bluebirdofoz:20190208072047j:plain

ただし制限として、引数の数が1つまでの関数しか利用できません。
2つ以上の引数を利用する関数は、関数の一覧に表示されません。

引数を動的に渡す

上記の方法だと、Inspector ビューで引数の値を指定するため、引数をプログラム実行中に自由に変更できません。
動的に引数を渡したい場合は、UnityEvent クラスを継承した新規クラスを作成する必要があります。
docs.unity3d.com

連続タップの検出スクリプトをサンプルに利用します。
タップカウントの値を引数として UnityEvent を設定できるよう改修しました。

UnityEvent を継承した MyIntEvent を作成し、Invoke(int arg0) 関数で引数を指定して実行しています。
・MultiTapEvent.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// IInputClickHandler を利用するため InputModule を追加
using HoloToolkit.Unity.InputModule;

// UnityEvent を利用するため Events を追加
using UnityEngine.Events;


// 引数に Int を受け取る UnityEvent<T0> の継承クラスを作成する
// Inspector ビューに表示させるため、Serializable を設定する
[System.Serializable]
public class MyIntEvent : UnityEvent<int>
{
}


public class MultiTapEvent : MonoBehaviour,
IInputClickHandler // タップ操作検出
{
    /// <summary>
    /// グローバルリスナーの有無
    /// </summary>
    [Tooltip("グローバルリスナーの有無")]
    public bool IsGlobalListener = false;


    // 作成した継承クラスで UnityEvent を登録する
    /// <summary>
    /// 連続タップ実行処理
    /// </summary>
    [SerializeField, Tooltip("連続タップ実行処理")]
    private MyIntEvent MultiTapUnityEvent;


    /// <summary>
    /// 連続タップ許容時間(秒)
    /// </summary>
    [SerializeField, Tooltip("連続タップ許容時間(秒)")]
    private float MultTapTime = 0.5f;

    /// <summary>
    /// 連続タップカウント
    /// </summary>
    private int p_MultTapCount;

    /// <summary>
    /// 連続タップ計測開始時刻
    /// </summary>
    private float p_MultTapStart;

    /// <summary>
    /// 起動時処理
    /// </summary>
    void Start ()
    {
        if (IsGlobalListener)
        {
            // 全てのジェスチャーイベントをキャッチする
            // 本設定を有効にしてColliderオブジェクトにアタッチした場合
            // オブジェクトへのタップとグローバルのタップが
            // 別々に検出される(連続タップとなる)ので注意
            InputManager.Instance.AddGlobalListener(gameObject);
        }
    }

    /// <summary>
    /// 定期実行
    /// </summary>
    void Update ()
    {
        // 連続タップ判定
        if (p_MultTapCount > 1)
        {
            // タップカウントが 2 以上の時、連続タップの発生チェック
            if ((Time.time - p_MultTapStart) > MultTapTime)
            {
                // 連続タップ許容時間が経過していればカウントに応じて処理を実行
                if (p_MultTapCount == 2)
                {
                    // ダブルタップ処理
                    Debug.Log("DoubleTap");
                    
                    // タップカウントの値を引数に指定して UnityEvent を実行
                    MultiTapUnityEvent.Invoke(p_MultTapCount);
                    
                }
                if (p_MultTapCount == 3)
                {
                    // トリプルタップ処理
                    Debug.Log("TripleTap");
                    
                    // タップカウントの値を引数に指定して UnityEventを実行
                    MultiTapUnityEvent.Invoke(p_MultTapCount);
                    
                }
                p_MultTapCount = 0;
            }
        }
    }

    /// <summary>
    /// タップ検出
    /// </summary>
    /// <param name="eventData"></param>
    public void OnInputClicked(InputClickedEventData eventData)
    {
        Debug.Log("clicked!");

        // 現在時刻の取得
        float nowTime = Time.time;

        // 連続タップ確認
        float tapTime = nowTime - p_MultTapStart;
        if (tapTime > MultTapTime)
        {
            // 前回タップから連続タップ許容時間を超えていれば初回タップと再判定
            p_MultTapCount = 1;
        }
        else
        {
            // 前回タップから連続タップ許容時間内ならば連続タップと判定
            p_MultTapCount++;
        }
        // 連続タップ計測開始時刻を更新
        p_MultTapStart = nowTime;
    }
}

作成したスクリプトSphere オブジェクトにアタッチします。
すると、Inspector ビューに「Unity Event (Int32)」という UnityEvent の設定項目が表示されます。
f:id:bluebirdofoz:20190208072246j:plain

オブジェクトを指定し、関数一覧を開きます。
すると「Dynamic int」という項目が追加されており、そこに引数指定可能な関数が表示されます。
動的に引数を渡す関数を指定したい場合は、この「Dynamic int」に表示された関数を指定します。
f:id:bluebirdofoz:20190208072257j:plain

「再生」ボタンをクリックして動作を確認してみます。
f:id:bluebirdofoz:20190208072307j:plain

連続タップを行ったとき、ダブルタップの時は2倍、トリプルタップの場合は3倍というように、タップ回数に応じて倍率の異なる拡大処理が実行されれば成功です。
f:id:bluebirdofoz:20190208072315j:plain

UnityEventには以下の4つの抽象クラスがあり、これらを利用すると最大4つの引数までの UnityEvent の利用が可能です。
docs.unity3d.com
docs.unity3d.com
docs.unity3d.com
docs.unity3d.com

UnityEventを使ってInspectorビューから実行処理を指定する その1(UnityEventの使い方)

本日は Unity の技術調査枠です。
UnityEvent を使って Inspector ビューから実行処理を指定する方法をまとめます。
以下の記事で作成した長押しタッププロジェクトを流用します。
bluebirdofoz.hatenablog.com
f:id:bluebirdofoz:20190207005002j:plain

UnityEvent

UnityEvent は関数そのものを引数として設定するコールバックの機能を提供します。
特色として Inspector ビュー上に設定UIを表示することができます。
docs.unity3d.com

UnityEventを用いた長押しタップスクリプト

長押しタップスクリプトを UnityEvent を用いたものに修正します。
UnityEvent のメンバ変数を追加し、長押しタップ時に Invoke() を実行する形にしました。
・LongTapEvent.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// IInputHandler を利用するため InputModule を追加
using HoloToolkit.Unity.InputModule;

// UnityEvent を利用するため Events を追加
using UnityEngine.Events;

public class LongTapEvent : MonoBehaviour,
IInputHandler // タップダウン、タップアップ検出
{
    /// <summary>
    /// グローバルリスナーの有無
    /// </summary>
    [Tooltip("グローバルリスナーの有無")]
    public bool IsGlobalListener = false;

    /// <summary>
    /// 長押しタップ実行処理
    /// </summary>
    [SerializeField, Tooltip("長押しタップ実行処理")]
    private UnityEvent LongTapUnityEvent;

    /// <summary>
    /// 長押しタップ検出時間(秒)
    /// </summary>
    [SerializeField, Tooltip("長押しタップ検出時間(秒)")]
    private float LongTapTime = 3.0f;

    /// <summary>
    /// 長押しタップ計測開始時刻
    /// </summary>
    private float p_LongTapStart;

    /// <summary>
    /// 起動時処理
    /// </summary>
    void Start()
    {
        if (IsGlobalListener)
        {
            // 全てのジェスチャーイベントをキャッチする
            // 本設定を有効にしてColliderオブジェクトにアタッチした場合
            // オブジェクトへのタップとグローバルのタップが
            // 別々に検出される(2回処理が走る)ので注意
            InputManager.Instance.AddGlobalListener(gameObject);
        }
    }

    /// <summary>
    /// タップダウン検出
    /// </summary>
    /// <param name="eventData"></param>
    public void OnInputDown(InputEventData eventData)
    {
        Debug.Log("TapDown!");

        // 現在の時刻を検出時刻として記録
        p_LongTapStart = Time.time;
    }

    /// <summary>
    /// タップアップ検出
    /// </summary>
    /// <param name="eventData"></param>
    public void OnInputUp(InputEventData eventData)
    {
        Debug.Log("TapUp!:" + LongTapTime);

        // 現在時刻の取得
        float nowTime = Time.time;

        // 長押しタップ検出時間より長くタップされていれば長押しと判定
        float tapTime = nowTime - p_LongTapStart;
        if (tapTime > LongTapTime)
        {
            // 長押しタップ処理
            Debug.Log("LongTap");
            // UnityEventを実行
            LongTapUnityEvent.Invoke();
        }
    }
}

LongTapEvent.cs をアタッチしたオブジェクトの Inspector ビューを確認します。
すると、以下のように UnityEvent を設定するパネルが表示されています。
f:id:bluebirdofoz:20190207004939j:plain

実行処理の作成

UnityEvent に設定する実行処理を持ったクラスを作成します。
このときの注意点として、指定する関数は public 関数である必要があります。
以下のようなオブジェクトを2倍の大きさにする関数を持ったクラスを作成しました。
・ChangeScale.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ChangeScale : MonoBehaviour {
    public void ToDouble()
    {
        // オブジェクトを2倍の大きさに変更
        transform.localScale = transform.localScale * 2.0f;
    }
}

作成したスクリプトSphere オブジェクトにアタッチします。
f:id:bluebirdofoz:20190207005017j:plain

作成した関数を実行処理として指定します。
LongTapEvent.cs の UnityEvent にある「+」ボタンをクリックします。
f:id:bluebirdofoz:20190207005027j:plain

作成された項目に、実行したいスクリプトを保持するオブジェクトを指定します。
今回の場合、Sphere オブジェクトを指定します。
f:id:bluebirdofoz:20190207005036j:plain

すると関数のプルダウンに、そのオブジェクトが保持するクラスと利用可能な関数の一覧が表示されます。
先ほど作成した ChangeScale クラスの ToDouble 関数を指定します。
f:id:bluebirdofoz:20190207005049j:plain

これで設定完了です。
「再生」ボタンをクリックして動作を確認してみます。
f:id:bluebirdofoz:20190207005101j:plain

長押しタップを行ったとき、拡大処理が実行されれば成功です。
f:id:bluebirdofoz:20190207005112j:plain
イベントの検出クラスと処理の実行クラスを分けることができるため、機能追加や処理の切り替え、スクリプトの流用が容易になります。

次は UnityEvent での引数の指定についてです。
bluebirdofoz.hatenablog.com