トマシープが学ぶ

Unity/VR/AR/デザイン好きのミーハー 記事内容は自分用のメモです

QuestのOVRBodyのFullBodyのサンプル触る&自分のキャラへ適用【Unity】【IOBT+Generative Legs】

IOBTとGenerative Legs

IOBTというやつでQuest3では全身トラッキングができる!と思ったけどちょっと違った。

IOBT自体は上半身を精密にトラッキングするというもの。

脚の部分は

AI 生成の脚は、Meta が「Generative Legs」と呼んでおり、より現実的なアバターの脚を可能にします。

IOBT とは異なり、ユーザーの脚の位置は Quest の内蔵センサーによって追跡されません。IOBT の追跡データをより正確に機能させる AI モデルによって推定されます。ただし、ジェネレーティブ レッグは IOBT なしでも機能し、古いQuest 2およびQuest Proヘッドセットによってサポートされます (精度は低くなります)。

mixed-news.com

だって。QuestProとか2でもFullBodyのトラッキングができるということ!

でもQuest3のほうが足も精度は高くなるらしい

 

あと開発者向けの記事にいろいろ注意点が書いてあった

Generative Legs の場合、ボディ トラッキングの開始時に、ヘッドセットから床までのおおよその高さが測定されます。各セッションは、ユーザーが立った状態で開始する必要があります。ボディスケールが正しく見えない場合は、Oculus ボタンを 2 回押してキャリブレーションをリセットします。また、このキャリブレーションのためにガーディアンを初期化する必要があることにも注意してください。座っているユーザーの場合、ユーザーは手を伸ばして円を描くように移動し、翼幅を使用して身長を推定できます。あるいは、新しいキャリブレーション API を使用して高さを明示的に設定することもできます。

https://developer.oculus.com/documentation/unity/move-body-tracking/

 

酔い改善に貢献するらしい

 

Dodge Arcade 

上の記事に載っていたDodge ArcadeというMetaが出しているアプリで体験できるって

https://www.meta.com/ja-jp/experiences/6511679575602893/

やってみたがかなり楽しい。小さい自分を後ろから見る

飛んでくるドッチボールはよけてサッカーボールは取るというゲームで、なんかツイスターとかポーズをとって迫り来る壁を抜けるゲームみたい

prtimes.jp

上半身は遠くのボールを取りつつ、足はよけるみたいなシーンもあってちゃんと反映されてた気がする

PVより

MovementLocomotionサンプル

環境

・Quest3

・Unity2022.3.7

・MetaXRSDKv60

 

ちょっと特殊な場所にあるMovementSDK内のMovementLocomotionというサンプルで全身を動かすのを体験できる

bibinbaleo.hatenablog.com

IBOTにするかどうかも選べる。

動かしても違いが分からなくて、ボタンがどっちの状態だとIOBTなのかもわからなかった。

youtu.be

他のUIの法則性やインスペクタを見た限りIBOTと表示されているときにIOBTになっているようだ。

CurrentFidelityがHighがIOBTっぽい

自分のキャラへの適用

これをVRMキャラに適用したい。

これができればFinalIKいらないかな~?

Twitterでやっている人いるけど記事なさそう・・・

 

サンプルシーン経由(無理)

サンプルシーンを参考に一つ一つコンポーネントつけていくか~

とりあえずサンプルシーンのアバターをプレハブ化して自分のシーンに持ってきたらちゃんと動いた

いろいろついてるんだよな~

VRMアバターに全部つけてみたけどRigBuilderとかもろもろよくわからない。当然ピクリともしなかった

ドキュメント見ながら

日本語のドキュメントを見てたけど、

Unity向けMovement SDKのボディトラッキング: Unity | Oculus開発者

同じページの英語版を見たらめっちゃ細かくセットアップの仕方を書いてた!!

https://developer.oculus.com/documentation/unity/move-body-tracking/

(※ログインしないと詳しい内容のページにたどり着けない?ログアウトしている状態だとURLは同じなのに内容が日本語版ページ版になってた)

 

Modelのfbxデータとかがある場合は、Humanoidにしたり、「マッスルと設定」で、設定の一番下にあるTranslation DOFがチェックされていることを確認する。

VRMのデータだと見れないので、チェック入ってることを願う

Mixamoでインポートしたモデルだとチェック入ってなかった・・・

あと初めて知ったが、Modelのところで大きさを変更できる!モデルをシーンで大きさを変えると不具合が出るのはよく知られているし、ドキュメントにもそう書いてあったので、程よい大きさにするにはここで調整

そしてモデルデータを右クリックしてMovement Samples > Body Tracking > Animation Rigging Retargeting (full body) (constraints)

すると必要なコンポーネントが一気についた!

Rigもいい感じに入ってる!

