UnityでLeap Motionが認識した手を動かす
UnityでLeap Motionのビジュアライザーのように認識した手を動かしてみました。手は以下のオブジェクトで表現しました。
Leap MotionのSDKのバージョンはもちろんv2 Betaです。Unity側スクリプト言語はC#を使いました。ソース一式はgithubにあげてあります。
以下ハマった点
1つめ
正規化した座標をUnityのオブジェクトに適応させるときにlocalPositionに代入していましたが、それだと間接の座標だけ他と位置が離れてしまって、パーツの配置に違和感が生じていました。positionに代入しないといけませんでした。
unityWrist.transform.position = utils.getScaledUnityPosition(hand.WristPosition, interactionBox);
utils.getScaledUnityPositionは自作dllの関数です。
2つめ
手首のCubuオブジェクトの回転は直近フレームを保存して、RotationAngleでxyzの軸別に差分角度を取得してtransform.Rotateで動かす方法をとっています。
Unityでオブジェクトを回転させる時はtransform.rotationで絶対値を代入するとか、Quaternion.Slerpを使うとかいくつか方法があるようですが、Leap MotionSDKのAPIと相性がいい方法をチョイスしました。
Hand.RotationAngleで直近フレームとの差分の角度を取得するんですが、こいつがラジアン角で、Unityのtransform.Rotateで回転させるためにはオイラー角である必要があります。
なのでラジアンをオイラーに変換する必要があったんですが、そこに気づくのに半日かかりました。
float angleX = hand.RotationAngle(basisFrame, basis.xBasis); float angleY = hand.RotationAngle(basisFrame, basis.yBasis); float angleZ = hand.RotationAngle(basisFrame, basis.zBasis); // 回転する unityWrist.transform.Rotate(new Vector3( LMUtils.rot2Dir(angleX), LMUtils.rot2Dir(angleY), -1 * (LMUtils.rot2Dir(angleZ))));
LMUtils.rot2Dirは自作dllの関数です。z方向に-1をかけているのは認識した手の向きを変えるためです(positionも反転させています)。
動作中のスクリーンをキャプチャしました。Line RendererがPalmのSphereを貫通してますがそこは気にせず。(Leap Motionのビジュアライザーだと第3間接のSphereを横につなげて見た目を整えてますが、、)。
両手対応してます。ソースは1つにしたかったので、Unityのオブジェクトにタグをふっておいて、スクリプト側ではHandListでforeachしてタグとisLeftやisRightの結果を比較して描画し分けています。
Line Rendererで骨を表現するとlengthを気にしなくていいので楽です。あと親指は他の指より間接が一つ少ない(というかlengthが0の骨がある)ことを考慮する必要あります。
ベースはできたのでこれからUnityとLeap Motionを遊び尽くす。