PhotonRigidbodyView using local space
Options
Has anyone adapted PhotonRigidbodyView to transmit and receive velocities in local space coords?
This may seem like a strange request at first but I'm creating a mixed-reality experience in which I physically align people's virtual environments (and everything in them). The only way for me to do this is to translate a 'rootspace' parent on each player which contains the environment (due to my setup, moving the player's POV won't help). For transforms, I saw that PhotonTransformViewClassic operates in local space and this has been very effective. But for rigidbodies, moving the parent transform on players who don't own the rigidbody causes very glitchy effects (wobbling crazy motion).
If no-one's done this before, my plan was to go through PhotonRigidbodyView and adjust all transmitted velocities to be relative to a parent (if present), then velocity back to world space based on any parent present when received before applying. Does that sound like the right approach?
This may seem like a strange request at first but I'm creating a mixed-reality experience in which I physically align people's virtual environments (and everything in them). The only way for me to do this is to translate a 'rootspace' parent on each player which contains the environment (due to my setup, moving the player's POV won't help). For transforms, I saw that PhotonTransformViewClassic operates in local space and this has been very effective. But for rigidbodies, moving the parent transform on players who don't own the rigidbody causes very glitchy effects (wobbling crazy motion).
If no-one's done this before, my plan was to go through PhotonRigidbodyView and adjust all transmitted velocities to be relative to a parent (if present), then velocity back to world space based on any parent present when received before applying. Does that sound like the right approach?
0
Comments
-
You could easily copy n pase the code from PhotonRigidbodyView.cs and rewrite it to fit ur needs. It is pretty simple code. So yes go through it.0
-
Thanks, I'll do that. If anyone needs this in the future:
namespace Photon.Pun { using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif /// <summary> /// transmits and applies rigidbody velocities in local space /// </summary> [RequireComponent(typeof(PhotonView))] [RequireComponent(typeof(Rigidbody))] [AddComponentMenu("Photon Networking/Photon Rigidbody View")] public class PhotonLocalRigidbodyView : MonoBehaviour, IPunObservable { private float m_Distance; private float m_Angle; private Rigidbody m_Body; private PhotonView m_PhotonView; private Vector3 m_NetworkPosition; private Quaternion m_NetworkRotation; public bool m_SynchronizeVelocity = true; public bool m_SynchronizeAngularVelocity = false; public bool m_TeleportEnabled = false; public float m_TeleportIfDistanceGreaterThan = 3.0f; public void Awake() { this.m_Body = GetComponent<Rigidbody>(); this.m_PhotonView = GetComponent<PhotonView>(); this.m_NetworkPosition = new Vector3(); this.m_NetworkRotation = new Quaternion(); } public void FixedUpdate() { if (!this.m_PhotonView.IsMine) { // convert m_NetworkPosition to world this.m_Body.position = Vector3.MoveTowards(this.m_Body.position, ToWorldPos(this.m_NetworkPosition), this.m_Distance * (1.0f / PhotonNetwork.SerializationRate)); // this.m_Body.position = Vector3.MoveTowards(this.m_Body.position, this.m_NetworkPosition, this.m_Distance * (1.0f / PhotonNetwork.SerializationRate)); // convert m_NetworkRotation to world this.m_Body.rotation = Quaternion.RotateTowards(this.m_Body.rotation, ToWorldRot(this.m_NetworkRotation), this.m_Angle * (1.0f / PhotonNetwork.SerializationRate)); // this.m_Body.rotation = Quaternion.RotateTowards(this.m_Body.rotation, this.m_NetworkRotation, this.m_Angle * (1.0f / PhotonNetwork.SerializationRate)); } } public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) { if (stream.IsWriting) { // change to local position stream.SendNext(this.m_Body.GetLocalPosition()); //stream.SendNext(this.m_Body.position); // change to local rotation stream.SendNext(this.m_Body.GetLocalRotation()); // stream.SendNext(this.m_Body.rotation); if (this.m_SynchronizeVelocity) { // convert to local stream.SendNext(this.m_Body.GetLocalVelocity()); // stream.SendNext(this.m_Body.velocity); } if (this.m_SynchronizeAngularVelocity) { // convert to local stream.SendNext(this.m_Body.GetLocalAngularVelocity()); // stream.SendNext(this.m_Body.angularVelocity); } } else { this.m_NetworkPosition = (Vector3) stream.ReceiveNext(); this.m_NetworkRotation = (Quaternion) stream.ReceiveNext(); if (this.m_TeleportEnabled) { // convert position to local for distance check (or m_NetworkPosition to world) if (Vector3.Distance(this.m_Body.GetLocalPosition(), this.m_NetworkPosition) > this.m_TeleportIfDistanceGreaterThan) // if (Vector3.Distance(this.m_Body.position, this.m_NetworkPosition) > this.m_TeleportIfDistanceGreaterThan) { // convert m_NetworkPosition to world this.m_Body.position = ToWorldPos(this.m_NetworkPosition); // this.m_Body.position = this.m_NetworkPosition; } } if (this.m_SynchronizeVelocity || this.m_SynchronizeAngularVelocity) { float lag = Mathf.Abs((float) (PhotonNetwork.Time - info.SentServerTime)); if (this.m_SynchronizeVelocity) { // convert stream to world this.m_Body.velocity = ToWorldVelocity((Vector3) stream.ReceiveNext()); // this.m_Body.velocity = (Vector3)stream.ReceiveNext(); // convert velocity to local this.m_NetworkPosition += this.m_Body.GetLocalVelocity() * lag; // this.m_NetworkPosition += this.m_Body.velocity * lag; // convert position to local this.m_Distance = Vector3.Distance(this.m_Body.GetLocalPosition(), this.m_NetworkPosition); // this.m_Distance = Vector3.Distance(this.m_Body.position, this.m_NetworkPosition); } if (this.m_SynchronizeAngularVelocity) { // convert stream to world this.m_Body.angularVelocity = ToWorldAngularVelocity((Vector3) stream.ReceiveNext()); // this.m_Body.angularVelocity = (Vector3)stream.ReceiveNext(); // convert angularVelocity to local this.m_NetworkRotation = Quaternion.Euler(this.m_Body.GetLocalAngularVelocity() * lag) * this.m_NetworkRotation; // this.m_NetworkRotation = Quaternion.Euler(this.m_Body.angularVelocity * lag) * this.m_NetworkRotation; // convert rotation to local this.m_Angle = Quaternion.Angle(this.m_Body.GetLocalRotation(), this.m_NetworkRotation); // this.m_Angle = Quaternion.Angle(this.m_Body.rotation, this.m_NetworkRotation); } } } } private Vector3 ToWorldPos(Vector3 localPosition) { return transform.parent.TransformPoint(localPosition); } private Quaternion ToWorldRot(Quaternion localRotation) { return transform.parent.rotation * localRotation; } private Vector3 ToWorldVelocity(Vector3 localVelocity) { return transform.parent.TransformVector(localVelocity); } private Vector3 ToWorldAngularVelocity(Vector3 localAngularScale) { return transform.parent.InverseTransformDirection(localAngularScale); } } /// <summary> /// extension methods to rigidbody to get local versions of stuff (pass in transform parent as param) /// </summary> public static class RigidBodyExtensions { public static Vector3 GetLocalPosition(this Rigidbody rb) { return rb.transform.localPosition; } public static Quaternion GetLocalRotation(this Rigidbody rb) { return rb.transform.localRotation; } public static Vector3 GetLocalVelocity(this Rigidbody rb) { // trying InverseTransformVector as I think we don't want to factor in position, only direction and scale? return rb.transform.parent.InverseTransformVector(rb.velocity); } public static Vector3 GetLocalAngularVelocity(this Rigidbody rb) { // trying InverseTransformDirection as we only want direction not affected by scale or position? return rb.transform.parent.InverseTransformDirection(rb.velocity); } } /// <summary> /// Custom editor duplicated from original /// </summary> #if UNITY_EDITOR [CustomEditor(typeof(PhotonLocalRigidbodyView))] public class PhotonLocalRigidbodyViewEditor : Editor { public override void OnInspectorGUI() { if (Application.isPlaying) { EditorGUILayout.HelpBox("Editing is disabled in play mode.", MessageType.Info); return; } PhotonLocalRigidbodyView view = (PhotonLocalRigidbodyView) target; view.m_TeleportEnabled = PhotonGUI.ContainerHeaderToggle("Enable teleport for large distances", view.m_TeleportEnabled); if (view.m_TeleportEnabled) { Rect rect = PhotonGUI.ContainerBody(20.0f); view.m_TeleportIfDistanceGreaterThan = EditorGUI.FloatField(rect, "Teleport if distance greater than", view.m_TeleportIfDistanceGreaterThan); } view.m_SynchronizeVelocity = PhotonGUI.ContainerHeaderToggle("Synchronize Velocity", view.m_SynchronizeVelocity); view.m_SynchronizeAngularVelocity = PhotonGUI.ContainerHeaderToggle("Synchronize Angular Velocity", view.m_SynchronizeAngularVelocity); if (GUI.changed) { EditorUtility.SetDirty(view); } } } #endif }
1