「ペンタVR」タグアーカイブ

Unityからペンタブレットのマルチタッチ機能を利用する方法

この記事はOculus Rift Advent Calendar 2015の6日目です。

はじめに

ペンタVRというVRお絵描きツールを開発しているのですが、今回はお絵描き以外でも使えそうなペンタブレットのマルチタッチ機能の利用方法についてご紹介させていただきます。

ペンタブレットのマルチタッチ機能が使えると何が嬉しいかというと、既に絵描きさんの間に広く普及していおり、同じ理由で比較的安価に入手することができます。
また、iOS/Androidのタブレットで実装する場合と比較すると、iOS/Android側からPCに情報を送信するアプリを別途開発する必要がないため、実装は少なくて済みます。

※もちろんペンで直接お絵描きできますが、それについてはこちらを参照ください。

今回は、Unity 5.0.3p3 64ビット版とWACOM Intuos Proを使用します。

マルチタッチをC#から利用する方法については以下の記事を参考にしました。

マルチタッチの基本部分を実装してみる

2つめの記事からサンプルコードをダウンロードして、下記クラスをプロジェクトに追加します。

  • FeelMultiTouchAPIConst.cs
  • MemoryUtil.cs
  • MTAPI.cs

上記のクラスはそのまま使えますが、初期化などは下記コードを参考にして、TabletTouchクラスとして実装します。

  • MainWindow.xaml.cs

クラスフィールド

そのままコピペで大丈夫です。

UpdateDeviceListメソッド

UpdateDeviceListメソッドは、リストボックスにデバイス一覧を表示する機能ですが、今回はリストボックスを使用せずデバッグログのみ出力します。
また、後ほど最初に見つかったデバイスを利用するように実装したいと思います。

MainWindowメソッド

MainWindowメソッドはコンストラクタですが、Unityのライフサイクルに則りAwakeメソッドとして実装しましょう。

UnregisterEventメソッド

UnregisterEventメソッドは、マルチタッチ機能の終了処理です。
見た目に関する処理は、Unityの仕組みを利用するので削除しましょう。

MainWindow_Closingメソッド

MainWindow_Closingメソッドは、OnDisableメソッドに置き換えます。

RegisterEventメソッド

RegisterEventメソッドは、マルチタッチ機能の開始処理です。
今回は、モードはWMTProcessingModeNoneに、イベントタイプはコールバックを残して削除します。
また、見た目に関する処理は、Unityの仕組みを利用するので削除しましょう。

MainWindow_Loadedメソッド

MainWindow_Loadedメソッドは、OnEnableメソッドに置き換えます。

wmtFingerCallbackメソッド

wmtFingerCallbackメソッドは、タブレットに触れている間のみコールバックが呼び出されます。
ただし、コールバックメソッド内はメインスレッドではなく、Unityの機能が利用できないため、受け取った情報をフィールドに保持しておきます。
また、コールバックとUpdateメソッドでは呼ばれるタイミングが異なるため、受け取った情報に更新があるかどうかをフラグに持たせます。

マルチタッチの可視化とタップの検出

ここからは重要では無いのですが・・・

TouchButtonクラス

作成したボタンにはTouchButtonコンポーネントをアタッチしておきます。
OnTapメソッドを作成し、呼び出されたらデバッグログを出力するようにしておきます。

マルチタッチの可視化

フィールドに保持したマルチタッチ情報を可視化します。
プロットする指の数は毎フレーム異なるため、GameObjectを使用せず、DrawMeshメソッドで直接描画を行っています。
なお、マトリックスからトランスフォームを取り出すのにはこちらを参考にしました。

タップの検出

最初に検出した指でタップ処理を実装します。
可視化で使用したのと同様のマトリクスを元にRayを飛ばしてボタンを特定し、さらに指を離した際にボタンのOnTapメソッドを呼び出しています。

シーンの構成

以下の様にシーンに、TabletTouchオブジェクトと、その子としてTouchButtonオブジェクトを作成し、各コンポーネントをアタッチします。
TabletTouch
TouchButton

実行すると、マルチタッチの可視化と、タップの検出が出来ていることが確認できます。

やったー!

最後に

