0
\$\begingroup\$

Hi i have a start point and end point which i use to create some point between, this points are calculated with a blending rotation between point A rotation to point B rotation.

I use Mathf.LerpAngel but still I'm getting wrong result.

When rotation reaches -180 or 180 in some cases even -359.05 or 0.005 it gets flipped. Here's the result with issue : https://raw.githubusercontent.com/CycloneRing/UnityRotationLerp/main/RotationLerpIssue%20.mp4

And this is the result I want to achieve:

enter image description here

And here's my code (Look at Github):

// Extra points for (int i = 0; i < genPts.Count; i++) { float blendValue = ConvertRange(0, genPts.Count, 0.0f, 1.0f, i); var localEulerFrom = start.localEulerAngles; var leftAngleFrom = spt.angleLeft; var rightAngleFrom = spt.angleRight; var localEulerTo = end.localEulerAngles; var leftAngleTo = ept.angleLeft; var rightAngleTo = ept.angleRight; var localEulerBlend = LerpAngles(localEulerFrom, localEulerTo, blendValue); var leftAngleBlend = Mathf.Lerp(leftAngleFrom, leftAngleTo, blendValue); var rightAngleBlend = Mathf.Lerp(rightAngleFrom, rightAngleTo, blendValue); var base_left_angle = Quaternion.Euler(localEulerBlend.x, localEulerBlend.y, localEulerBlend.z + leftAngleBlend) * Vector3.right; var base_right_angle = Quaternion.Euler(localEulerBlend.x, localEulerBlend.y, localEulerBlend.z + -rightAngleBlend) * Vector3.right; var leftPos = genPts[i] + -base_left_angle.normalized * length; var rightPos = genPts[i] + base_right_angle.normalized * length; genExtraPts.Add(leftPos); genExtraPts.Add(rightPos); } 

I want it continuously keep rotation with a smooth blend. How can i achieve that?

A simple, minimal unity project is uploaded in github at https://github.com/CycloneRing/UnityRotationLerp

EDIT 1 : I tried using Quaternion as well but result is same.

// Extra points for (int i = 0; i < genPts.Count; i++) { float blendValue = ConvertRange(0, genPts.Count, 0.0f, 1.0f, i); var rotationFrom = start.localRotation; var rotationTo = end.localRotation; var localRotationBlend = Quaternion.LerpUnclamped(rotationFrom, rotationTo, blendValue); var base_left_angle = localRotationBlend * Vector3.right; var base_right_angle = localRotationBlend * Vector3.right; var leftPos = genPts[i] + -base_left_angle.normalized * length; var rightPos = genPts[i] + base_right_angle.normalized * length; genExtraPts.Add(leftPos); genExtraPts.Add(rightPos); } 
\$\endgroup\$
5
  • \$\begingroup\$ General advice is always lerp (or in this case, it looks like you want slerp) quaternions, never Euler angles. It's not obvious what you're doing with your left/right variables though - can you edit your question to give more context about what the expected inputs/outputs there should be? \$\endgroup\$ Commented Aug 16, 2022 at 2:05
  • \$\begingroup\$ @DMGregory They will be vertices, I tried slerp but it doesn't give a better result, also I need to apply calculation on vector3 positions and not quaternions. \$\endgroup\$ Commented Aug 16, 2022 at 2:15
  • 1
    \$\begingroup\$ An Euler angle.triplet is not a position. Can you explain in more detail why you can't use quaternions here? Saying that these points are vertices doesn't clear anything up, because we can put vertices in ANY spatial configuration. What we need from you is to describe the spatial configuration you're trying to make. Embedding images or animated gifs in your question usually works better than off-site file hosting for getting eyeballs on it. Do you have any constraints, like the helix always staying in vertical orientation? \$\endgroup\$ Commented Aug 16, 2022 at 11:25
  • \$\begingroup\$ @DMGregory it may be in any orientation, i want to use it to create a road editor for sci fi racing game, so i generate vertices and mesh based on them. I added reference gif I want to achieve. \$\endgroup\$ Commented Aug 16, 2022 at 12:30
  • \$\begingroup\$ @DMGregory The problem here is he sometimes wants to Lerp more than 180 degrees. IIRC the built-in Quaternion functions will never do this - they always take the shortest path. \$\endgroup\$ Commented Aug 16, 2022 at 23:42

1 Answer 1

1
\$\begingroup\$

You run into this type of issue when you want to rotate in a specific direction, and Unity doesn't realize this.

When you tell Unity to Lerp/Slerp between two angles, it takes the shortest path. You are running into problems is when the shortest path is no longer in the direction you want to go. In your video, the bottom gizmo is rotating clockwise. For the first 180 degrees of rotation, the double-helix is rotating in the same way - clockwise. However, once the difference in rotation between the top and bottom gizmos is more than 180 degrees, the double-helix suddenly rotates 180 degrees counter-clockwise because that's now the shortest direction to go.

For example, if you tell Unity to Lerp a quaternion from 0 degrees to 179 degrees, it will move in the positive direction (clockwise, if you're looking at the Y axis), because that's the shortest path from 0 to 179. However, if you tell it to Lerp a quaternion from 0 degrees to 181 degrees, it will move in the negative direction (counter-clockwise, if you're looking at the Y axis).

If you're only rotating one axis, the easiest thing to do is track the rotation of each end as a single float, so that it doesn't wrap at 180/-180, and use Mathf.Lerp().

A highly simplified example:

[SerializeField] private Transform start; [SerializeField] private Transform mid; [SerializeField] private Transform end; float speed = 90; float startRotation = 0; float endRotation = 0; void Start() { startRotation = start.transform.localEulerAngles.y; endRotation = end.transform.localEulerAngles.y; } void Update() { endRotation += speed * Time.deltaTime; float midRotation = Mathf.Lerp(startRotation, endRotation, .5f); Debug.Log(midRotation); mid.transform.localEulerAngles = new Vector3(0, midRotation, 0); end.transform.localEulerAngles = new Vector3(0, endRotation, 0); } 

In this example, the endRotation value is always increasing and never wraps. This means that when we Lerp from startRotation to endRotation, we're always moving in the positive (clockwise) direction.

You need to store your rotation values separately rather than reading them from the transform each frame, or Unity may wrap them:

transform.localEulerAngles = new Vector3(0, 370, 0); Debug.Log(transform.localEulerAngles); //"(0.00, 10.00, 0.00)" 
\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.