3

最初に、ここに問題のビデオ: ビデオへのリンク、ここにパッケージ 、およびここに階層のスクリーンショットがあります: ここに画像の説明を入力 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;
    }
}

だから、戦車の塔と銃のような同様の設定です....私はすでにその質問をここに投稿しましたが、投稿を見た人はほとんどいないようです...アドバイスをいただければ幸いです! ありがとう。

アップデート:

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

問題は同じままです:(

4

3 に答える 3

3

私の推測では、他の回答で述べたように、ジンバルロックです。ただし、クォータニオンをオイラーに、またはその逆に渡していることを考えると、それを修正しようとするかどうかはわかりません。オブジェクト間の親子関係にクォータニオンを使用することは大きな頭痛の種であるため、私がやらなければならない場合、あなたのようにはしません。

まず、オブジェクトをペアレンティングしている間は、その機能を使用していません! これは Unity の非常に堅実な機能です。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);
    }
}

注: 怠け者だったので、銃のバレルを X 軸ではなく Z 軸に移動する必要がありました。したがって、このコードをコピーして貼り付けるだけの場合、バレルはフレームの方を向いていますが、銃はターゲットに正しく追従します。

回転がローカルになったので、何年も船を回転させることができ、銃がオフセットすることはありません.

于 2012-10-28T13:45:57.260 に答える
1

よくわかりませんが、ジンバル ロックの問題が発生しているようです。計算はクォータニオンから始まりますがMathf.SmoothDampAngle、長期的には への 2 つの呼び出しが根本的な原因である可能性があります。

したがって、最初にすべてのスムージングを削除してから、これが原因であることが判明した場合は、これらのメソッドをQuaternion.Slerpのような純粋な四元数ベースのメソッドに置き換えることをお勧めします。

于 2012-10-24T17:21:54.090 に答える
0

Update からLateUpdateに変更した後、問題を再現できません。多分私はあなたのように回転をスラッシングしていませんが、タレットの回転の前後にギズモの回転が適用されていて、エラーが蓄積していたと思います.

于 2012-10-29T07:17:04.383 に答える