1
\$\begingroup\$

I've done an if / else with the final position / rotation plus they never complete, how can I check this? stays like this

https://i.sstatic.net/3ADqz.gif

    if(head == false)
        cam.transform.position = Vector3.Lerp(cam.transform.position, PosicMin, Time.deltaTime * Speed);
    else {
        cam.transform.position = Vector3.Lerp(cam.transform.position, PosicMax, Time.deltaTime * Speed);
    }
    if(head == false)
        cam.transform.eulerAngles = Vector3.Lerp(cam.transform.rotation.eulerAngles, RotationMin, Time.deltaTime*Speed);
    else {
        cam.transform.eulerAngles = Vector3.Lerp(cam.transform.rotation.eulerAngles, RotationMax, Time.deltaTime*Speed);
    }
\$\endgroup\$
4
  • 3
    \$\begingroup\$ 1. You're not adjusting for deltaTime correctly 2. Never Lerp Euler angles - Lerp quaternions instead to always take the shortest path and handle wrap-around correctly. 3. Show us your if/else attempt so we can see exactly what you tried. \$\endgroup\$
    – DMGregory
    Commented Feb 26, 2019 at 4:26
  • \$\begingroup\$ hi again, edited post.I did not understand your second question. \$\endgroup\$
    – Nitecki
    Commented Feb 26, 2019 at 5:32
  • \$\begingroup\$ @Nitecki DMGregory is saying to use Quaternion.Lerp instead of Vector3.Lerp and to use transform.rotation instead of transform.rotation.eulerAngles. This provides a much smoother rotation, and prevents gimbal lock \$\endgroup\$
    – Alex F
    Commented Feb 26, 2019 at 6:11
  • \$\begingroup\$ sorry, I did not see any difference between the two with the naked eye, the quaternion is very difficult to use. even getting more error still persists. I did transform.rotation = Quaternion.lerp (RotMin, RotMax, Time.deltaTime * Speed) \$\endgroup\$
    – Nitecki
    Commented Feb 26, 2019 at 16:53

1 Answer 1

1
\$\begingroup\$

You're using an exponential ease-out Lerp, which in real numbers never actually reaches completion. Each iteration, it moves a fraction of the remaining distance - always leaving a nonzero fraction left to go. Even in finite-precision floating point, it might not reach the destination value: at a certain point, the incremental displacement can round to less than the precision of the current value, resulting in no further change.

Fortunately, Unity's == comparison operator on Vector3s and Quaternions includes a tolerance range so it will return true when they're almost the same.

The other issue that's going to throw you off is you're trying to interpolate Euler angles. This is almost always a bad idea. The game engine does not store or use Euler angles internally - it computes them on demand from the quaternion internals. That means the output you save in one frame might not match the input you get in the next frame, due to inevitable discontinuities in computing an Euler angle triplet from an orientation. That can be the source of the perpetual jitter in your implementation. And even without that complication, Euler angles do not interpolate well in general:

Animation contrasting smooth quaternion interpolation and tumbling Euler angle interpolation

  • On the left: interpolating rotations with quaternions, we get smooth rotation along the shortest arc to the destination

  • On the right: interpolating rotations with Euler angles results in excessive spinning/tumbling

(See this UnityAnswers post for more details - unfortunately the original source of this animation is no longer available online nor in the Wayback machine, but you can play with an interactive app)

So, we can fix your code like so:

// Adjust for deltaTime correctly, given the non-linear nature of this use of Lerp.
float blend = 1.0f - Mathf.Pow(1.0f - Speed/30f, Time.deltaTime * 30f);

// Select destinations. This way we don't need to repeat our blend / check logic.
Vector3 destinationPosition = head ? PosicMax : PosicMin;
Quaternion destinationRotation = Quaternion.Euler(head ? RotationMax : RotationMin);

// Ease toward the selected destinations.
cam.transform.position = Vector3.Lerp(cam.transform.position, destinationPosition, blend);
cam.transform.rotation = Quaternion.Lerp(cam.transform.rotation, destinationRotation, blend);

// Check whether we're "close enough".
if(cam.transform.position == destinationPosition && cam.transform.rotation == destinationRotation) {
    // Arrived!
}

If you want to more precisely control the threshold of what gets to count as "close enough," you can use Vector3.Distance and Quaternion.Angle to compute how far we are from our destinations, and compare those against custom thresholds.

\$\endgroup\$
6
  • \$\begingroup\$ appeared 39 errors, I resolved 37, it is difficult to understand the quaternion is equal to "Malbolge" because it asks several arguments and they do not end more. it is like this, pastebin.com/yxjtG4rD and erros imgur.com/a/MBZJqDQ \$\endgroup\$
    – Nitecki
    Commented Feb 26, 2019 at 20:33
  • \$\begingroup\$ If you've changed RotationMin/Max from the Vector3s you were using previously to Quaternions, then you don't need the Quaternion.Euler call, since you're not using Euler angles anywhere. I'm not sure what your remark about Malbolge is meant to say. \$\endgroup\$
    – DMGregory
    Commented Feb 26, 2019 at 21:16
  • \$\begingroup\$ I implemented some things, and it worked, but the script does not allow you to set the positions in play mode, the script does not accept (-destination) to return to the previous position or rotation. in any case, thank you very much is working even with these problems. \$\endgroup\$
    – Nitecki
    Commented Feb 27, 2019 at 20:09
  • \$\begingroup\$ In what sense does it not? You can set the destination variables to absolutely any value you find useful at runtime. \$\endgroup\$
    – DMGregory
    Commented Feb 27, 2019 at 20:10
  • \$\begingroup\$ youtube.com/watch?v=KsNg9iz-Exo&feature=youtu.be \$\endgroup\$
    – Nitecki
    Commented Feb 27, 2019 at 20:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .