Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
12 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
This question was closed Aug 06, 2014 at 12:49 PM by meat5000 for the following reason:

The question is answered, right answer was accepted

avatar image
3
Question by Fishhead · Jun 05, 2011 at 02:52 PM · animationrotationbone

How to rotate a bone during an animation?

I have a character with idle and walk animations. Now I want to rotate the upper body without stopping the animations. So only one bone should stop playing the animation. If I try to stop the animation with animation.Stop(); it tells me that this bone isn't playing any animations. The line of script that is supposed to be rotating the bone looks like this: transform.Rotate(0, Input.GetAxis("Mouse X") sensitivityX, 0);*. It doesn't give me any console errors. Please help or ask for further information on my problem.

Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image meat5000 ♦ · Aug 06, 2014 at 12:48 PM 0
Share

I made a little script to perform manual I$$anonymous$$ during a sword swing, to hit a particular target. I performed transform rotation on the particular bone in LateUpdate() and this worked for me. Although, be advised, use of LateUpdate() should be kept to a $$anonymous$$imum for performance reasons.

2 Replies

  • Sort: 
avatar image
6
Best Answer

Answer by Owen-Reynolds · Jun 05, 2011 at 04:03 PM

If the bone you want to not animate is at the top of a chain (suppose the lower spine,) you could try to "subtract" it with:

 // path in Heirarchy to bone. Set in Start():
 Transform upperSpine = transform.find("bones/lowerSpine/upperspine");
 
 animation["Walk"].AddMixingTransform(upperSpine);
 // repeat for hips

