【问题标题】:unity rotation issue on parent rotation关于父轮换的统一轮换问题
【发布时间】:2012-10-23 19:43:55
【问题描述】:

首先,这里是问题的视频: link to video,这里是package 这是层次结构的屏幕截图: GUN 是带有脚本(空游戏对象)的父级,暂停被丢弃到towerRotateObj,枪被丢弃在turretRotateObj。 Suspension 和 Gun 也是空的游戏对象。它们只是某种组对象 这里是代码:

public class WeaponMover : MonoBehaviour
{
    public Transform target;
    public GameObject turretRotateObj;
    public GameObject towerRotateObj;

    public float maxTowerRotationSpeed = 360.0f;
    public float maxTurretRotationSpeed = 360.0f;

    public float smoothFactorTower = 0.125f;
    public float smoothFactorTurret = 0.125f;

    public float maxTowerRotation = 130.0f;
    public float maxTurretRotation = 50.0f;

    private Vector3 m_newRotation;
    private Vector3 m_angles;
    private float m_minTowerAngle;
    private float m_maxTowerAngle;
    private float m_minTurretAngle;
    private float m_maxTurretAngle;
    private float m_velTower;
    private float m_velTurret;

    private bool m_isTransNecTower = false;
    private bool m_isTransNecTurret = false;

    // initialization
    void Start()
    {
       m_newRotation = Vector3.zero;
       m_angles = Vector3.zero;

       m_maxTowerAngle = towerRotateObj.transform.eulerAngles.y + maxTowerRotation/2;
       m_minTowerAngle = towerRotateObj.transform.eulerAngles.y - maxTowerRotation/2;

       m_maxTurretAngle = turretRotateObj.transform.eulerAngles.z + maxTurretRotation/2;
       m_minTurretAngle = turretRotateObj.transform.eulerAngles.z - maxTurretRotation/2;

       // check if rotation happens between 0/360
       // tower
       if(m_minTowerAngle <= 0.0f)
         m_minTowerAngle += 360.0f;

       if(m_maxTowerAngle >= 360.0f)
         m_maxTowerAngle -= 360.0f;

       if(m_minTowerAngle > m_maxTowerAngle)
         m_isTransNecTower = true;

       // turret
       if(m_minTurretAngle <= 0.0f)
         m_minTurretAngle += 360.0f;

       if(m_maxTurretAngle >= 360.0f)
         m_maxTurretAngle -= 360.0f;

       if(m_minTurretAngle > m_maxTurretAngle)
         m_isTransNecTurret = true;
    }

    void Update()
    {
       m_newRotation = Quaternion.LookRotation(target.position - towerRotateObj.transform.position).eulerAngles;
       m_angles = towerRotateObj.transform.rotation.eulerAngles;
       towerRotateObj.transform.rotation = Quaternion.Euler(m_angles.x,
         ClampAngle(Mathf.SmoothDampAngle(m_angles.y, 
          m_newRotation.y - 90.0f, 
          ref m_velTower, 
          smoothFactorTower, 
          maxTowerRotationSpeed), m_minTowerAngle, m_maxTowerAngle, m_isTransNecTower),
         m_angles.z);

       m_newRotation = Quaternion.LookRotation(target.position - turretRotateObj.transform.position).eulerAngles;
       m_angles = turretRotateObj.transform.rotation.eulerAngles;
       turretRotateObj.transform.rotation = Quaternion.Euler(m_angles.x,
         m_angles.y,
         ClampAngle(Mathf.SmoothDampAngle(m_angles.z, 
          -m_newRotation.x, 
          ref m_velTurret,
          smoothFactorTurret, 
          maxTurretRotationSpeed), m_minTurretAngle, maxTurretRotation, m_isTransNecTurret));
    }

    private float ClampAngle(float angle, float min, float max, bool isTranslationNecessary)
    {
       if(!isTranslationNecessary)
       {
         if(angle < min )
          return min;

         if(angle > max)
          return max;
       }
       else
       {
         if(angle > max && angle < min)
         {
          if(min - angle > angle - max)
              return max;
          else
              return min;
         }
       }

       return angle;
    }
}

所以,这是一个类似的设置,就像坦克的塔和炮一样...... 我已经发布了这个问题here,但似乎很少有人看到这个帖子......任何建议都值得赞赏!谢谢。

更新:

    m_newRotation = Quaternion.LookRotation(m_target.transform.position - towerRotateObj.transform.position).eulerAngles;
    m_newRotation.y -= 90f;
    m_angles = towerRotateObj.transform.rotation.eulerAngles;
    towerRotateObj.transform.rotation = Quaternion.Euler(m_angles.x, m_newRotation.y, m_angles.z);

    m_newRotation = Quaternion.LookRotation(m_target.transform.position - turretRotateObj.transform.position).eulerAngles;
    m_angles = turretRotateObj.transform.rotation.eulerAngles;
    turretRotateObj.transform.rotation = Quaternion.Euler(m_angles.x, m_angles.y, -m_newRotation.x);

