- Home /
Problem with FromToRotation
So in a nutshell, what I'm trying to do is move my player across a mesh and have the players transform.up be the same as the normal of the face I'm moving over. It works fine most of the time, but there are places where it breaks down.
In one instance I have a mesh which is a 90 degree arch. The arch is rotated 90 degrees to the side so when the player moves over it, the player is also rotated. Each time I move to a new face on this arch my player turns a little to the left. In certain cases when the player is upside down the problem is even more dramatic, as the player will turn completely around.
Here's the part of my code which handles the transform.up rotation:
Vector3 prevUp = transform.up;
RaycastHit hit;
if (Physics.Raycast(transform.position, -prevUp, out hit))
{
Quaternion tilt = Quaternion.FromToRotation(transform.up, hit.normal);
transform.rotation = tilt;
}
Any advice or help will be greatly appreciated, thank you!
Answer by FortisVenaliter · May 12, 2015 at 03:24 PM
Yeah, you are only handling the up Vector. Since the rotations work on all three axes, you have to specify the others or they will be undefined.
Think of an airplane. If you just tell it you want it inverted, it can. But it could do a half-barrel roll, where it will be inverted but facing the same direction, or it can do a half loop, where it will be equally inverted, but facing the opposite direction.
So, I would do something like this (haven't tested the below code, but it should be a good starting point):
Vector3 prevUp = transform.up;
Vector3 prevFwd = transform.forward;
RaycastHit hit;
if (Physics.Raycast(transform.position, -prevUp, out hit))
{
Vector3 newUp = hit.normal;
transform.rotation = Quaternion.LookRotation(prevFwd, newUp);
}
I'm not a great mathematician so please bear with me now. I understand that I need to figure out the forward vector somehow, thus far I've been doing this:
Vector3 prevUp = transform.up;
yaw += turSpeed * Time.deltaTime * Input.GetAxis("Horizontal");
transform.rotation = Quaternion.Euler(0, yaw, 0);
RaycastHit hit;
if (Physics.Raycast(transform.position, -prevUp, out hit))
{
Quaternion tilt = Quaternion.FromToRotation(transform.up, hit.normal);
transform.rotation = tilt * transform.rotation;
}
What this does in my $$anonymous$$d is calculate the new up vector and factor in a rotation around the Y-axis based on input. This works well most of the time, even when going upside-down or on slanted surfaces except in a few cases where the player will suddenly turn on its own.
I used your suggestion and now it looks like this:
prevUp = transform.up;
prevFwd = transform.forward;
RaycastHit hit;
if (Physics.Raycast(transform.position, -prevUp, out hit))
{
transform.rotation = Quaternion.LookRotation(prevFwd, hit.normal);
}
It now seems to follow the surface alright, but it completely fails to calculate the up vector (it doesn't align with the surface normal). I've tried different configurations and I've looked around, but my algebra just isn't good enough to let me really understand what's going wrong.
Once again, any help will be much appreciated!
@inZayne:
This order makes not much sense:
transform.rotation = Quaternion.Euler(0, yaw, 0);
Vector3 prevUp = transform.up;
Since you first set a new rotation and then you grab the up vector you effectively always get Vector3.up since you first set the transform to face that way (with your Euler angles).
You should swap those lines. You have to get the prev up before you set the eulerangles.
Yes sorry, that's what I'm doing but I managed to put them in the wrong order here. I'll edit my post!