FinalIK(VRIK)でワープ移動時に足が伸びてしまう問題の解消方法


環境

開発環境

  • Unity5.5
    • 5.6にはRectTransformとCanvasのバグがあったので使ってないです
  • OculusRift
  • PhotonNetwork

Asset

やりたかったこと

  • Unity-chanをOculusRiftで手と頭のトラッキングをして、コントローラーでワープ移動(VRでよくある移動先をコントローラーで指し示して一瞬で移動する方法)できるようにする
  • またアナログスティックで前後移動と左右の回転もできるようにする
  • トラッキングはOVRCameraRigをつかって問題なく動作できた
  • Unity-chanにはFinalIKのVRIK、PhotonViewとPhotonTransfromViewのコンポーネントをアタッチしてPhotonViewでPhotonTransformViewをObservedComponentsに入れていた
  • それをネットワーク上で同期させたい

問題

現象

  • Unity-chanをA地点からB地点にワープさせるとA地点に足が地面にくっついたままびよーんと伸びてしまう

解決方法

足が伸びてしまう問題の解消

  • リファレンスに載ってないのでVRIKのスクリプトから処理を追っていくと、IKSolverVR にReset関数が用意されており以下のようにコメントされていたのでこれを使うことで解消した

Resets all tweens, blendings and lerps. Call this after you have teleported the character.

  • ローカルでは移動処理後に Reset() を呼び出すと自然な動きになった

ネットワーク上で互いに移動すると足が伸びてしまう問題の解消

  • はじめは自身のワープ処理後にRPC経由で Reset() を呼び出したが、同期がうまくあわないのか(?)うまくいかなかった
  • PhotonTransformView を使うのをやめて、PhotonViewOnPhotonSerializeViewTransform を同期し、Updateの !PhotonView.isMine の中で同期を行うように変更し、その中で移動距離に応じて、アナログスティック移動とワープ移動を理由、ワープ移動内でのみReset処理を呼び出した
    void Update() {
        if (photonView.isMine) {
          // do anything
        } else {
            float distance = Vector3.Distance(transform.position, currentPosition);
            if(distance > 1.0f) {
                transform.position = currentPosition;
                VRIK ik = GetComponentInChildren<VRIK>();
                if (ik != null) {
                    ik.solver.Reset();
                }
            } else {
                transform.position = Vector3.Lerp(transform.position, currentPosition, Time.deltaTime * 5);
            }            
            transform.rotation = Quaternion.Lerp(transform.rotation, currentRotation, Time.deltaTime * 5);
        }
    }

    void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
        if (stream.isWriting) {
            stream.SendNext(transform.position);
            stream.SendNext(transform.rotation);
        } else {
            currentPosition = (Vector3)stream.ReceiveNext();
            currentRotation = (Quaternion)stream.ReceiveNext();
        }
    }
  • ちなみにMonoBehaviorのUpdateの中で Reset() 呼んだらどうなるか試してみましたが、足とかが常に軸回転してしまうのでやめたほうがいいです

うまい方法がほかにあればご教授いただけるとうれしいです