Unity物体旋转的值错误

6
我的问题是,我希望能够旋转一个圆柱9次。360/9等于40,因此我所需要做的就是旋转9次,每次旋转40度。然而,当我第一次旋转圆柱时,它不会按照40度旋转,而只会旋转39.99度。其他旋转也会出现这种情况。
我是通过以下方式进行旋转的:
if(Input.GetKeyUp("i"))
      transform.GetChild(m_Section).Rotate(0,40.0f,0);

我使用的是Unity 3.4版本,不是专业版,并且我在使用C#进行编码。

由于我刚开始学习Unity,所以非常需要帮助。

2个回答

1

Unity3D在一个相当抽象的数学表示中存储旋转,称为四元数。从欧拉角(在Unity编辑器中看到的)到四元数的转换涉及一系列三角函数,因此对于简单的浮点类型来说容易出现舍入误差。

为了解决这个问题,在您的情况下,我建议在开始旋转之前存储初始的四元数对象,并在过程结束时设置它。以下是一些伪代码:

public class RotationController : MonoBehaviour {
    Quaternion rotationAtStart;
    int numOfRotations = 0;

    void rotate () {
        numOfRotations++;
        if (numOfRotations == 1) {
            rotationAtStart = transform.rotation;
        } else if (numOfRotations < 9) {
            transform.Rotate (new Vector3 (0,40.0f,0));
        } else if (numOfRotations == 9) {
            transform.rotation = rotationAtStart;
        }
    }
    void Update () {
        if (numOfRotations < 9) {
            rotate ();
        }
    }
 }   

360°的特殊情况使得这种方法更加稳定。对于小于360°的情况,您必须接受小的舍入误差。对于这种情况,我建议使用Quaternion.RotateTowards计算目标四元数,并在最后一步类比于360°的情况下设置它。

对于您来说,另一个有用的工具是Animations。您可以将动画定义为平滑或离散步骤,并在按下“i”时调用GameObject.animation.Play("MyRotation")。在最后使用一个AnimationEvent来获取动画终止的信息。

最后,Mathf包含了一个Approximately函数,用于处理浮点数精度问题。


如果我使用您建议的动画,那么它会改变对象的本地轴吗?还是只会旋转对象? - Dave
你要动画化游戏对象转换的成员。transform.rotation 是欧拉角。 - Kay
谢谢你的帮助。这更像是绕过问题的方式而不是解决方案。我无法说 if(transform.eulerAngles.y == 40.0f) ,因为即使旋转朝向给出了更准确的结果,仍然会存在误差。我还没有尝试过动画的建议,但我现在会去尝试一下。 - Dave

0

看一下Kungfooman这篇帖子中的回答,他描述了旋转超过90度或者在90度和270度时的问题。他提供了一个扩展程序,它将始终计算出你想设置的四元数的正确挂件。在这里看一下:

using UnityEngine;
using System.Collections;

public class ExtensionVector3 : MonoBehaviour {

    public static float CalculateEulerSafeX(float x){
        if( x > -90 && x <= 90 ){
            return x;
        }

        if( x > 0 ){
            x -= 180;
        } else {
            x += 180;
        }
        return x;
    }

    public static Vector3 EulerSafeX(Vector3 eulerAngles){
        eulerAngles.x = CalculateEulerSafeX(eulerAngles.x);
        return eulerAngles;
    }
}

我是这样使用它的:

Quaternion newQuat = m_directionalLight.transform.rotation;
Vector3 nL = new Vector3(ExtensionVector3.CalculateEulerSafeX(xNewValueLight), 
                         0, 
                         0);
newQuat.eulerAngles = nL;

m_directionalLight.transform.rotation = 
     Quaternion.Lerp(m_directionalLight.transform.rotation, 
                     newQuat, 
                     Time.deltaTime);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接