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

背景
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を解除できるようになります。

Disable IK on PickupとしてUdonSharpを作成。
OnPickupイベントを使って実装しました。
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に戻ってしまいました。
オブジェクトはずっと空中に浮いたままとなってしまいました。

そこで試しにイベントをOnPickupからOnDropイベントに変更してみたところ、UnityでもVRChat上でも正しく動作しました。理由は分かりません...教えてうどん職人の方...。
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で落下させるという動作ができるようになりました。なぜかは本当に分かりません。

有力な情報をお教えいただきました!

本来やりたかったPickup時にIKをOFFにするようにコードに修正を加えて...
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);
}
}
最終的なインスペクターはこんな感じ

できた!!!

総括
公式ドキュメントを見落としていたのが災いして、ハマってしまいました(n敗)
Don't forget to read the official reference!!
OnDropで動作したように見えていたのはおそらくVRChatの仕様的なところだったんじゃないかなと思います(震え声)
この問題の解決に導いてくださったのりたま@VRC🍥(noritama_vrc)様に謝意を表明させていただき、こちらのスクラップをクローズしたいと思います。
大変にありがとうございました!