Rotating local transform not rotating fully if tranform.up is not exactly at (0,1,0)

Hello,

I’m making a game utilizing zero gravity. I have a sphere that a character floats inside of, and when space is pressed a force is applied and the character is propelled along the character’s local up direction ( character.up ) towards the edge of the sphere.

When the character gets close to the edge of the sphere I’m trying to make the character rotate so it’s local up ( character.up ) is pointing towards the center of the sphere and therefore lands against the sphere edge standing on his feet.

I know I’ve got the correct newUp direction because I’m using Debug.DrawLine to visualise it and it’s correct.

So it seems to be a problem with the way I’m using Quaternion.Lerp or possibly Quaternion.FromToRotation.

Here’s the relevant portions of code:

 void Update () {
        if(targetWithinDistance) { //If getting close to target point on the sphere's edge
    	    RotateToCenter();
        }
        bool jumpPressed = CrossPlatformInputManager.GetButtonDown("Jump");
        if(jumpPressed) {
            Jump();
        }
    }

    void Jump() {
    
    	localUp = character.up;
    
    	RaycastHit hitInfo;
    	//Raycast to jump direction
    	// 0.1f is a small offset to start the ray from inside the character
    	//Start ray from inside character, ray is directed along localUp towards the edge.
    	if(Physics.Raycast(character.position + (localUp * 0.1f), localUp, out hitInfo, 1000f))
    	{
    		//Hit found.
    		targetPoint = hitInfo.point;
    		newUp = (center.position - hitInfo.point).normalized;
    	} 
    	jump = localUp * jumpPower;
    	rigidbody.velocity = jump;
    
    	Debug.Log("localUp: "+localUp);
    	Debug.Log("newUp: "+newUp);
    
    	isGrounded = false;
    	targetWithinDistance = false;
    }

    void RotateToCenter() {
    	q = Quaternion.FromToRotation (localUp, newUp);
    	character.rotation = Quaternion.Lerp(character.rotation, q, Time.deltaTime );
    }

The code works perfectly fine if the localUp is exactly (0, 1, 0), but is wrong when it’s not. It won’t rotate at all when the player’s localUp is (0,-1,0)even though newUpis displayed as (0,1,0) and therefore should require a rotation of 180 degrees on the y axis.

The Debug.Log in the Jump() Method shows:

localUp: (0.0, -1.0, 0.0)
newUp: (0.0, 1.0, 0.0)

Yet the Lerp rotation doesn’t rotate at all.

Any help in finding out why this problem exists would be greatly appreciated.

Dan

UPDATE*

I’ve been trying to narrow down the problem and it seems to be to do with the local rotation of the character.

I’ve changed the code to instantly apply the rotation without using Quaternions, as below:

if(targetWithinDistance) {
	transform.eulerAngles = newUp;
	//RotateToCenter();
}

when this is run: the character will still rotate to an incorrect rotation, when transform.up is not exactly (0, 1, 0). But I’ve noticed that the Rotation displayed in the Inspector for the character seems to show the character has been rotated as if the transform.up started at (0, 1, 0).

For Example: If I I set the scene so that the character is at position: x:0, y:0, z:0, character’s rotation is x:0 y:0 z:315 in the inspector, the transform.up for the character is displayed as (0.7071066, 0.707107, 0).

When jump is pressed, the new rotation back to the center is (-0.7071066, -0.707107, 0), (newUp is set to this correctly)

Now when the rotation angles are set with: transform.eulerAngles = newUp;the new transform.up should be set to (-0.7071066, -0.707107, 0), but this is not the case!

The new transform.up is now: (0.000152301, 0.9999238, -0.01234009).
Looking at the rotation of the character in the inspector though shows a rotation of: x:359.2929, y:359.2929, z:0.

For some reason the character has had the newUp angles minused from the rotation!

X: 0 (360) degrees - 0.7071066 =  352.2928934;
Y: 0 (360) degrees - 0.707107 = 359.292893;
Z: 0 - 0 = 0;

I have no idea why but it I’ve managed to fix the issue whilst using Quaternions:

Instead of passing in the localUp into the FromToRotation I need to pass in the the GLOBAL UP:

This is the line I changed:

q = Quaternion.FromToRotation (localUp, newUp);

I changed to:

q = Quaternion.FromToRotation (Vector3.up, newUp);

I’d very much like if someone could explain this to me.