Closed7

[UdonSharp]OnPickupイベントでRigidBodyのIKを解除しようとしたらハマった話

kesera2kesera2

背景

RigidBodyコンポーネントのUse Gravityが有効なオブジェクトに対して、プレイヤーが持ち始めるまでIKを有効にしておきたいユースケースがあり、Udonを使って変更しようとしたらちょっとハマったのでメモします。状況としては、プレイヤーが持つまでは空中に浮かせておきたい感じですね。Unity上ではうまく動作するのに、VRChatだと動かない現象が発生していました。

環境

VRChat SDK - Base, World 3.7.5

TL;DR

RigidBodyのIKを変更したいときは、イベントとしてOnPickupじゃなくてOnDropを使うとうまくいきました。
VRC Object Syncを使ってTransformとRotationの同期を制御しているときに、RigidBodyのIKを変更する場合、SetKinematic(bool value)経由で操作するとIKを解除できるようになります。

kesera2kesera2

Disable IK on PickupとしてUdonSharpを作成。

OnPickupイベントを使って実装しました。

DisableIKOnPickup.cs
using UdonSharp;
using UnityEngine;

public class DisableIKOnPickup : UdonSharpBehaviour
{
    public override void OnPickup()
    {
        // ピックアップされたオブジェクトのRigidBodyを取得
        var rigidBody = GetComponent<Rigidbody>();
        Debug.Log("DisableIKOnPickup has called. rigidBody.isKinematic is " + rigidBody.isKinematic); // True

        // IKを無効化
        rigidBody.isKinematic = false;
        Debug.Log("rigidBody.isKinematic is " + rigidBody.isKinematic); // False
    }
}

Unity上ではPickupした後オブジェクトがGravityによって落下し、持ち直しても正しく動作しました。rigidBody.isKinematicは初回のTrueが変更された後ずっとFalseになっています。

そこでVRChatでテストしてみると、何度PickupしてもなぜかrigidBody.isKinematicがFalseに書き換えた後にTrueに戻ってしまいました。

オブジェクトはずっと空中に浮いたままとなってしまいました。

kesera2kesera2

そこで試しにイベントをOnPickupからOnDropイベントに変更してみたところ、UnityでもVRChat上でも正しく動作しました。理由は分かりません...教えてうどん職人の方...。

DisableIKOnDrop.cs
using UdonSharp;
using UnityEngine;

public class DisableIKOnDrop : UdonSharpBehaviour
{
    public override void OnDrop()
    {
        // ピックアップされたオブジェクトのRigidBodyを取得
        var rigidBody = GetComponent<Rigidbody>();
        Debug.Log("OnDrop has called. rigidBody.isKinematic is " + rigidBody.isKinematic);

        // IKを無効化
        rigidBody.isKinematic = false;
        Debug.Log("rigidBody.isKinematic is " + rigidBody.isKinematic);
    }
}

Unityのコンソールログ

VRChatのログ

VRChatのログとUnityのログが異なるのが気になりますが、OnDropだと今回のユースケースである持ち上げたときにIKを無効化してGravityで落下させるという動作ができるようになりました。なぜかは本当に分かりません。

kesera2kesera2

本来やりたかったPickup時にIKをOFFにするようにコードに修正を加えて...

DisableIKOnPickup.cs
using UdonSharp;
using VRC.SDK3.Components;

public class DisableIKOnPickup : UdonSharpBehaviour
{
    private VRCObjectSync objectSync;

    private void Start()
    {
        objectSync = GetComponent<VRCObjectSync>();
    }

    public override void OnPickup()
    {
        objectSync.SetKinematic(false);
    }
}

最終的なインスペクターはこんな感じ

kesera2kesera2

総括

公式ドキュメントを見落としていたのが災いして、ハマってしまいました(n敗)

Don't forget to read the official reference!!

OnDropで動作したように見えていたのはおそらくVRChatの仕様的なところだったんじゃないかなと思います(震え声)

この問題の解決に導いてくださったのりたま@VRC🍥(noritama_vrc)様に謝意を表明させていただき、こちらのスクラップをクローズしたいと思います。

大変にありがとうございました!

このスクラップは2025/01/08にクローズされました