我的四元数旋转协程在接近结束时变慢?

huangapple go评论119阅读模式
英文:

My Quaternion rotation coroutine slows down towards the end?

问题

我有一个协程,当用户输入一个触发器然后按下特定的键时启动。整体上旋转是有效的,但在旋转末尾开始变得非常慢。我在使用Vector3.Lerp时遇到过这个问题,但我通过使用speed * Time.deltaTime和另一个变量来使其平滑化来解决了这个问题。我尝试根据Unity文档中的Quaternion.RotateTowards使用一步,但它根本不会旋转。

  1. void Update()
  2. {
  3. if (Input.GetKey(KeyCode.Z))
  4. {
  5. Debug.Log("Raycast.");
  6. if (Physics.Raycast(transform.position, Vector3.down, 1.5f))
  7. {
  8. StartCoroutine(Turn(cubeObject));
  9. }
  10. }
  11. }
  12. IEnumerator Turn(Transform cubeObject)
  13. {
  14. Quaternion targetRotation = Quaternion.identity;
  15. do
  16. {
  17. Debug.Log("Begin rotating.");
  18. Vector3 targetDirection = cubeObject.position - transform.position;
  19. targetRotation = Quaternion.LookRotation(targetDirection);
  20. Quaternion nextRotation = Quaternion.RotateTowards(
  21. transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
  22. transform.localEulerAngles = new Vector3(0, nextRotation.eulerAngles.y, 0);
  23. yield return null;
  24. } while (Quaternion.Angle(transform.rotation, targetRotation) == 0f);
  25. }

如果我将最后一行的最后一个值(Quaternion.Angle)更改为大于0的任何值,旋转永远不会结束。我将被锁定在旋转状态,直到退出运行时。我只想在按下适当的键时旋转一次完全朝向目标。

英文:

I have a coroutine that is initiated when the user enters a trigger and then presses a specific key. The rotating as a whole works, but towards the end of the rotation it begins to rotate much, much slower. I have had this issue when using Vector3.Lerp but I fixed that by using speed * Time.deltaTime and another variable to make it smooth. I tried to use a step as per the Quaternion.RotateTowards unity docs but it would just not rotate at all.

  1. void Update()
  2. {
  3. if (Input.GetKey(KeyCode.Z))
  4. {
  5. Debug.Log("Raycast.");
  6. if (Physics.Raycast(transform.position, Vector3.down, 1.5f))
  7. {
  8. StartCoroutine(Turn(cubeObject));
  9. }
  10. }
  11. }
  12. IEnumerator Turn(Transform cubeObject)
  13. {
  14. Quaternion targetRotation = Quaternion.identity;
  15. do
  16. {
  17. Debug.Log("Begin rotating.");
  18. Vector3 targetDirection = cubeObject.position - transform.position;
  19. targetRotation = Quaternion.LookRotation(targetDirection);
  20. Quaternion nextRotation = Quaternion.RotateTowards(
  21. transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
  22. transform.localEulerAngles = new Vector3(0, nextRotation.eulerAngles.y, 0);
  23. yield return null;
  24. } while (Quaternion.Angle(transform.rotation, targetRotation) == 0f);
  25. }

And if I change the very last value on the last line (Quaternion.Angle) to anything greater than 0, the rotation never ends. I will be locked in rotation until I exit runtime. I'm only trying to rotate fully towards the target just once when the appropriate key is pressed.

答案1

得分: 1

以下是您要翻译的内容:

"As said there is a combination of a couple of issues here

  • First you potentially start a lot of concurrent ("simultaneously" happening) Coroutines! You should only start ONE and either make sure you don't start a second one or interrupt an already running one:

    1. private Coroutine currentRoutine;
    2. void Update()
    3. {
    4. // Use GetkeyDown to check of the first frame the key went down
    5. // rather than a continuous holding down of the button
    6. if (Input.GetKeyDown(KeyCode.Z))
    7. {
    8. Debug.Log("Raycast.");
    9. if (Physics.Raycast(transform.position, Vector3.down, 1.5f))
    10. {
    11. if (currentRoutine != null) StopCoroutine(currentRoutine);
    12. currentRoutine = StartCoroutine(Turn(cubeObject));
    13. }
    14. }
    15. }
    16. IEnumerator Turn(Transform cubeObject)
    17. {
    18. ...
    19. currentRoutine = null;
    20. }
  • Then you are mixing the global world space direction targetDirection and also world space transform.rotation with a local space transform.localEulerAngles. You want to either do all calculation in local or global space - don't mix!

  • Then I think the slowing down can be explained by the fact that your targetDirection might have an offset in the Y axis.

    You do RotateTowards which rotates into the target rotation on all three axes - but then throw away X/Z and only apply the Y component.

    => The closer your rotation comes to the final targetRotation (potentially never fully reaching it btw) the more you see the effect since the Y component of the rotation is already almost "correct" so it now tries to rotate more and more on the X/Z components - the ones you ignore.

    In order t solve this (and in general) I would recommend to stick to Quaternion as much as possible and rather already fix the target direction

    1. targetDirction.y = 0;
    2. targetRotation = Quaternion.LookRotation(targetDirection);
    3. transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
    4. yield return null;
  • And finally never use == for comparing float! You could rather use Quaternion == which uses a reduced precision of 1e-5

    1. while(transform.rotation != targetRotation);
    2. // and then make sure to end up with clean values
    3. transform.rotation = targetRotation;

    or alternatively if you want to stick to the angle an be more precise use Mathf.Approximately

    1. while(!Mathf.Apprximately(Quaternion.Angle(transform.rotation, targetRotation), 0f));

    which basically equals doing

    1. while(Quaternion.Angle(transform.rotation, targetRotation) > Mathf.Epsilon);"
英文:

As said there is a combination of a couple of issues here

  • First you potentially start a lot of concurrent ("simultaneously" happening) Coroutines! You should only start ONE and either make sure you don't start a second one or interrupt an already running one:

    1. private Coroutine currentRoutine;
    2. void Update()
    3. {
    4. // Use GetkeyDown to check of the first frame the key went down
    5. // rather than a continuous holding down of the button
    6. if (Input.GetKeyDown(KeyCode.Z))
    7. {
    8. Debug.Log("Raycast.");
    9. if (Physics.Raycast(transform.position, Vector3.down, 1.5f))
    10. {
    11. if (currentRoutine != null) StopCoroutine(currentRoutine);
    12. currentRoutine = StartCoroutine(Turn(cubeObject));
    13. }
    14. }
    15. }
    16. IEnumerator Turn(Transform cubeObject)
    17. {
    18. ...
    19. currentRoutine = null;
    20. }
  • Then you are mixing the global world space direction targetDirection and also world space transform.rotation with a local space transform.localEulerAngles. You want to either do all calculation in local or global space - don't mix!

  • Then I think the slowing down can be explained by the fact that your targetDirection might have an offset in the Y axis.

    You do RotateTowards which rotates into the target rotation on all three axes - but then throw away X/Z and only apply the Y component.

    => The closer your rotation comes to the final targetRotation (potentially never fully reaching it btw) the more you see the effect since the Y component of the rotation is already almost "correct" so it now tries to rotate more and more on the X/Z components - the ones you ignore.

    In order t solve this (and in general) I would recommend to stick to Quaternion as much as possible and rather already fix the target direction

    1. targetDirction.y = 0;
    2. targetRotation = Quaternion.LookRotation(targetDirection);
    3. transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
    4. yield return null;
  • And finally never use == for comparing float! You could rather use Quaternion == which uses a reduced precision of 1e-5

    1. while(transform.rotation != targetRotation);
    2. // and then make sure to end up with clean values
    3. transform.rotation = targetRotation;

    or alternatively if you want to stick to the angle an be more precise use Mathf.Approximately

    1. while(!Mathf.Apprximately(Quaternion.Angle(transform.rotation, targetRotation), 0f));

    which basically equals doing

    1. while(Quaternion.Angle(transform.rotation, targetRotation) > Mathf.Epsilon);

huangapple
  • 本文由 发表于 2023年7月13日 20:06:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/76679193.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定