Bakulog

獏の夢日記的な何か。

QUMARION SDKをC#でラップしてみた

ラッパー公開したので書きました。使い方の紹介も兼ねています。

 

2015/12/21追記: GitHub上のソリューション構成を若干変更したためリンクの修正と若干の加筆をしました。

 

もくじ

  • QUMARIONとは何者か
  • .NET用にQUMARION SDKラッパーを作りたい理由
  • QUMARION SDKの構成について
  • QUMARIONのボーン/センサ構成
  • ラッパーのソース公開先(GitHub)とサンプルコード
  • ラッパーの実装について
  • Unityでの再利用について
  • まとめ

 

 

QUMARIONとは何者か

この記事を見てくださってる方には説明不要な気もしますが、QUMARIONとはいわゆる「人型入力デバイス」で、人形みたいなデバイスの可動関節を動かしながら角度を計測することで主にヒューマノイドCGのモーションやポーズ生成を支援するデバイスです。

QUMARIONを利用したアプリケーションとしては販売元でもあるセルシスがCLIP STUDIOシリーズのソフトをいくつか対応させているほか3ds maxなどへのプラグインも提供されています(詳細はQUMARIONの製品ページで確認できます)。

 

とはいえ当然コレだけではサードパーティ方面への広がりが生まれないので、実際には更にQUMARIONを利用したアプリケーション作成のためのSDKが提供されています。リンク先にも書かれていますがライセンスはそこそこ緩く、有償アプリケーションでも売り上げが一定以下なら無償でSDKが使えるなど、個人で同人範囲で何か作るのにも向いていそうな感じがします。

 

