Why is rotation locking to an axis?

I have a 3rd person skateboarding character (imagine Tony Hawks) whose rotation I wish to set at the top of a half pipe (so that they launch straight “up” and land back down on the pipe, without moving either forward or backwards). I’m doing this as, for small half pipes, some forward momentum is maintained so they hit the top and keep moving forward. Not ideal!

alt text

Fig 1 - Skateboarder and halfpipe.

In order to set the correct rotation (as if the player is riding an invisible wall aligned with the half pipe), I figure the players local x rotation should be 270.

alt text

**Fig 2 - Halfpipe with “wall”. No matter the angle player goes up halfpipe, they should behave as if riding this (nonexistant) wall **

To do this, I have a collider/trigger set up at the lip of the pipe, with an OnTriggerEnter() calling this code:

if (coll.gameObject.tag == "Player")
        {
             Vector3 newEulerAngles = new Vector3(270, 
             coll.gameObject.transform.rotation.eulerAngles.y, 
             coll.gameObject.transform.rotation.eulerAngles.z);

            float speed = 100000; // want this to be instant
            float step = speed * Time.deltaTime;
            coll.gameObject.transform.rotation = 
            Quaternion.RotateTowards(coll.gameObject.transform.rotation, 
            Quaternion.Euler(newEulerAngles), step);
        }

When trying this however, the y and z rotation is set to zero, every time.


Fig 3 - Approaching pipe at an angle

Fig 3 - On trigger, player rotation is snapped to (270, 0, 0), despite only x being altered

I’ve tried various methods and they all behave this way, for example the simpler script:

if (coll.gameObject.tag == "Player")
{
    Vector3 newEulerAngles = new Vector3(270, 
    coll.gameObject.transform.rotation.eulerAngles.y, 
    coll.gameObject.transform.rotation.eulerAngles.z);
    coll.gameObject.transform.rotation = Quaternion.Euler(newEulerAngles);
}

I’ve done some looking around and my best guess is this has something to do with Gimbal locking, but I could be way off. If anyone can point out why the player is snapping to this angle and ignoring the previous y, z values I’d love to learn!

Could coll.gameObject.transform.rotation.eulerAngles.y be getting set to 0 earlier in the script? Try printing that value without doing anything else and let me know what it says.

I would definitely try print (the xyz euler values) on the initial rotation and the created quaternion to see what the heck is going on.

Rotations in unity have given me so much frustration in the past. Hope that helps a little tho. Let me know what you find out and maybe I can shed some more light on what’s happening.

You experience a Gimbal Lock since you work with an eulerangles representation. Unity specifically uses Quaternions to avoid a gimbal lock. However when you use eulerAngles you convert the rotation to an eulerAngles representation.

You shouldn’t use any absolute values and avoid using euler angles in such cases.

This is not something that Unity is responsible for. This is a pure effect / limitation of an eulerangles representation.

First of all, if you need to lerp a rotation, you should not do this in OnTriggerEnter() method. Because this method is just called once when you enter. you should do lerping in OnTriggerStay() method.

What i would do is:
First i would get the rotation at first enter

Quaternion enterRotation;
OnTriggerEnter()
{
enterRotation = transform.rotation;
}

Then while i am in trigger i would lerp that rotation

OnTriggerStay()
{
//lets say you need 30 degree rotation around your transform's local up axis (since pivot may vary with .fbx files, you might need to use transform.right or transform.forward):
Quaternion targetRotation = enterRotation * Quaternion.AngleAxis(30, transform.up);
transform.rotation = Quaternion.Lerp(transform.rotation,targetRotation,Time.fixedTime * speed)
}

I hope that works for you. There might be typo errors since i don’t have a compiler right now. Sorry for that.