Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

[SOLVED] Rigidbody physics addtorque to aim at target with lerp

Discussion in 'Physics' started by DeadAz69, Mar 28, 2020.

  1. DeadAz69

    DeadAz69

    Joined:
    Aug 25, 2019
    Posts:
    13
    Good day.

    I'm struggling getting my spaceship to aim at a target without wildly over compensating when adding torque.

    The ship ends up wiggling like a fish as it tries to maintain it's target, but is never able to directly aim at it's target.

    Is there a way to smooth the torque so it does not wiggle? (Video
    )

    I'm using this function:


    public Transform target;
    public float force = 0.1f;

    void LockOnTarget() // Face target direction
    {
    // find distance between object and target
    Vector3 targetDelta = target.position - transform.position;

    //get the angle between transform.up and target delta
    float angleDiff = Vector3.Angle(transform.up, targetDelta);

    // get its cross product, which is the axis of rotation to
    // get from one vector to the other
    Vector3 cross = Vector3.Cross(transform.up, targetDelta);

    // apply torque along that axis according to the magnitude of the angle.
    GetComponent<Rigidbody>().AddTorque(cross * angleDiff * force);

    }
     
  2. AlTheSlacker

    AlTheSlacker

    Joined:
    Jun 12, 2017
    Posts:
    326
    I've not tried experimenting with rigid body forces much in Unity, but I believe you may be better off looking at https://docs.unity3d.com/ScriptReference/Rigidbody.MoveRotation.html

    I assume the oscillation you are seeing is simply an under-damped response to the inputs - if you imagine your ship in space, free from any external forces: As soon as you apply a torque to it there will be a corresponding angular acceleration, until an opposing torque is applied - angular velocity will change depending on the torque / time profile used. The chances of you applying an equal and opposite torque at the correct time is quite unlikely without some significant control logic.

    I hope that helps, sorry I cannot add more. I did take a look at the ForceMode options in case there was some sort of cheat, but I don't think there is. Perhaps someone more knowledgeable has a simpler answer.
     
    DeadAz69 likes this.
  3. tjmaul

    tjmaul

    Joined:
    Aug 29, 2018
    Posts:
    464
    Control logic shouldn’t be so hard for this. Try to also add a force counteracting the angularVelocity:

    rb.AddTorque(-rb.angularVelocity * factor)

    The factor will need some fiddling and there is a spring/damper ratio that will not overshoot.. but that I‘d have to look up.

    alternatively you can also just increase angular damping on the rigidbody in the inspector
     
    DeadAz69 likes this.
  4. DeadAz69

    DeadAz69

    Joined:
    Aug 25, 2019
    Posts:
    13
    Wow! I can't believe how simple that solution is. Thank you
    @tjmaul !
     
  5. felres

    felres

    Joined:
    Mar 6, 2018
    Posts:
    1
    For anyone that happens to stumble upon this thread Ive made a method that replicated this for 2D rigidbodies:

    Code (CSharp):
    1. /// <summary>
    2.     /// Use AddTorque() to face a specific angle. For 2D physiscs. Should be used in every FixedUpdate() frame.
    3.     /// </summary>
    4.     /// <param name="currentVec"> vector representing the direction we are currently pointing at. (transform.right) </param>
    5.     /// <param name="targetVec"> vector representing the direction we want to point at. </param>
    6.     /// <param name="rb"> Rigidbody to affect. </param>
    7.     /// <param name="maxTorque"> Max torque to apply. </param>
    8.     /// <param name="torqueDampFactor"> Damping factor to avoid undershooting. </param>
    9.     /// <param name="offsetForgive"> Stop applying force when the angles are within this threshold (default 0). </param>
    10.     public static void TorqueTo(Vector3 currentVec, Vector3 targetVec, Rigidbody2D rb, float maxTorque, float torqueDampFactor, float offsetForgive = 0)
    11.     {
    12.         float targetAngle = FindAngle(targetVec);
    13.         float currentAngle = FindAngle(currentVec);
    14.         float angleDifference = AngleDifference(targetAngle, currentAngle);
    15.         if (Mathf.Abs(angleDifference) < offsetForgive) return;
    16.  
    17.         float torqueToApply = maxTorque * angleDifference / 180f;
    18.         torqueToApply -= rb.angularVelocity * torqueDampFactor;
    19.         rb.AddTorque(torqueToApply, ForceMode2D.Force);
    20.     }
    This method does use other "helper" methods, to make my life easier in general. Here they are:

    Code (CSharp):
    1. public static float AngleDifference(float a, float b)
    2.     {
    3.         return ((((a - b) % 360f) + 540f) % 360f) - 180f;
    4.     }

    Code (CSharp):
    1. /// <summary>
    2.     /// Returns the angle (in degrees) in which the vector is pointing.
    3.     /// </summary>
    4.     /// <returns>0-360 angle </returns>
    5.     public static float FindAngle(Vector2 vec)
    6.     {
    7.         return FindAngle(vec.x, vec.y);
    8.     }
    9.     public static float FindAngle(float x, float y)
    10.     {
    11.         float value = (float)((System.Math.Atan2(y, x) / System.Math.PI) * 180);
    12.         if (value < 0) value += 360f;
    13.         return value;
    14.     }
     
  6. p3tri1ell0

    p3tri1ell0

    Joined:
    Sep 7, 2021
    Posts:
    2
    your script didn't work for me but I managed to do:


    Code (CSharp):
    1.  private void Update_PhysicsModel()
    2.     {
    3.         for (int i = 0; i < Physics_Model.Length; i++)
    4.         {
    5.             float Difference = GetDiff(Target_Model[i].transform.eulerAngles.z, Physics_Model[i].transform.eulerAngles.z);
    6.             float Distance = Mathf.Abs(Difference);
    7.  
    8.             TorqueLerp(Physics_Model[i], Difference, Distance);
    9.         }
    10.     }
    11.  
    12.     private static float GetDiff(float A, float B)
    13.     {
    14.         A = Mathf.Repeat(A + 180, 360) - 180;
    15.         B = Mathf.Repeat(B + 180, 360) - 180;
    16.         return (A - B);
    17.     }
    18.  
    19.     private static void TorqueLerp(Rigidbody2D rb, float Diff, float Dist)
    20.     {
    21.         float Force = Diff * (Dist / 2);
    22.         rb.angularVelocity = Force;
    23.     }
     
    Last edited: Jul 10, 2022