OVRManagerではIOBT(BodyTrackingFidelityをHigh)とFullBodyを設定

なんとこれだけで動いた!!!

すごいことにはなっているけど!

 

指は完ぺきに動いた!すごい!

これしなくてもOVRBodyの機能で動くんだ!

bibinbaleo.hatenablog.com

FullBodyHandDeformationのおかげかな?

調整(分からない・・・)

この感じは、MovementSDKのサンプルでもあった。

MovementRetargeting

あれはちゃんと設定しないとこうなるよっていうサンプルだったのかな~

で、調整しようとドキュメント後半を読んだけどよくわからない・・・Weightを調整するっぽいが・・・

RigのDeformationConstraintについて書いてはありそう

あとモデルの一番上についているRetargetingLayerのWeight

ここら辺変えたけどうまくいかない。ウエイトを0にしたら動かない代わりに破綻しないとかはあったけど

 

VRMモデルのせいかと思ったが、Mixamoのモデルでも変わらない。

腕だけが目立ちがちだが、上半身の胴体が回転しないとかもある。

youtu.be

手の位置はあっているけど、それ以外があっていないのか・・・

ボーンビジュアライズ

ボーンのビジュアライズはできた。


DebugBonesとDebugBonesOVRSkeletonFullBodyというプレハブがあるのでそれを置いて、それぞれ設定

FullBodyのほう(白色)はOVRから来るボーンのが見える化される

DebugBone(黄色)は実際にAnimatorで動いているボーン?白いボーンはちゃんといい感じになっているのがわかる

具体的にどこのボーンのせいでぐちゃぐちゃになっているかがわかりやすい

 

Animator経由で送る(失敗)

うまくいっている青いサンプルアバターの動きをAnimator経由で送ったらどうなるか試した。

受け取るほうのアバターはOVRBodyとか何もつけていないVRMアバターの素の状態にした

ChatGPTに頼んだら動くもの作れた

public class AvatarMotionTransfer : MonoBehaviour
{
    public Animator sourceAnimator;
    public Animator targetAnimator;

    void LateUpdate()
    {
        CopyAvatarTransforms(sourceAnimator, targetAnimator);
    }

    void CopyAvatarTransforms(Animator source, Animator target)
    {
        foreach (HumanBodyBones bone in System.Enum.GetValues(typeof(HumanBodyBones)))
        {
            if (bone == HumanBodyBones.LastBone) continue;

            Transform sourceTransform = source.GetBoneTransform(bone);
            Transform targetTransform = target.GetBoneTransform(bone);

            if (sourceTransform != null && targetTransform != null)
            {
                targetTransform.localPosition = sourceTransform.localPosition;
                targetTransform.localRotation = sourceTransform.localRotation;
            }
        }
    }
}

そしたら動きは同期はされたけど、相変わらずVRMアバターは崩れたままだった;;

左がAnimator経由で動きを送った子。右の子のようにOVR経由だと指とかはうまくいってたのにそれも変になっている。


解決

HumanPoseHandlerを送るようにしたら反映された

using UnityEngine;

public class AvatarMotionTransfer : MonoBehaviour
{
    public Animator sourceAnimator;
    public Animator targetAnimator;
    private Avatar m_SourceAvatar;
    private Avatar m_TargetAvatar;
    public HumanPoseHandler m_SourcePoseHandler;
    public HumanPoseHandler m_TargetPoseHandler;
    private HumanPose m_SourcePose;
    private HumanPose m_TargetPose;
    public bool m_LerpEnabled = true;
    public bool m_FixedBodyPosition = false;
    public Vector3 BodyPositionCorrection = new Vector3(0.0f, 1f, 0.0f);

    void Awake()
    {

        if (sourceAnimator != null && sourceAnimator.avatar != null)
        {
            m_SourceAvatar = sourceAnimator.avatar;
            m_SourcePoseHandler = new HumanPoseHandler(m_SourceAvatar, sourceAnimator.transform);
            m_SourcePoseHandler.GetHumanPose(ref m_SourcePose);
        }

        if (targetAnimator != null && targetAnimator.avatar != null)
        {
            m_TargetAvatar = targetAnimator.avatar;
            m_TargetPoseHandler = new HumanPoseHandler(m_TargetAvatar, targetAnimator.transform);
            m_TargetPoseHandler.GetHumanPose(ref m_TargetPose);

        }
    }


    void LateUpdate()
    {
        CopyAvatarHumanPose(sourceAnimator, targetAnimator);
    }

    void CopyAvatarHumanPose(Animator source, Animator target)
    {
        if (m_SourcePoseHandler != null && m_TargetPoseHandler != null)
        {
            m_SourcePoseHandler.GetHumanPose(ref m_SourcePose);

            m_TargetPoseHandler.SetHumanPose(ref m_SourcePose);

        }
    }
}