AddMixingTransform (see the docs) is a wierd one. The first one subtracts all but that bone and below. The second+ is supposed to add more bone chains (but I haven't done that.)

You upperSpine should then be completely non-animated, and "adding" method you are using should work.

A more robust solution is to just play the animation and overwrite the bone's transform. The problem is, even if the bone never moves, the animation is resetting to that position ever frame. Adding 1 degree/frame won't work any more -- rotation is always reset to 0. Felix's LateUpdate comment is correct -- animation is set in Update, bones are positioned by animation after Update quits (overridding bone rots you made in update,) and then LateUpdate has a crack at them. Try:

 // instead of changing rotation, change my rotation var:
 float spineSpin = 0;
 spineSpin += Input.GetAxis("Mouse X") * sensitivityX;
 lowerSpine.eulerAngles = new Vector3(0, spineSpin, 0);
 
 // complete guess. Math to apply overall model tilt to the spine:
 lowerSpine.rotation = transform.rotation * lowerSpine.rotation;
Comment
Add comment · Show 11 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image coffiarts · Feb 20, 2013 at 08:24 AM 0
Share

I am quite curious whether the solution(s) proposed by Owen work, because I seem to be having quite similar problems (as posted over here: http://answers.unity3d.com/questions/402259/how-to-combine-mecanim-and-script-based-bone-movem.html).

I've already tried to adopt both the LAteUpdate() and Add$$anonymous$$ixingTransform approach, but I am afreaid that in my case the issue seems to go further: By this I've managed to apply player/mouse controlled bone rotation over animation controlled roation. But this leads into trouble whenever I try to propagate the bone rotation changes over RPC in a network multiplayer game. In that case, the additional bone rotation (over RPC) seems to be too slow and laggy, so that the animation controlled rotation (which runs locally on the client and thus much faster) makes the model always flatter and snap back into its original position.

One thing that came to my $$anonymous$$d, concerning Owen's idea:

// complete guess. $$anonymous$$ath to apply overall model tilt to the spine: lowerSpine.rotation = transform.rotation * lowerSpine.rotation;

I wonder whether it would be even better to use the following:

 lowerSpine.rotation = lowerSpine.rotation + spineSpin;

I imagine that in this approach lowerSpine.rotation would always return the exact rotation of the bone (as induced by the animation during that specific frame or point in time), and then the + spineSpin would ensure that any additive rotation is really applied additively to that.

I have some hope that this could solve my network/RPC lag issue. I'll have to try this out and post the results asap.

avatar image Owen-Reynolds · Feb 20, 2013 at 02:33 PM 1
Share

The math to combine rotations (Quaternions) uses the multiply symbol, just because. rotation1*rotation2 computes rotate #1, followed by #2 on local coords. So "adds" 2 to 1.

The network stuff sounds like a data problem. In my limited experience, if you're sending the "user rotation" and having the client remember the old value (not somehow resetting each frame in the hopes of fresh data,) then it should be laggy, but otherwise look the same.

avatar image coffiarts · Feb 21, 2013 at 11:50 AM 0
Share

Owen, you're certainly right about the multiplication of the rotation values (my math knowledge isn't very deep in that point). In my case, I am calculating euler angles ins$$anonymous$$d of Quaternions. Don't know whether this makes a difference.

Concerning the network lag issue: I should be more precise about what I am trying to do. I have a 1st person camera, which is controlled in a free mouse look way by a dedicated script. This works absolutely fine. Now I want the upper body of my player model (including the arms, hands and any gear he is holding) to align with the player's camera orientation. In other words: The mouse control is used only for steering the camera, while the player model's spine just needs to "follow" the camera. For achieving this, I am grabbing the rotation of my 1st person camera inside LateUpdate(), and then applying it to my player model's spine bone. This must be fired via RPC, so that any clones of the player on any connected client is updated visually.

This looks roughly like this (don't have the exact code available here on this PC):

 var mySpineBone:Transform;
 var myCamera:Transform;
 
 function Start()
 {
     // the following two public variables are actually assigned during design time by drag&drop in the editor
     // I am just assigning them dynamically inside the code here for a demonstration
     mySpineBone = GameObject.Find("$$anonymous$$y$$anonymous$$odel/Armature/etc./etc./Spine");
     myCamera = GameObject.Find("1st Person Camera");
 }
 
 function LateUpdate()
 {
     var rotationX:float = myCamera.rotation.eulerAngles.X;
     networkView.RPC("changeBoneOrientation", RPC$$anonymous$$ode.AllBuffered, rotationX);
 }
 
 @RPC
 function changeBoneOrientation(xValue:float)
 {
     mySpineBone.rotation.eulerAngles.X = xValue;
 }
 
 

It is important to know that the player model is animated by several animations (Idle, Run, Walk etc.), each of them having an effect on the spine bone as well.

Now when I run the above code, it works absolutely smoothly on the local client: There's absolutely no visual lag between the animation based bone rotation and the (additive) mouse induced bone rotation. But in any other connected client, the model will be flapping forward and backward. It should be noted that I am testing this only in local LAN and on localhost, i.e. the connection itself is brilliantly fast (1Gbit LAN).

I can't see currently why there should be a problem with transferring the data. I rather suppose that the RPC update of the spine bone rotation is always somewhat slower than the animation itself, so that every frame, the bone is experiencing two interfering rotation updates.

avatar image Owen-Reynolds · Feb 21, 2013 at 08:59 PM 1
Share

I'd think should post as a fresh Q emphasizing networking. But just looking:

o recommending not to use things like Quat.Eulerangle.x= (but not real problem, just now.)

o You client has no "old value" to go back to if it doesn't get a fresh packet that frame. Suppose animation says x=0, and your RPC xValue is constant at 30. If a packet is delayed past a frame, x won't get the extra rotation that frame, so will appear to "snap back" to 0.

$$anonymous$$ake xValue a global. Still use that to set rotation, but have the RPC only copy into xValue. Now, when you lose a frame, you have the "old" xValue.

avatar image coffiarts · Feb 21, 2013 at 10:19 PM 0
Share

Just for better understanding: Why isn't it a good idea to set .rotation.eulerAngles.x to a new value? Thinking about it, I recall that I've read somewhare that it's always recommended to set eulerAngles to a full Vector3(x,y,z) ins$$anonymous$$d of assigning the x,y,z values separately. Is that what you meant by that? But I don't want to go too far off topic here.

$$anonymous$$ost important: You've solved it!!

You are right, it was simply the stored "old value" that was missing! By adding a few more lines to my code (declaring rotationX as a private global, overwriting its value in changeBoneRotation() and ensuring that changeBoneRotation() is invoked at least once per frame for remote clones), it works brilliantly now: No flapping anymore, and bone rotation appears smooth like silk over RPC). Thanks alot!!

Here's my full code that's working fine (the real code now, with some lines that were missing in the original one above). The new lines are marked as // new!

 #pragma strict
 var playerBoneTo$$anonymous$$ove:Transform;
 var camera1st:Transform;
 
 // new!
 private var rotationX:float;
 private var rotationY:float;
 private var rotationZ:float;
 
 function LateUpdate () 
 {
     if (!networkView.is$$anonymous$$ine)
     {
         // new!
         // ensure for remote clients that the bone rotation is updated at least once each frame with the
         // most recently known value.
         // This avoids "bone flapping" due to network lags
         changeBoneOrientation(rotationX, rotationY, rotationZ);
         return;
     }
     
     if (camera1st.gameObject.activeSelf)
     {
         var newRotationX:float = -camera1st.localRotation.eulerAngles.z;
         var newRotationY:float = -camera1st.localRotation.eulerAngles.x;
         var newRotationZ:float = -camera1st.localRotation.eulerAngles.y;
         
         changeBoneOrientation(newRotationX, newRotationY, newRotationZ);
         
         if (networkView.is$$anonymous$$ine)
         {
             networkView.RPC("changeBoneOrientation", RPC$$anonymous$$ode.Others, newRotationX, newRotationY, newRotationZ);
         }
     }
 }
 
 
 @RPC
 function changeBoneOrientation(newRotationX:float, newRotationY:float, newRotationZ:float)
 {
     // new!
     rotationX = newRotationX;
     rotationY = newRotationY;
     rotationZ = newRotationZ;
     
     playerBoneTo$$anonymous$$ove.localRotation.eulerAngles = new Vector3(rotationX, rotationY, rotationZ);
 }
 

BTW: Don't bother about why I am so wildly assigning the x/y/z values of the camera to the rotation variables: I seem to have messed something up with my local/global coords, and so far couldn't find out the reason. The current "cross-assignment" (x=z, y=z, z=y) is the only way that seems to work. But that's also off topic.

Show more comments
avatar image
4
Best Answer

Answer by fherbst · Jun 05, 2011 at 03:32 PM

You have to rotate the bone every frame. You cannot stop the animation for a single bone (as long as I know); the animation will rotate the bone every frame to the animated value, so you have to rotate the bone every single frame (possibly in LateUpdate, so it happens after the animation updates your bone rotation).

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image AndrewRyan · Dec 01, 2014 at 01:15 AM 0
Share

Late update did the trick to those wondering.

avatar image kk88 · Oct 05, 2019 at 08:54 PM 0
Share

thanks LateUpdate workes indeed.

Follow this Question

Answers Answers and Comments

9 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Rigging Question: Location of Root bone 0 Answers

fbx animation beats script animation? 2 Answers

Rotate a bone with mouse input while animation is playing 0 Answers

animation & position problem 0 Answers

Bone rotation overrides animations completely 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges