C# 关于父旋转的统一旋转问题

C# 关于父旋转的统一旋转问题,c#,rotation,unity3d,C#,Rotation,Unity3d,首先,这里是问题的视频: ,这是 这是一个层次结构的截图: 枪是带有脚本(空游戏对象)的父对象,暂停被放置到ToErrortateObj上,枪被放置在炮塔旋转BJ上。悬挂和枪也是空的游戏对象。它们只是某种群体对象 下面是代码: public class WeaponMover : MonoBehaviour { public Transform target; public GameObject turretRotateObj; public GameObject tow

首先,这里是问题的视频: ,这是 这是一个层次结构的截图: 枪是带有脚本(空游戏对象)的父对象,暂停被放置到
ToErrortateObj
上,枪被放置在
炮塔旋转BJ
上。悬挂和枪也是空的游戏对象。它们只是某种群体对象 下面是代码:

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;
    }
}

问题依然存在:(

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


因此,我建议首先删除所有平滑,然后,如果这是罪魁祸首,用纯四元数方法替换这些方法,如。

所以我猜,万向节锁,如另一个答案中所述。但是,我不确定我是否会尝试修复它,考虑到你正在将四元数传递给euler,反之亦然。如果我必须这样做的话它,我不会像你那样做,因为在对象之间使用四元数作为父子关系是相当令人头痛的

首先,当您为对象设置家长时,您没有使用该功能!这是Unity非常可靠的功能。Unity家长:

每个炮塔对象只在一个局部轴上旋转。Unity就是为了处理这个问题而构建的:

当一个对象成为另一个对象的父对象时,可以在所需的轴上局部旋转该对象。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轴,因为我很懒。因此,如果你只复制粘贴此代码,枪管将指向帧,但枪管将正确跟随目标


由于旋转现在是局部的,你可以使飞船旋转数年,而火炮将永远不会得到任何偏移。

在从更新更改为后,我无法重现你的问题。也许我没有像你那样反复旋转,但我认为小发明的旋转是在炮塔旋转之前和之后应用的,并且误差不断累积。

这篇文章太大了。不太可能有人会花所有的时间去理解问题是什么。两人都不会寻找答案。试着问一个只提供最相关代码的详细问题。非常有用。如果我不知道问题是什么,如何缩短。如果你看了视频,你就会看到问题,如果我愿意的话d写下发生了什么,需要更长的时间才能理解。另一点是,我一次只旋转一个轴,而不是同时旋转所有三个轴。那么,万向节锁定会发生吗?此外,我只使用四元数,正如你所说(在更新中)..:|不,我不知道。我数学不好。这是软件包。你的意思是:你不是在彼此之间为你的对象设置家长吗?正如你在帖子的图片上看到的,我在使用家长…@immerhart:那么你为什么要修改对象的全局旋转而不是使用“局部旋转”而且只在一个轴上旋转对象?@immerhart:给你,我用你的软件包写下了我的意思。我用修复代码更新了我的答案。这似乎有效。你能告诉我,我做错了什么?或者为什么会出现这种行为吗?我只是旋转了对象,不是局部的,但它工作正常。我只是不明白为什么会出现这种行为。@immerh艺术:有几件事……首先,你不应该选择最后一个方向并试图修改它,它必然会随着时间推移叠加不精确性。通过拥有一个不绑定到任何变换空间的固定向量,你可以保持它的有效性并有一个稳定的引用可供使用。第二,你不应该在拥有父对象时修改全局旋转,除非你是ab绝对确定这就是你想要做的。我还没有遇到这种情况。第三,在euler和四元数之间跳跃很少是个好主意。四元数是框架锁的证明,但不是euler。我更喜欢使用向量和矩阵变换。如果是这样,在游戏运行时错误也会累积,并且任何ag都会看到错误ing测试。代码应该考虑到偏移量或错误永远不会随着时间累积。这就是切换到LateUpdate所做的。它在LateUpdate上无论如何都会这样做,因为他正在修改以前的全局旋转。这样做肯定会有不精确性,因为你在每个帧上叠加浮点不精确性,你永远不会得到摆脱它。
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);
    }
}