Friday, October 12, 2012

Unity3d, Rotate around axis glitch with scale

For the record, Let me state that I'm posting this solely because I spent a LONG (2+wks) time debugging this problem and finally figured out what is going on. I've submitted a bug report to Unity3d, but in reality, I'm not entirely sure it's a glitch, because I can't figure out the expected behavior, and the Unity3d Rotate documentation is worthless.




This is my scenario, and I make no claims that this is the same for other situations:

I have a game object that is scaled to be -1, 1, 1 ( basically to mirror a model.) Inside of that object I have some child objects in a hierarchy :  Parent -> Child1 -> Child2.  Parent has a behavior script on it that uses both children. The goal is to make a non-trivial axis from the center of Child1 and rotate around that axis. Child2 should follow since of the hierarchy. The problem is that with the object scaled to -1 in the x direction, the rotation  doesn't work around the correct axis.


Here's the example. On the right side of the screen, there's the object with normal (1,1,1) scaling. The yellow debug line represents the rotation axis and the blue lines represent rotating the red sphere around that line (36 times, at 10degree intervals). As expected, the cone of lines has the axis in the center.

On the left side of the screen is the same object,but with scaling of (-1,1,1). With this scaling, the cone is clearly not along the axis. Now, in this case it's pretty clear that the cone is not around the axis, but in my actual project, the axis was nearly vertical, so instead of being way off, it was just slightly off and hard to debug.

Anyway, after some quick math and toying around, I decided to add a new debug line, that is the same axis but with scaling of (-1,1,1) applied to it. Here's the picture with that line turned on as well (in purple).


Visually the purple line seems to be correct on the left and the yellow line is correct on the right (and in my actual project I have means to verify it's exactly correct, not just visually.)


Here's some code:


void Start () {
   rotAxis = new Vector3(1,.5f,0);
            rotAxis.Normalize();
}
void Update () {
 shoulder.transform.rotation = Quaternion.identity;
        Debug.DrawLine(shoulder.transform.position, shoulder.transform.position + 11 * rotAxis, Color.yellow);

   for (int i = 0; i < 36; i++)
   {
       shoulder.transform.Rotate(rotAxis,10);
            Debug.DrawLine(shoulder.transform.position, elbow.transform.position, Color.blue);
   }

            Debug.DrawLine(shoulder.transform.position, shoulder.transform.position + new Vector3(-11 * rotAxis[0], 11 * rotAxis[1], 11 * rotAxis[2]), Color.magenta);
}



Basically I'm using Transform.rotate(axis, angle). So it seems to me, moral of the story is that if your parent object has scaling,  you need to apply the same scaling to a rotation axis. I'm not entirely sure what you should do if multiple parents have scaling, but my guess is that you'd have to apply all of those scalings, but that's my guess.

Anyway, I'm posting this just so I can find this again, and in case anyone else has the issue.

If you want to play with my example, here's the scene
RotateGlitch.zip
If you open the project and click play, it runs with the yellow line displayed, when you hit spacebar it also shows the purple scene.

No comments:

Post a Comment