Bakulog

獏の夢日記的な何か。

QUMARIONのUnity用ライブラリでQUMARIONの体の傾きを測る

QUMARION/Unity関連記事の年内ラストです。

 

前に公開したQumarionDotNetという、人型入力デバイスQUMARION」を.NETやUnityで使うためのライブラリがあります。ライブラリ紹介記事の時点で最低限のネタとサンプルは紹介し切っているのですが、細かい話題として姿勢情報を数字で拾う方法を紹介していなかったのでそれについて補足です。

これまでに書いた記事はコチラの二つです。

 

では本題。サンプルスクリプトにも載せていますが、基本的にQumarionDotNetでは次のような手順でデバイスの情報を拾います。

  1.  名前空間Baku.Quma.Pdkをusing文で宣言
  2.  ライブラリで定義された専用ボーンのモデルをロード
  3.  ハードウェアのQumarionをロード
  4.  モデルにQumarionを関連づけてポーズ情報が同期されるようにする
  5.  モデルのUpdate関数を呼び出して姿勢情報を更新しつつ何かする

サンプルスクリプトでは急に行列処理や行列/クオータニオン変換がドカドカ出てきて何が起きてるのか分かりにくい部分があると思いますが、基本処理はあくまで上に書いている流れに則っています。

 

今回はボーンの可視化とかヒューマノイドとの同期といった難しい目標ではなく、あくまで体全体つまりHip相当の箇所の姿勢情報を取得するのがゴールです。

 

ここでは具体例としてQUMARIONが左右/前後に傾くとアタッチされたオブジェクトが前後左右に動く、つまりQUMARIONをある種の操縦レバーのように使えるスクリプトを考えてみます。動きとしてはこういうの。

https://twitter.com/baku_dreameater/status/682202033227608064

この例では前後左右の移動に加えて手を照準に使うとかボタンを押すと浮上するといった機能もついてるのですが、まあそこは無視で。

 

スクリプトはこんな感じです。

using UnityEngine;
using System.Collections;
using Baku.Quma.Pdk;

public class MoveByQumarion : MonoBehaviour {

    private StandardCharacterModel _model;

    //左右方向の移動速度です。
    public float xSpeed = 3.0f;
    //前後方向の移動速度です。
    public float zSpeed = 3.0f;

    //左右方向について、移動の傾き度合の閾値(0より大きく1以下)を指定します。
    //大きい値にするほど動きにくくなります。
    public float xTiltThreashold = 0.6f;

    //NOTE: Qumarionの仕様上前に傾けるより後ろに傾ける方がちょっと難しいので、
    //後ろ向きの閾値を小さくしておくといいかも
    //前方向について、移動の傾き度合の閾値(0より大きく1以下)を指定します。
    public float zTiltPositiveThreashold = 0.6f;
    //後ろ方向について、移動の傾き度合の閾値(0より大きく1以下)を指定します。
    public float zTiltNegativeThreashold = 0.6f;

    // Use this for initialization
    void Start ()
    {
        _model = PdkManager.CreateStandardModelPS();
        if(PdkManager.ConnectedDeviceCount > 0)
        {
            _model.AttachQumarion(PdkManager.GetDefaultQumarion());
            _model.AttachedQumarion.EnableAccelerometer = true;
            _model.AccelerometerMode = AccelerometerMode.Direct;
            _model.AccelerometerRestrictMode = AccelerometerRestrictMode.None;
        }
    }
    
    // Update is called once per frame
    void Update ()
    {
        if (_model == null) return;
        _model.Update();

        //加速度センサの結果を用いるためにルート(=Hips)ボーンの軸をちょっと見てみる
        var hipsWorldMatrix = _model.Root.WorldMatrix;

        //デバッグしたければ成分(のうち回転行列に相当する部分)を、実機のQUMARIONを傾けながら観察
        //Debug.Log(string.Format(
        //    "Hips Matrix = ([{0:0.000}, {1:0.000}, {2:0.000}], [{3:0.000}, {4:0.000}, {5:0.000}], [{6:0.000}, {7:0.000}, {8:0.000}], )",
        //    hipsWorldMatrix.M11, hipsWorldMatrix.M12, hipsWorldMatrix.M13,
        //    hipsWorldMatrix.M21, hipsWorldMatrix.M22, hipsWorldMatrix.M23,
        //    hipsWorldMatrix.M31, hipsWorldMatrix.M32, hipsWorldMatrix.M33
        //    ));

        float xDirect = hipsWorldMatrix.M11 > xTiltThreashold ? 1.0f :
                      hipsWorldMatrix.M11 < -xTiltThreashold ? -1.0f :
                      0.0f;

        float zDirect = -hipsWorldMatrix.M31 > zTiltPositiveThreashold ? 1.0f :
                      -hipsWorldMatrix.M31 < -zTiltNegativeThreashold ? -1.0f :
                      0.0f;

        var pos = transform.position;
        transform.position = new Vector3(
            pos.x + xDirect * xSpeed * Time.deltaTime,
            pos.y,
            pos.z + zDirect * zSpeed * Time.deltaTime
            );
    }

}

上の例ではボーンのルート要素であるHipsから姿勢行列を拾っています。これはUnityの4次正方行列型ではないのですが、成分を見る分にはそこまで困らないかと思います。

で、上の例によれば姿勢行列の成分のうちM11(左上)とM31(左下)の成分値がそれぞれ体の左右、前後の傾き具合に対応しているとして移動への入力に使っています。もちろん実際には行列成分は9個あるため(根本的な意味での自由度は3だか4だかしかありませんが)もっと洗練された方法でデータを拾うことも可能ですが、この程度でもそこそこうまく動きます。需要に応じてうまく使ってください。

短いですが今回は以上です。