问题依旧 :(

【问题讨论】:

  • 帖子太大了。不太可能有人会花费所有时间来理解问题是什么。两者都不会寻找答案。尝试仅使用提供的最相关代码提出详细问题。
  • 非常有帮助。如何缩短,如果我不知道问题是什么。如果你看一下视频,你就会发现问题,如果我写下发生了什么,那就需要更长的时间才能理解。

标签: c# rotation unity3d


【解决方案1】:

所以我的猜测,万向节锁,就像在另一个答案中所说的那样。但是,考虑到您将四元数传递给欧拉,我不确定我是否会尝试解决这个问题,反之亦然。如果我必须这样做,我不会像你那样做,因为使用四元数在对象之间进行父级处理等于非常头疼。

首先,当您为对象创建父对象时,您并没有使用该功能!这是 Unity 的一个非常可靠的功能。团结育儿:http://docs.unity3d.com/Documentation/ScriptReference/Transform-parent.html

您的每个炮塔对象仅在一个局部轴上旋转。 Unity 就是为解决这个问题而构建的:http://docs.unity3d.com/Documentation/ScriptReference/Transform-localRotation.html

当一个对象是另一个对象的父对象时,您可以在您想要的轴上局部旋转它。 Unity 自行处理整个矩阵变换。当您修改对象的全局旋转时,您基本上是在覆盖来自父级的转换。在这一点上,随着时间的推移,任何层次结构都很容易出现错误和不精确。

编辑:用你的包,我能写出我的意思:

public class WeaponMover : MonoBehaviour
{
    public GameObject boat;
    public GameObject turretRotateObj;
    public GameObject towerRotateObj;
    public GameObject target;

    private Vector3 lastDirection;

    // initialization
    void Start()
    {
        lastDirection = boat.transform.forward;
    }

    void Update()
    {
        // Find direction toward our target. Use turret as origin.
        Vector3 wantedDirection = target.transform.position - turretRotateObj.transform.position;
        // Rotate our last direction toward that new best direction. Change floats to make it move faster or slower.
        lastDirection = Vector3.RotateTowards(lastDirection, wantedDirection, 0.01f, 0.01f);

        // Find the direction local to the tower as the boat can move around!
        Vector3 towerDirection = boat.transform.InverseTransformDirection(lastDirection);
        // Remove unwanted axis
        towerDirection = new Vector3(-towerDirection.z, 0, towerDirection.x);
        towerDirection.Normalize();
        // Set local rotation
        towerRotateObj.transform.localRotation = Quaternion.LookRotation(towerDirection);

        // Find the direction local to the gun, as the tower may have rotated!
        Vector3 turretDirection = towerRotateObj.transform.InverseTransformDirection(lastDirection);
        // Remove unwanted axis.
        turretDirection = new Vector3(turretDirection.x, turretDirection.y, 0);
        turretDirection.Normalize();
        // Set local rotation
        turretRotateObj.transform.localRotation = Quaternion.LookRotation(turretDirection);
    }
}

注意:我不得不将枪管移动到 Z 轴而不是 X 轴,因为我很懒惰。所以如果你只复制粘贴这段代码,枪管会指向框架,但枪会正确地跟随目标。

由于现在是局部旋转,因此您可以将船旋转数年,而炮永远不会有任何偏移。

【讨论】:

  • file-upload.net/download-6745903/rotation.rar.html 这是包。你是什​​么意思:你没有在彼此之间养育你的对象?正如您在帖子图片上看到的那样,我正在使用育儿...
  • @immerhart:那你为什么要修改对象的全局旋转而不是使用“localRotation”并且只在一个轴上旋转对象?
  • @immerhart:给你,用你的包我能写出我的意思。我用修复代码更新了我的答案。
  • 它似乎有效。你能告诉我,我做错了什么吗?或者为什么会出现这种行为?我只是旋转了对象,不是本地的,但它工作正常。我只是不明白为什么会出现这种行为。
  • @immerhart:有几件事...首先,您不应该采用最后一个方向并尝试修改它,随着时间的推移,它必然会堆积不精确。通过拥有一个未绑定到任何转换空间的固定向量,您可以使其保持有效并具有稳定的使用参考。第二,除非您绝对确定这是您想要做的,否则您不应该在拥有父对象时修改全局旋转。我还没有遇到这种情况。第三,在欧拉和四元数之间跳转很少是一个好主意。四元数是万向节锁证明,但不是欧拉。我更喜欢坚持向量和矩阵变换。
【解决方案2】:

好吧,我不确定,但您似乎遇到了Gimbal Lock 问题。尽管您的计算是从四元数开始的,但从长远来看,对 Mathf.SmoothDampAngle 的两次调用可能是根本原因。

所以我建议首先删除所有平滑,然后,如果这被证明是罪魁祸首,则将这些方法替换为基于纯四元数的方法,例如 Quaternion.Slerp

【讨论】:

  • 另一点是,我一次只旋转一个轴,而不是同时旋转三个轴。那么,云台锁会发生吗?此外,正如您所说(在更新中),我只使用四元数..:|不知道。我数学不好
【解决方案3】:

从更新更改为LateUpdate 后,我无法重现您的问题。也许我没有像你那样颠簸旋转,但我认为小玩意儿的旋转在炮塔旋转之前和之后都被应用了,并且错误正在累积。

【讨论】:

  • 如果是这样,游戏运行时也会累积错误,并且任何老化测试都会显示错误。构建代码时应该考虑到偏移量或错误永远不会随着时间的推移而累积。
  • 这就是切换到 LateUpdate 的作用。
  • 无论如何它都会在 LateUpdate 上完成,因为他正在修改以前的全局轮换。这样做肯定会产生不精确性,因为您在每一帧上堆叠浮点不精确性并且您永远无法摆脱它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-16
  • 1970-01-01
  • 2013-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多