Rotation Lerp Question
Hello Guys, i have a question if those following two lines of code would do the same (they don't, but idk why)
transform.parent.rotation = Quaternion.Lerp(transform.parent.rotation, Quaternion.Euler(0, angle * 180 * sensitivity_x, 0), smoothingDuration);
and
transform.parent.rotation = Quaternion.Euler(Mathf.Lerp(transform.parent.rotation.x, 0, smoothingDuration), Mathf.Lerp(transform.parent.rotation.y, angle * 180 * sensitivity_x,
smoothingDuration), Mathf.Lerp(transform.parent.rotation.z, 0, smoothingDuration));
the reason why I am asking this, is because when I use Quaternion.Lerp
and I change the angle too fast, it always takes the "shortest path" to the target. So it will suddenly change the of the rotation, and that is a problem because I am trying to create some kind of 3d view around the y axis, but smooth. Now, I tried modifying the y value itself, not as an angle, but as a float. Because an euler value is wrapped and will jump from 180 to -180 and will never be greater than those values, but a float can. Thats why I would prefer the second code, but it doesn't work. Why? I seriously need help so bad, I literally tried everything to solve this problem.
Answer by Lvl1Lasagna · Mar 21, 2021 at 01:58 AM
Lerping a quaternion is not the same as lerping its euler angles. The size of the values between the raw angle data and the euler angle data is quite a big leap, so the speed of the lerp will definitely look much faster during a Quaternion.Lerp than lerping the individual euler angles. Quaternion also holds a bit more information than just the angles of the rotation and will lerp based on those as well (Generally Quaternion.Slerp is a bit better visual-wise than Quaternion.Lerp as well).
Lerping the individual angles could work, however you may want to use Mathf.LerpAngle instead of Mathf.Lerp as it will wrap the angles for you.
But thats the thing, if the angles are wrapped, than the direction can change while lerping. THats what I was trying to achieve
Answer by Ermiq · Mar 22, 2021 at 09:26 AM
To prevent the issue with lerp going to the shortest path, you need to use a rotation that is a sum of current rotation and some euler rotation.
The thing is, when you set target rotation as Quaternion.Euler(0, 90f, 0)
this quaternion represents a rotation that doesn't take into account anything else and basically if you imagine it as a vector than it would be a direction vector Vector3.right
( 0, 1, 0
). It doesn't care about from which position it has been rotated, it just knows that it should point 90 degrees to the right from wherever, and the (S)Lerp
will simply try to rotate the transform to the Vector.right
direction and that's it, and it will use the shortest path to do so. That's how (S)Lerp
work.
So, what to do?
To create a rotation quaternion that will represent a continuing rotation from current to target with the given direction (is it 90 degrees around Y clockwise
or -45 degrees around Y counterclockwise
?) you need to add this desired euler rotation to the current rotation of the transform, so the final target rotation will be current rotation + 90f degrees around Y clockwise
, as an example. Quaternions addition is made with *
, so to get the desired final rotation you do this:
Quaternion rotate90DegreesClockwise = transform.rotation * Quaternion.Euler(0, 90f, 0);
With this method, even if you set the euler rotation to, say, 250 degrees to the right, it will rotate to the right and won't cut the path through the left side. At least I believe it should work like this, I use this technique with adding eulers to the current rotation in my camera rig setups, and it works fine with fast camera rotations:
transform.rotation = transform.rotation * Quaternion.Euler(0, 250f, 0);
Obviously, there's a tricky nuance: you can't just tell rotate to the Vector3.right
. Instead you will need to precalculate and prepare the euler quaternion so it would represent a rotation some amount of degrees between current Y euler angle and target Y euler angle
.
The actual method of preparing of the angle value would depend on your setup: do you use mouse input values or maybe you set some desired angle manually... So, I can't tell how exactly you should calculate the current-to-target angle value.
However, here's a part of my camera rig setup. This is a part of the CameraRotator script that handles camera rotation based on mouse input, I have cut other stuff and only left the stuff useful for Y axis rotation here. The Rotate()
method takes Input.GetAxisRaw("Mouse Y") * Sensivity;
and performs a transform rotation for the given amount of degrees in the given direction (to the left when mouse input value is < 0
, to the right otherwise).
Try to attach it to some object and see how it works. Maybe you could use it.
public class CameraRotator : MonoBehaviour
{
Quaternion targetRotation;
float currentAngleDelta;
public bool smooth = true;
[Range (0.000001f, 0.1f)] public float smoothDelay = 0.00001f;
[Range (0.1f, 10f)] public float Sensitivity = 6f;
public static float SmoothDelay(float current, float target, float delay = 0.001f, float dt = Time.deltaTime)
{
return Mathf.Lerp(current, target, 1f - Mathf.Pow(delay, dt));
}
void Update()
{
Rotate(Input.GetAxisRaw("Mouse Y") * Sensitivity);
}
public void Rotate(float angle)
{
targetRotation = transform.rotation;
if (smooth)
{
currentAngleDelta = SmoothDelay(currentAngleDelta, angle, smoothDelay);
}
else
{
currentAngleDelta= angle;
}
targetRotation *= Quaternion.Euler(0f, currentAngleDelta, 0f);
transform.rotation = targetRotation;
}
Your answer
Follow this Question
Related Questions
Copy Roll From one Gameobject to another Without other rotations effecting it 0 Answers
Add Rotation from parent to Quaternion Child 1 Answer
Maintain fixed vision while the player turn 0 Answers
Help with rotating camera around object based on mouse input 0 Answers
How can I find direction with known 2 projection angles on xz and yz planes? 2 Answers