Slate Forums › Support › Animating local transform?
I’m animating an object with nested transforms, each of which can rotate. It seems that the existing transform rotation actions always rotate to world rotation, rather than local rotation? Is there any way to apply local rotation? Or do I need to make my own track for that?
Also, rotation is behaving a bit weird. If I use a RotateTo (-10, 0, 0), then right after I use RotateTo(20, 0, 0), it’s rotating 330 degrees around to 20, rather than taking the shorter rotation. Is there some way to control rotation direction?
Hello,
Hmm.. Are you refering to keyframing/animating transform in an “Animate Properties” clip, or a “Properties Track”?
If so, all transforms (and child transforms) are animated in their Local Coordinates (localPosition, localRotation).
Or, are you refering to the pre-made clips found under the “Transform” category, like “Rotate By” and “Rotate To”?
Let me know.
Thanks!
Join us on Discord: https://discord.gg/97q2Rjh
I was initially using Slate.ActionClips.RotateTo in a Transform track, but found it was setting ‘eulerAngles’. So I made a copy of this, named it LocalRotateTo, and started setting localEulerAngles. So that addresses my initial concern that I wanted to be able to set local rotation instead of world rotation.
As for the second issue, here’s a simple test case: Put an object in a room, and set its “X” rotation to 10. (So, it’s looking down a little.) Using a RotateTo clip to rotate to (0,0,0), and you’ll see that the x rotation goes from 10 to 0 as expected. Now, change the object’s initial rotation to -10 instead, and run the animation again. This time, the RotateTo considers the rotation to be -350 (if you look at what gets sent into Vector3.LerpUnclamped). The RotateTo clip then lerps from 350 to 0, causing the object to do a backflip to get back to 0. I’m not sure there’s much to be done about that, though, aside from making Quaternion versions of the Rotate scripts (which I’m thinking of doing myself.)
I played around with this a bit more. The issue is that Lerp just does plain old math, without any concern for the different ways Vector3s can be equivalent. So, (180,0,0) is the same as (-180,0,0), but will produce different lerp results when used as the Start or End of a Lerp.
So, before calling Lerp to determine the rotation, I first need to clean up the target rotation so that none of the component differences (Mathf.Abs(original.x – target.x), for example) exceeds 180. Here’s what I’m doing, which seems to work properly, though I assume there’s a more efficient approach. The following is the OnUpdate method of my LocalRotateTo action clip. Note the use of GetShortestResult to adjust the targetRotation to create an equivalent Vector3 that minimizes the rotation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
protected override void OnUpdate(float deltaTime) { if (length == 0) { actor.transform.localEulerAngles = targetRotation; return; } targetRotation = GetShortestResult(originalRotation, targetRotation); actor.transform.localEulerAngles = Easing.Ease(interpolation, originalRotation, targetRotation, deltaTime / length); } private Vector3 GetShortestResult(Vector3 original, Vector3 target) { // Ensure the rotation between any two components doesn't exceed 180 degrees var x = target.x; var y = target.y; var z = target.z; while (original.x + 180 < x) x -= 360; while (original.x - 180 > x) x += 360; while (original.y + 180 < y) y -= 360; while (original.y - 180 > y) y += 360; while (original.z + 180 < z) z -= 360; while (original.z - 180 > z) z += 360; return new Vector3(x, y, z); } |
So now my LocalRotateTo always takes the shortest rotation instead of doing backflips or pirouettes. 🙂
Thank you for the follow up.
Indeed, the “RotateTo” clip in the “Transform” does have this problem and which of course I will need to fix 🙂
There is already an extension method to transform I’ve made called “GetLocalEulerAnges” and “SetLocalEulerAngles” which is using some internal Unity methods, but because this is done through reflection, I’ve not used it a lot. If I manage to avoid pure reflection in those calls, then using those extension would be a proper solution. I will take a look at doin that 🙂
Thanks!
Join us on Discord: https://discord.gg/97q2Rjh