少し前に紹介したQUMARION SDKのC#ラッパーをいくらか強化し、Unityで使えるようにしました。
概要
「QUMARIONは人型入力デバイスで…」といった基本事項は本記事では省略します。本ブログで過去に扱った記事もあるのでデバイスとしてのポテンシャルについてはコチラでご覧ください。一つ目の記事で紹介しているのがもっとも典型的なQUMARIONの使い方で、下に行くほどフリーダムになっていきます。
QUMARIONの人気っぷり?が分かるよう、以前に私がQUMARION関係で投げたツイートを二つほど掲載しておきます。
https://twitter.com/baku_dreameater/status/678347488730812416
https://twitter.com/baku_dreameater/status/678491938383794176
導入: 前の記事のときと何が変わったの?
では本題。上記の記事のうち「QUMARION SDKをC#でラップしてみた」でも触れているのですが、QUMARIONにはC/C++用のSDKがあり、大きく分けて2種類の機能が提供されています。
- Low API: 低レイヤーAPI。角度センサーや加速度センサーの値を直接読める。ロボットとかと好相性
- Pdk API: 高レイヤーAPI。QUMARIONのポーズを人型ボーンに適用した結果を取れる。CGと好相性
このうち以前の記事の時点ではLow APIのみについてC#用にラッパーを実装してました。これはLow APIの方がラッパーの作成がラクだった事に加え、上のツイートに載ってるようなSoftbank Pepperの操縦プログラムを作る際にはLow APIで角度センサーの値が読めれば十分だったためです。
それで個人的にはPepperの操縦にQUMARIONが使えてひとまず満足していたのですが、Twitterで「UnityでQUMARIONって使えないの?」という発言が耳に入ったことと、Low APIだけのラッパーはいかにも片手落ちでダサいと思っていたことから、手を付けていなかったPdk APIのラッパーを実装しました。ラッパー自体は一般的な.NETアプリケーションで使えるように作ってありますが、今回は実際に使われそうな?プラットフォームであるUnityに焦点を絞って紹介をします。
動作環境
QUMARIONはWindowsでしか動きません。これはSDK自体がWindowsにしか対応していない為です。あらかじめご注意下さい。
C#ライブラリの入手とUnityへの配置
ラッパーライブラリのソースコードはGitHubに公開しています。開発はVisual Studio 2015 Communityで行っており、ラッパーのライセンスはMITライセンスです。
またビルド手順に若干のクセがあるのでバイナリ版も用意しています。バイナリ版はGoogle Driveに置いてあるのでこちらから落として下さい。
バイナリ配布に伴っての重要な注意ですが、QUMARION SDKのラッパーはGitHubのソースファイルを丸ごとUnityに持ち込んでも動きません。事前にVisual Studioでdllへビルドする処理は必須です。これはラッパーのC#言語バージョンがC#6.0に準拠しているためです。
ソースからビルドする場合は以下の手順や注意事項を確認してください。
[expand title="ソースのビルド(クリックして展開)"]
ソースコードのビルド方法についてですが、Visual Studio 2015 (Community以上)を使って普通にソリューションを開きビルドします。
(2016/1/16追記: ライブラリ本体とは直接関係ないのですが、ソリューションの中に含まれるGUIのサンプルでReactive Extensionsを用いているため、ビルド時にコレをインストールしておく必要があります。「連載:Reactive Extensions(Rx)入門 第1回 Reactive Extensionsの概要と利用方法」などを参考にインストールを行ってください。)
ビルドにあたってはターゲットプラットフォームを「Any CPU」にし、ラッパー本体のプロジェクトである「QumarionDotNet」プロジェクトのプロパティ内で、ビルド時のプリプロセッサシンボルに「UNITY」というのを指定します。
このシンボルを使っている場所は"DllImportSetting.cs"というソースです。ソースの中身はこんな感じ。
using System; namespace Baku.Quma { /// <summary>Dllのロード先を定義します。</summary> public static class DllImportSetting { /// <summary>現在実行中のプロセスが64bitプロセスかどうかを取得します。</summary> internal static readonly bool Is64bit = (IntPtr.Size == 8); //NOTE2: Unity用にビルドするときはUNITYシンボルをプロジェクトプロパティで定義してAny CPU構成を取ること //NOTE3: Unity上にソース自体を持っていくのは無理: なぜなら本プロジェクトがC# 6.0準拠で書かれているため。 /// <summary>QUMARION SDKのライブラリ(32bit版)のインポート先です。</summary> #if UNITY public const string DllName86 = "QmPdkDll"; #else public const string DllName86 = @"dll\release\x86\QmPdkDll.dll"; #endif /// <summary>QUMARION SDKのライブラリ(64bit版)のインポート先です。</summary> #if UNITY public const string DllName64 = "QmPdkDll"; #else public const string DllName64 = @"dll\release\x64\QmPdkDll.dll"; #endif } }
ここではDllImportの対象を使い分けるため処置を行っています。Unityと通常の.NETではDllImportに指定したファイル名と実行時に探すライブラリファイルの対応づけが異なるため、こういう使い分けが必要になっています。なお「構成をAny CPUにしてね」と書いてる所から分かるかと思いますが、32bit用SDKと64bit用SDKの使い分けについては同じdllから勝手に使い分けてくれるようにしてあります。
ビルド結果の出力先は標準的なVSプロジェクトと同じ"QumarionDotNet\bin(Debug|Release)\QumarionDotNet.dll"です。
[/expand]
バイナリ版あるいはビルドによって"QumarionDotNet.dll"を入手したら適当なUnityプロジェクトを作り、Assetsの中に"QumarionDotNet.dll"を置いてください。XMLドキュメントコメントがあった方が使いやすいのでdllに加えて"QumarionDotNet.XML"も一緒に配置しておくのをオススメします。
QUMARION SDKの入手と配置
上記のラッパーバイナリやGitHubレポジトリには大元のQUMARION SDKは入ってません。
QUMARION SDKの公式ページで規約に同意してSDKをダウンロードしてください。特に商用利用の際は規約に注意してください。
一応ライセンス周りで断っておきますが、上記のダウンロード手順がある事からも分かる通り、C#ラッパーはライセンス的に元々のC/C++用SDKと分離しています。C#ラッパーのソース自体にも私が記載したMITライセンスが利いてますが、二次利用者の方はそれと本来のSDKの規約とを別々に守ってお使い下さい。
SDKの中身を展開してみると「lib/release/x86/QmPdkDll.dll」と「lib/relase/x64/QmPdkDll.dll」というファイルがあり、これがそれぞれx86, x64用のSDK本体です。これらをUnity側に持っていって先ほど導入したC#ラッパーから見えるように設定します。
Unity側のAssetsに「Plugins」というフォルダを作り、その直下に子フォルダとして「x86」「x86_64」の二つを追加します。「x86」フォルダには「lib/release/x86/QmPdkDll.dll」を、「x86_64」フォルダには「lib/relase/x64/QmPdkDll.dll」を、それぞれコピーします。これでターゲットが32bitでも64bitでもライブラリが使えるようになります。配置例は以下のような感じです(Plugins以外にもフォルダが映ってますが無視してください)。
Unityサンプルその1: ボーンを作って眺める
Unity用のサンプルスクリプトはGitHubのコチラに置いています。こちらのスクリプト群はQumarionDotNetとは別物として(MITライセンスで)公開しています。スクリプトはUnityのAssetsの適当なフォルダに突っ込んで使ってください。
ではサンプルの使い方紹介へ。QUMARIONの使い方第一歩として、まずQUMARIONのボーン情報を絵で出してみます。UnityにTransformコンポーネントだけがついた空のオブジェクトを配置し、サンプルスクリプトのうち「Samples/PdkSample1_BoneVisualizer/PdkBoneVisualizer」をアタッチします。
コレでQUMARIONをUSBでPCに接続し実行してみると、QUMARION SDKで定義された標準ボーンが表示されます。リアルタイムでQUMARIONと同期してるのでグリグリ動かしてみてください。
スクリプトの"Use Accelerometer"を切り替えると加速度センサの値を使うかどうか選べます。加速度センサを用いる場合、体全体が横に倒れるような姿勢をとらせることも可能になります。
Unityサンプルその2: ヒューマノイドを動かす
こっちが本番です。上の例ではQUMARIONの標準ボーンを動かしていますが、実際には既存の3DモデルをQUMARIONで制御したい人の方がだいぶ多いと思うので、そこそこ実用に堪えそうなサンプルを作ってみました。
適当なヒューマノイドモデルを持ってきて「Samples/PdkSample2_HumanoidManipulator/PdkToHumanoid」をアタッチします。アニメーターを配置してコントローラは外してください。コントローラの制御次第ではコントーラとサンプルの両立も出来ると思いますが、今回はQUMARION以外ではボーンを制御しないようにします。あと、スタートの時点でキャラが必ずTポーズをとるようにしてください。これについては後述します。
今回は例としてUnityちゃんにお手伝いしてもらいます。設定はこんな感じ。
スクリプトの設定のうち"Animator"がNoneになってますが、これはNoneの場合アタッチ先のオブジェクト(今回ならUnityちゃん)のアニメーターを勝手に拾うので放置しておいて構いません。これで実行します。
Unityちゃんがきちんと動かせているのが分かりますね。
Unityサンプルの中身について
一つ目のサンプルは大した事してないのですが、ヒューマノイドを動かす方のスクリプトでは適用先のキャラクターボーンの違いを吸収するよういろいろ手を回しています。詳細はスクリプトの実装を見てほしいのですが、大まかな指針としては以下のような計算処理をやっています。
- Start()の時点でQUMARION SDK標準のボーン構造をロードする。ライブラリの仕様でロードした瞬間のボーンは(QUMARIONのハードウェアと同期する前は)Tポーズを取っている
- 適用先キャラクターの初期姿勢がTポーズであるという前提で、初期ポーズでの各ボーンの回転情報と、Tポーズでの固定座標軸をキャッシュ
- QUMARION側のボーンでもTポーズ時点での固定座標やらなんやらをキャッシュ
- Update()の際は、クォータニオンの回転軸をうまく座標変換していくことで「QUMARIONボーンの姿勢回転」 -> 「(中間的な、QUMARIONにもボーンにも依存しない回転表現)」 -> 「ヒューマノイド側の姿勢回転」という変換を順番に行う
このうち2番目の計算については毎回Tポーズで初期状態をキャッシュさせなくても事前調査をやって静的な情報として保持することが可能です。詳細は"PdkToHumanoid"のStart関数の実装を頑張って読んで下さい。うまくデータを捌くことで、ヒューマノイドの初期ポーズがTポーズじゃなくてもQUMARIONとの同期が取れます。
最後に
ホントはヒューマノイドへの適用スクリプトは座標計算のごにょごにょがあるのでその辺もきちんと紹介したいのですが、いかんせん私はこういう計算が苦手で「ギリギリ動いた」というとこまでしか持っていけてないので人に説明するほど余裕が残っていません…。
また個人がノリで作ったラッパーなのでバグやらなんやらが含まれる可能性が非常に高いです。何か見つけました場合はこちらの記事へのコメントかTwitterまでご連絡頂ければ幸いです。