んで。本記事はタイトルの通り、単にQUMARIONで遊ぶのではなくSDKを利用してなんか作りたい方を想定した記事です。そこで、以下ではSDKを.NET(C#)から使えるようにした話を簡単に書き留めておきます。

 

 

.NET用にQUMARION SDKラッパーを作りたい理由

QUMARION SDKWindows向けのC/C++用ライブラリとして.lib/.dllとヘッダファイルが提供されていますが、私は普段C#/WPFGUI整備してアプリケーション作っているため、C#のラッパーが無いライブラリはイマイチ使う気になれません。

特に私の場合はQUMARIONをCG用に使う気はそこまで無く、むしろ「センサーの値を一覧化して他プロセス/他のマシンへ送信したい」みたいな、C++で書くよりC#で書いといた方が気分の良さそうな用途でQUMARIONを使うつもりです(私がQUMARIONで具体的に何やろうとしてるのかについては別途紹介予定です)。なのでC#用のラッパーが欲しいなあと。でも軽くググった限りではラッパーが無かった事と、APIのサイズが比較的こじんまりしてて独力でも十分捌けそうだったのとで「じゃあ作ろう!」と思い立ったのがきっかけです。

 

また世間的な需要についても触れておくと、C#C++ほどではありませんがCGに応用する余地のある言語です。より平たく言うと「SDKC#ラッパーくらいまで書いとけばUnity界隈の詳しい人がなんか良い感じに使ってくれるのではないか」と。そういうわけで作ってみました。

 

 

QUMARION SDKの構成について

QUMARION SDKは大きく2つのライブラリに分かれていて、具体的な名前で言うと"QmLow"と"QmPdk"というのが別々に存在します。

前者のQmLowは名前の通り低レイヤーAPIで、QUMARIONの各関節に入ってる角度センサーの値や胴体部に存在する加速度計の読みを得たりするのに使うことが可能です。

いっぽう後者のQmPdkは高水準APIで、コチラはモデルの操作とかいかにもCGらしい操作を行うためのセットになっています。QUMARIONのボーンと任意の人型ボーン間でのマッピング処理関数などが定義されているらしいです。

 

それで…CG/ゲーム開発/VR系の方に期待されすぎるとアレなので先にバラしておきますが、本記事の段階で公開するラッパーはQmLow側の分だけです。なぜかというとQmLow APIの方がAPIが小さくてラッパー作成の難易度が低く、開発の取っ掛かりに適していたからです。あと個人的な用途としてはQmLow APIから拾える角度値データでも十分使用に堪えるかな、と思ったというのもあります。

 

 

QUMARIONのボーン/センサ構成

QmLow APIでは生のセンサー値を拾いに行くのでボーンやセンサーの具体的な構成をよく知っておく必要があります。

ラッパーの方にも一応書いてますが、QUMARIONのデバイス構成は大まかには下記のようになっています。"S1", "S2", "S3"とか書かれているのは角度値センサー(APIでの名前割り当ては特にない)で、それ以外の"Root"や"L_Thigh"といった名前はボーンの名称です。

Root
├Waist_V┬S1
│       ├S2
│       ├L_Thigh┬S1
│       │       ├S2
│       │       ├S3
│       │       └L_Leg┬S1
│       │              └L_Foot┬S1
│       │                      ├S2
│       │                      └L_Toe
│       └R_Thigh┬S1
│                ├S2
│                ├S3
│                └R_Leg┬S1
│                       └R_Foot┬S1
│                               ├S2
│                               └R_Toe
└Waist_V┬S1
         ├S2
         └Chest ┬ Neck ┬S1
                │      ├S2
                │      └ Head ┬S1
                │              └S2
                │
                ├L_Shoulder┬S1
                │          ├S2
                │          ├S3
                │          └L_Elbow┬S1
                │                   └L_Hand┬S1
                │                          └S2
                └R_Shoulder┬S1
                            ├S2
                            ├S3
                            └R_Elbow┬S1
                                     └R_Hand┬S1
                                            └S2

ボーンについては基本的に普通のヒューマノイドボーンです。センサーの名前は上では省略してますが、QUMARIONの可動部とセンサーは1対1に対応してるので、触ってればどれがどれだかすぐ分かるようになると思います。

また上記には載せてませんが胴体に加速度センサがあり、背面にはボタンがついてます。これらのデバイスにもQmLow APIからアクセス可能です。

 

 

ラッパーのソース公開先(GitHub)とサンプルコード

GitHubにVS2015用のソリューションを公開しています。構成は以下の通り。

  • QumarionDotNet: ラッパー本体
  • ConsoleSample: 最小限のコードによるラッパーの使用サンプル
  • QumarionDataViewer: 角度センサーとボタンをモニタリングするGUIサンプル
  • TestQumarionDotNet: (非常に適当な)テストコード

 

利用時の注意ですがダウンロードして即実行は出来ません。というのも現状ではライセンス周りのドキュメントが揃ってないので、実行時に必要なライブラリファイルである"QmPdkDll.dll"を同梱していないからです。利用時には以下の手順に従ってください。

※「下記の手順であれば二次利用者が必ずSDKの規約に同意する事になるので規約上の問題は解決してるだろう」という算段でこのような処置を取っています。ご理解下さい。

 

  1. QUMARION SDKのページで規約に同意してSDKをダウンロードする
  2. GitHubから落としたソリューションをVS2015で開く
  3. SDKのフォルダ中に"lib/release/x86/QmPdkDll.dll"というファイルがあるので、ソリューション中の"QumarionDotNet"プロジェクト以下"dll/relase/x86"フォルダへドラッグ&ドロップ
  4. 同様に"lib/release/x86/QmPdkDll.dll"を"QumarionDotNet"プロジェクト以下"dll/relase/x64"フォルダへドラッグ&ドロップ
  5. ソリューションエクスプローラでソリューションのプロパティを開き「シングルスタートアッププロジェクト」のターゲットを"ConsoleSample"(CUIサンプル)か"QumarionDataViewer"(GUIサンプル)に設定
  6. 実機のQUMARIONをUSBでPCに接続する
  7. ビルド構成をx86かx64にしてビルド実行

 

 

コンソールアプリケーションのサンプルコードはGitHub中にもありますがこんな感じです。

using System;
using System.Threading;

using Baku.Quma.Low;

namespace ConsoleSample
{
    class LowSample
    {
        //Low APIを使ったサンプルコードです。
        public static void LowSampleMain()
        {
            bool hardwareExists = QumarionManager.CheckConnectionToHardware();
            if(hardwareExists)
            {
                Console.WriteLine("Found Qumarion hardware.");
            }
            else
            {
                Console.WriteLine("Could not find Qumarion hardware: simulator will be used.");
            }

            //GetDefaultDevice関数では実機のQumarionがある場合それを、ない場合シミュレータをロードする
            var device = QumarionManager.GetDefaultDevice();
            //注意: デバイスの仕様でロード後ある程度待たないとアップデート処理が通らない
            Thread.Sleep(1000);

            for(int i = 0;i < 10; i++)
            {
                Console.WriteLine("press ENTER to check Head Yaw angle..");
                Console.ReadLine();

                //センサーのデータ更新
                device.Update();
                float angle = device.Sensors[Sensors.Head_Y].Angle;
                Console.WriteLine("Head Yaw(deg): {0}", angle);
            }

            QumarionManager.Exit();
        }
    }
}

 

ラッパーを使う流れは以下の通りです。

  1.  "QumarionDotNet.dll"を参照に追加
  2. 名前空間Baku.Qumaをusingで指定
  3.  (他のソリューションで使う場合)ConsoleSampleプロジェクトの出力ディレクトリを参考に、"dll/release/(x86|x64)/QmPdkDll.dll"の入ってるフォルダを実行ディレクトリに配置
  4.  QumarionManager.GetDefaultDevice関数を使って実機かシミュレータを取得
  5.  Update関数でセンサやボタンの情報を更新
  6.  SensorsプロパティやBonesプロパティからセンサー、ボーンなどのデータにアクセスして必要なデータを読み取る

なお上記サンプルにもチョロっと書いてますが、このラッパーでは角度を度数法で表しています。

 

またラッパー中で定義されてるセンサーと実際のQUMARIONのセンサーの対応についてはGUIサンプルである"QumarionDataViewer"で以下のようにして確認できます。

  1.  メニューバーの「デバイス->接続」から「実機」と書かれているやつをクリック
  2.  接続に成功するとメインGUIの真ん中にセンサ名と最新の角度値がズラッと表示される
  3.  数字ではなく時系列グラフデータとして角度値を眺めたい場合は「グラフを表示」を選ぶと右側に表示される。同時にたくさんのグラフを表示すると処理が重くなるので注意

 

GUIサンプルはうまく動くとこんな感じになります。

quma_wrapper_gui

 

 

ラッパーの実装について

ソース公開してるのに中身の解説が必要なのかは疑問ですが一つだけ、DllImport周りで私が今回新しく知った知識をメモ程度に書いておきます。QumarionDotNetの中でC/C++用のライブラリである"QmPdkDll.dll"を直接ラップしているソースファイルはLow/LowApi/LowApi.csです(2015/12/21追記: Pdk側のAPIをラップしたソースをPdk/PdkApi/PdkApi.csに追加しました)。このソースとQUMARION SDKのincludeフォルダに入ってる"QmLowDll.h"を見比べると分かるのですが、ライブラリの各関数の名前は本来のQUMARION SDKでヘッダファイルに載っているやつと違う(いわゆるマングリング)ので、ヘッダファイル側の名前を書いてもDllImportでは使えません。

この問題を解決するにはVisual Studioの付属ソフトであるdumpbin.exeというソフトで実際のQmPdkDll.dllを覗き、関数名を修正してDllImportのEntryPoint属性に挿し込めばOKです。たとえばSDKのライブラリバージョン文字列を取得するGetVersion関数は次のように拾ってきています(GitHubのこの辺から引用)。

#if !T_X64
    [DllImport(DllName, CallingConvention = CallingConvention.Cdecl, EntryPoint = @"?QmLowGetVersion@@YAXPA_W@Z")]
#else
    [DllImport(DllName, CallingConvention = CallingConvention.Cdecl, EntryPoint = @"?QmLowGetVersion@@YAXPEA_W@Z")]
#endif
    private static extern void GetVersion([MarshalAs(UnmanagedType.LPWStr, SizeConst = ApiConstants.API_VERSION_STR_MAX_LENGTH)]StringBuilder res);

T_X64というのは私が勝手に定義しているシンボルで、ターゲットアーキテクチャがx64の場合とx86の場合で関数名が異なるのに対応するために用いています。このほか、dumpbin.exeで調べた関数名一覧についてはここのディレクトリに一通り記載しています。

 

 

Unityでの再利用について

現時点ではコンソールアプリケーションとWPFでの利用を検証しただけなのでUnityで使えるかどうかは未チェックです。私が知る限りUnityでQumarionDotNetを使う場合は最低でもDllImportのファイルパス修正が必要なハズなので、LowAPI.csを編集(2015/12/21追記: PdkApi.csも修正が必要です)したうえでソースとDLLを丸ごと突っ込んで検証を行ってください。

 

 

まとめ

繰り返しになりますが、現状ではQUMARION SDKの大きく2種類に分かれたAPIのうちQmLowという低レイヤー側についてラッパーを作って公開するところまでを紹介しました。

正直QmPdk側のラッパーは私が使うかどうか不明なので製作モチベが高くないのですが、GitHubのソースの中にはQmPdkをラップする際に参考になるようなモノ(dumpbinの結果とか)も意識的に仕込んでいるので、ラッパーを作りたい人がいたらぜひ頑張ってください。また確約はしませんが「QmPdk側のラッパー実装が喉から手が出るほど欲しいです」とかいう人が居たらいちおう考慮はするので、その際はTwitterとかメールでお声かけください。