Bone rotation not synchronising.

Hey guys,

Been using Photon for a while now, really excellent piece of kit. Perfect for what i need.

I'm making a top down online shooter. The player runs around and is able to animate, shoot and track score. My issue right now is that i cannot synchronise the rotation of a transform that is located within my player game object heirarchy. This transform is a bone that is attached to the a rig thats a part of the player. I have tried sending and receiving vector3 and quaternions through OnPhotonSerializeView, but it doesnt seem to update the rotation on the body. Ill be clear, in my actual code i make this rotation in the LateUpdate(), and i do this because the character is animated. Is this the issue? Can i not synchronise the bone rotation(and subsequent mesh rotation) on the transform because the skinnedMeshRenderer is using it in some way? I have tried attaching a photonview and just interpolating its values that way but it still doesnt work.

Any help is greatly appreciated.


  • Thanks for your kind words! Good to read you like it so far :)

    I would do any animation on the remote clients just based on "input" or "state". If you move forward locally, you trigger an animation for that and keep your state as "moving" or "running" or something. Then send this "moving" to the others and start animations based on that fake input.

    We do that in the Marco Polo Tutorial, afaik: ... marco-polo

    Animations could easily override the state of bones, etc. If you usually animate the bone in LateUpdate(), you should probably "cache" the latest received position for the bone and then apply it (bit by bit) in LateUpdate() as you do now.

    I hope that helps.
  • Hello Tobias,

    Thanks for the reply.

    I have indeed put the animations into states and play them locally as per the build in Marco Polo.
    Here is a code snipped of what i attempted in my network rigidbody class:
    PlayerCharacter PC = GetComponent<PlayerCharacter>();
                //Spine rotation send
                stream.Serialize(ref pos);
                stream.Serialize(ref velocity);
                stream.Serialize(ref rot);
                stream.Serialize(ref angularVelocity);
            // Read data from remote client
                Vector3 pos =;
                Vector3 velocity =;
                Quaternion rot = Quaternion.identity;
                Vector3 angularVelocity =;
                PlayerCharacter pc = GetComponent<PlayerCharacter>();
                pc._characterStates = (CharacterStates)stream.ReceiveNext();
                pc.weapon = (Weapons)stream.ReceiveNext();
                //Spine rotation receive
                pc.spine.rotation = (Quaternion)stream.ReceiveNext();

    And here is the code snipped that handles bone rotation in my player character class
    void LateUpdate() 
           {    if (JoyStickPos != new Vector2(0, 0))
               angle = Mathf.Atan2(-JoyStickPos.y, JoyStickPos.x) * Mathf.Rad2Deg;
               var rotx = spine.eulerAngles;
               rotx.y = angle;
               spine.eulerAngles = rotx;

    With this method what happens is, there is a rotation present, but it doesnt take the mesh with it..Could this be because ive got the animations in a state and im somehow not updating the code in LateUpdate ?

    I've tried using an [RPC] and i get the same results.
  • I have to admit: I don't really know what's going on in terms of animation/state, when to update things, etc..
    This is more a question about "how would i do this in Unity" than a networking issue. You might get better answers on the Unity forum if you re-phrase this as question about how to modify the bones when playing animations or so.
  • Ill be clear:
    I am already able to modify the bones and rotation during animation(as im doing the rotation in LateUpdate(). It works absolutely fine, LOCALLY.
    I just don't know how to synchronise this over a network. We share animations via sending integars to indicate the state the animation is in. With bones i am directly rotating them in a fixed axis, if i send the eulerangles vector3 or rotation quaternion, i still cant get it to work.
    Here is a thread i found with exact same problem, that may clear it up for you more:
  • If it works locally, you need to check which values you get from remote character and analyze why those values are not ok.
    PUN does not even touch animation by itself, so it's either something you disabled, that's skipped by a "isMine" condition or it's some value you don't apply or that is a "world" rotation instead of a "local" rotation value, etc.

    If nothing works, we definitely need a small repro project and a description what goes wrong. Otherwise, we can hardly help. Getting the code only is not enough in this case, I'd guess.
  • Edit: Problem Solved
    So here is what happened, i was synchronising the correct rotation values but was missing out the source of the rotation which was a joystick value; the input. I corrected this in my "void OnPhotonSerializeView() function. For anyone wondering.

    Thanks for all your help Tobias.
  • hey there! I'm having the same issues with bone Sync and Animations. It works perfectly well locally but sending the correct info to the Network Character is giving me a real headache! I didn't get to understand how you solved this. In my case I have a mecanim animator and a script atached to my camera. Then my player has it's own script where I make the sync. The source of the bone rotation comes from the camera script but of course the network player doesn't have that. So I make the player send the rotation of the bone from OnPhotonSerializeView() and I asign it over there to another variable wich I lerp in LateUpdate() I even tried making the same calculations I make in the camera script:

    Bone.rotation = camera.transform.rotation * bone.rotation

    All I get is a trembling movement, sort of blinking to the right position but keeps mixing up with the Animations. By the way... I'm completly sure the issue is there because when I disable the animator of my network character the bone syncs just fine... I think it would help me a lot if you could share a little more details on how you solved this issue DarthGarth I would really apreatiate it. Thanks a lot in advance!

  • OK after hours and hours of hard work I managed to make the bone move... It was indeed a problem in the execution order of the animation and the rotation. What I have is the character from Unity's angry bots demo animated through mecanim instead of Legacy as it was. I made my own third person shooter controller and Camera orbit with up and down aiming. It works great locally and everything syncs perfectly in the network but the up/down aiming bone. It would be awful to see a guy shooting at your thorax and receiving a headshot.

    This is how my sync looks like


    transform.position = Vector3.Lerp(transform.position, this.correctPlayerPos, Time.deltaTime * 5);
    transform.rotation = Quaternion.Lerp(transform.rotation, this.correctPlayerRot, Time.deltaTime * 5);
    anim.SetFloat( "Speed", Mathf.Lerp(anim.GetFloat("Speed"), this.correctSPEEDanim, Time.deltaTime * 5));
    anim.SetFloat( "Direction", Mathf.Lerp(anim.GetFloat("Direction"), this.correctDIRanim, Time.deltaTime * 5));



    void LateUpdate(){

    GunAim.eulerAngles = this.correctBoneEuler;
    GunAim.rotation = Quaternion.Lerp(GunAim.rotation, this.correctBoneRotation * GunAim.rotation, multiplier);


    multiplier is actually 0, if I add any amount it starts to move in a freaky way. If I directly assign correctBoneRotation without lerping it, the resulting moves are even weirder. If I Lerp the eulerangles it doesn't work. So after trying a lot of combinations that one made the bone move.
    The Stream is just very obvious how it looks like but I'll just paste it here since a lil redundance won't kill anybody

    [code2=csharp]void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    if (stream.isWriting)

    stream.SendNext( anim.GetFloat("Speed") );
    stream.SendNext( anim.GetFloat("Direction") );


    this.correctPlayerPos = (Vector3)stream.ReceiveNext();
    this.correctPlayerRot = (Quaternion)stream.ReceiveNext();
    this.correctSPEEDanim = (float)stream.ReceiveNext();
    this.correctDIRanim = (float)stream.ReceiveNext();
    this.correctBoneEuler = (Vector3)stream.ReceiveNext();
    this.correctBoneRotation = (Quaternion)stream.ReceiveNext();


    The Results: What comes up from this script wich is atached to the playerPrefab is a very accurate Bone rotation when animation is on Idle, but when running in any direction the bone makes a horrible balancing movement that will blow your hope away. Very sad!
    Annyways... That is the best I could come up with so far... if anyone has a clue of why this happens please share! :)

    I've looked everywhere for people having the same issue and there's almost nothing out there. Thanks in advance!

  • I guess you will have to log most values and see if something is odd / 0 or otherwise wrong. This would actually also be the way I would do this if we could repro this.
    I'm sorry you didn't solve this already but I can hardly help :(
  • Thanks for our answere Tobias! Indeed, I was not able to solve this, but I kind of have an idea of what's going on. The animator is allways animating locally and just a single value makes the animation change. But the bone movement requires a more complex calculation, that needs to be set after the animation. So since the IDLE animation is allways animating unless character recieves speed or direction, I think the odd move comes when the manual bone move plus the IDLE plus the animation that's being sent all sum up and bring Chaos. Maybe if I had a better connection it would look different I don't know I just bring a theory up.

    Annyways I found a "Workaround" intead of moving the neck bone wich moves arms and head together I used the spine that hardly participates in any animation so that reduced by 80% the odd movement... I just have to make calculations locally and not rely on what the other player is seeing of his peers, sending a raycast would make a real mess haha. Everything's fine now! Thanks. Even with headaches included photon's still lovlely, and It even makes me wanna have more headaches, who doesn't like a little challenge? hehe. Seriously, congratulations, it's awesome, I tried a bunch of other's and I still choose photon with my eyes folded.
  • Wow. That's some seriously nice feedback at the end of your post! It's super reassuring to read that PUN and all of Photon is doing so well in your opinion! That's going to be a quote I have to send to the team :)

    And: Great to read that you could find a workaround for your problem. I think doing the calculation completely local could be a good solution. It's probably not essential that the animation is 100% accurately the same at the same time as on other clients. Better make it look good.
  • Well...I know this is not very topic related but it wouldn't be a good feedback if I don't go for goods and bads, te important thing is that most of this is awesome. In fact the whole thing is great, but adding a couple more things would make it perfect. For example as a Uruguayan I would love a South American Server. Center americans and northern south americans have a fairly good connection with USA server... 110 ping something like that. And people at the south like me get 350 ping, wich realy makes it a lil hard. I know LA south is expensive, I wouldn't put up a server in Uruguay, but Chile is very cheap and gets a 70 ping tops, to whole South America.
    I know this isn't a one way thing. So I'm going to give my first step and as soon as I finish a couple games I'm developing, I'm gonna buy the 100CCU plan and after I get a lil profit I'm getting the 500CCU right away. I don't think it's good to come asking for stuff if I don't even move a hair for it, at least that's what indie means to me, and whay makes me proud of it. So there... whatever you need man!
  • :)

    Thanks for that nice post. Your feedback is absolutely welcome and it's a particularly nice pointer to Chile for the hosting in South America. We definitely keep that in mind.
    It is sad that we can't cover all regions with a proper ping at the moment. We hope that things improve for everyone but we need your games and presence.

    If your players are mainly in the regions we cover and you only need a better server for development, please feel free to download and run the Photon Server internally. It's easy to switch as most features are covered by it.
    If you wanted to, you could even run one Photon instance yourself for the more local players and then use the cloud in all other regions. It's just a matter how you setup PUN before connect and that can be done in code.
Sign In or Register to comment.