このようにUnityから簡単にマルチタッチ機能を実装することができました。

ただし、VRで使う場合は、以下の様な欠点がありますが、そこは使い所と工夫次第なのかなと思います。

  • タブレット自体の位置や傾きが取れない
  • タブレットに触れるまで指を検出できない

もし面白いVRコンテンツを思いついたらご相談ください。
技術的な協力など出来るかもしれません。

次は、pafuhana1213さんの2015年の私とOculusRift  (VRに関する資料・投稿記事・作品まとめ)です。

UnityからWintab APIを利用する方法

WintabをC#から利用する方法については以下の記事を参考にしました。

上記の記事で提供されているソースコードはほぼ改変の必要ありませんが、一点だけ問題があります。
UnityのC#ではウインドウプロシージャが存在しないため、別の方法でWindowsメッセージを受信する必要があります。

そこで、以下の様にuser32.dllをDLLImportすることで、UnityからWindowsメッセージを受信することが出来ます。
※ただし、32ビット版のUnityエディタでしか動作しません。

※参考にしたURLを紛失してしまったのですが、恐らくここを見て実装したと思われる。
http://forum.unity3d.com/threads/recieve-window_commands-in-unity.213741/

コンポーネントをGameObjectにアタッチして実行すると、以下の様なログが出力されます。
スクリーンショット 2015-09-08 02.40.35

ペンタVRの実装方式について

ペンタVRとは?

VRHMDとペンタブレットを利用して、仮想空間でお絵描きをする仕組みのことです。

発端となったのは、よー清水さんの下記ツイート

一連の流れは、栗坂こなべさんが纏めてくれています。

最新の情報はTwitterのハッシュタグ #ペンタVR で確認できます。

ペンタブレットの基本的な使い方、各部名称についてはこちら

開発環境

  • OS : Windows
  • ゲームエンジン : Unity
  • VRHMD : Oculus Rift
  • ペンタブレット : Intuos

どうやって実現するか?

ペンタブレットの情報を取得する方法

  1. マウスの座標を利用
    Unity標準のInput.mousePositionからマウスの座標として取得することが出来ます。
    筆圧などの付加情報が不要な場合はこちらでも良いではないでしょうか。

  2. Wintab APIを利用 ※こちらを採用しました。
    WACOMさんが提供しているWintab APIを利用することで、各種情報を取得することが出来ます。
    各種情報はWindowsメッセージとして送られてきますが、UnityからWindowsメッセージを取得するには一工夫必要になります。

  3. おまけ:Macの場合
    マウスイベントに筆圧情報が入ってくる様ですが、Unityから利用するにはNative Pluginの実装が必要となりそうです。

ペンタブレットを位置を現実とVRで関連づける方法

多くのOculus Rift向けVRコンテンツでは、仮想空間内のカメラ位置にプレイヤーを一致させますが、
今回は、タブレットの上部にOculus Riftの赤外線カメラを固定することで、現実の赤外線カメラとHMDの相対位置をそのまま仮想空間に持ち込みます。
これにより、現実と仮想空間でタブレットの位置を一致させることが出来ます。
ただし、タブレットの傾きは反映されません。

キャンバスを管理する方法

キャンバスの管理方法は、大まかに2つに分類できます。

  1. 既存のお絵描きアプリでキャンバスを管理
    デスクトップのキャプチャ画像をテクスチャに貼り付ける方式です。
    既存のお絵描きアプリの機能をそのまま仮想空間に持ち込むことが出来ますが、現状では遅延が大きく使い物にならないようです。

    • キャプチャアプリからGPU側のテクスチャ情報を直接更新できれば、遅延が改善するかも知れません。
    • 平面のお絵描きに限定すれば、APIを提供することでお絵描きアプリ側にペンタVR連携機能を組み込むことが出来る可能性があります。
  2. 新規のVRアプリでキャンバスを管理 ※こちらを採用しました。
    ゲームエンジンの機能を利用してテクスチャの更新を行う方式です。
    お絵描きアプリをフルスクラッチで実装するような手間が掛かりますが、VRならではの表現を行いやすいメリットがあります。

具体的な実装方法については次回以降に行いたいと思います。