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
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Use torque to match rotation to a second object

Discussion in 'Physics' started by Gnimmel, Dec 15, 2016.

  1. Gnimmel

    Gnimmel

    Joined:
    Apr 21, 2010
    Posts:
    358
    I have two objects, one is rigid body and the other isn't.

    I would like the rigid body to rotate until it matches the same rotation as the second object by using forces.

    I was hoping it would work like translation where I can take the target rotation and subtract the present rotation to get the forces needed, but this isn't the case.

    Can anyone point me in the right direction?
     
  2. Dennis_eA

    Dennis_eA

    Joined:
    Jan 17, 2011
    Posts:
    375
  3. Gnimmel

    Gnimmel

    Joined:
    Apr 21, 2010
    Posts:
    358
    Thanks for the reply.

    I need to go over that thread a little more and look at the script, but I like the idea of a PID controller.
     
  4. Dennis_eA

    Dennis_eA

    Joined:
    Jan 17, 2011
    Posts:
    375
    I didn't download anything for now, but in one of the threads you find over google when searching for PID there is a nice little spaceship shaped like a 'C' or 'V'. I remember that this particular project had some nice clean understandable code.
     
  5. Tehelee

    Tehelee

    Joined:
    Jan 26, 2013
    Posts:
    12
    After scouring the forums, I ended up figuring it out myself. The force value is equivalent to what you'd use on a regular Spring Joint.

    Code (CSharp):
    1. [RequireComponent(typeof(Rigidbody))]
    2. public class SpringRotation : MonoBehaviour
    3. {
    4.     public float force = 10f;
    5.  
    6.     public Rigidbody target;
    7.     private new Rigidbody rigidbody;
    8.  
    9.     private Vector3 torque;
    10.  
    11.     private void Awake()
    12.     {
    13.         this.rigidbody = this.GetComponent<Rigidbody>();
    14.     }
    15.  
    16.     private void FixedUpdate()
    17.     {
    18.         if ((null == target) || !target) return;
    19.        
    20.         // Determine Quaternion 'difference'
    21.         // The conversion to euler demands we check each axis
    22.         Vector3 torqueF = OrientTorque(Quaternion.FromToRotation(this.transform.forward, this.target.transform.forward).eulerAngles);
    23.         Vector3 torqueR = OrientTorque(Quaternion.FromToRotation(this.transform.right, this.target.transform.right).eulerAngles);
    24.         Vector3 torqueU = OrientTorque(Quaternion.FromToRotation(this.transform.up, this.target.transform.up).eulerAngles);
    25.  
    26.         float magF = torqueF.magnitude;
    27.         float magR = torqueR.magnitude;
    28.         float magU = torqueU.magnitude;
    29.  
    30.         // Here we pick the axis with the least amount of rotation to use as our torque.
    31.         this.torque = magF < magR ? (magF < magU ? torqueF : torqueU) : (magR < magU ? torqueR : torqueU);
    32.            
    33.         this.rigidbody.AddTorque(this.torque * Time.fixedDeltaTime * force);
    34.     }
    35.  
    36.     private Vector3 OrientTorque(Vector3 torque)
    37.     {
    38.         // Quaternion's Euler conversion results in (0-360)
    39.         // For torque, we need -180 to 180.
    40.  
    41.         return new Vector3
    42.         (
    43.             torque.x > 180f ? 180f - torque.x : torque.x,
    44.             torque.y > 180f ? 180f - torque.y : torque.y,
    45.             torque.z > 180f ? 180f - torque.z : torque.z
    46.         );
    47.     }
    48. }
     
  6. mite51

    mite51

    Joined:
    Jun 25, 2015
    Posts:
    23
    I had a similar need... but the class above wasn't working so well.. Here's what I ended up making
    //---------------------------------------------------------
    using UnityEngine;

    [RequireComponent(typeof(Rigidbody))]
    public class SpringRotation : MonoBehaviour
    {
    public bool active = true;

    public Rigidbody target;
    private new Rigidbody rigidbody;

    private Vector3 torque;

    private void Awake()
    {
    this.rigidbody = this.GetComponent<Rigidbody>();
    }

    private void OnGUI()
    {
    Quaternion diff = Quaternion.Inverse(rigidbody.rotation) * target.rotation;
    Vector3 eulers = OrientTorque(diff.eulerAngles);
    GUI.TextArea(new Rect(50, 50, 200, 50), eulers.ToString());
    }

    private void FixedUpdate()
    {
    if (active)
    {
    //Find the rotation difference in eulers
    Quaternion diff = Quaternion.Inverse(rigidbody.rotation) * target.rotation;
    Vector3 eulers = OrientTorque(diff.eulerAngles);
    Vector3 torque = eulers;
    //put the torque back in body space
    torque = rigidbody.rotation * torque;

    //just zero out the current angularVelocity so it doesnt interfere
    rigidbody.angularVelocity = Vector3.zero;

    rigidbody.AddTorque(torque, ForceMode.VelocityChange);
    }
    }

    private Vector3 OrientTorque(Vector3 torque)
    {
    // Quaternion's Euler conversion results in (0-360)
    // For torque, we need -180 to 180.

    return new Vector3
    (
    torque.x > 180f ? torque.x - 360f : torque.x,
    torque.y > 180f ? torque.y - 360f : torque.y,
    torque.z > 180f ? torque.z - 360f : torque.z
    );
    }
    }
     
    MagiJedi, Rujash and God-at-play like this.
  7. jimmying

    jimmying

    Joined:
    Sep 20, 2017
    Posts:
    105
    If you're having an issue where it's rotating quite slowly/linearly (as if there is some sort of drag), for the rigidbody, increase the maxAngularVelocity.
     
    MagiJedi likes this.
  8. p3tri1ell0

    p3tri1ell0

    Joined:
    Sep 7, 2021
    Posts:
    2
    upload_2022-7-10_2-49-24.png 2
    For rigidbody2d use this
     
  9. Gullie667

    Gullie667

    Joined:
    Apr 21, 2021
    Posts:
    17
    This works quite well. Here is the same thing on a spring so that it can bump other objects:

    Code (CSharp):
    1. private void _SetRotationForce(Rigidbody rigidbody) {
    2.  
    3.     static float _GetSpringForce(float mass, float springTravel, float velocity, float positionSpringStrength, float positionSpringDamper) {
    4.         // Find the magnitude of the dampened spring force
    5.         return (springTravel * positionSpringStrength * mass) - (velocity * positionSpringDamper * mass);
    6.     }
    7.  
    8.     //Find the rotation difference in eulers
    9.     Quaternion diff = Quaternion.Inverse(rigidbody.rotation) * m_currentGoalRotation;
    10.     Vector3 eulers = OrientTorque(diff.eulerAngles);
    11.  
    12.     //Find the rotation difference in eulers
    13.     Vector3 torque = eulers;
    14.     //put the torque back in body space
    15.     torque = rigidbody.rotation * torque;
    16.  
    17.     /*
    18.     //You could rescale the torque here but it will only be out of range at extreme offsets / momentarily. (Replace torque.x.y.z)
    19.     Vector3 springTravel = OrientTorque(torque);
    20.     */
    21.  
    22.    
    23.     torque = new Vector3(
    24.         _GetSpringForce(rigidbody.mass, torque.x, rigidbody.angularVelocity.x, RotationSpringStrength, RotationSpringDamper),
    25.         _GetSpringForce(rigidbody.mass, torque.y, rigidbody.angularVelocity.y, RotationSpringStrength, RotationSpringDamper),
    26.         _GetSpringForce(rigidbody.mass, torque.z, rigidbody.angularVelocity.z, RotationSpringStrength, RotationSpringDamper)
    27.     );
    28.  
    29.     _AddRotationForce(rigidbody, torque);
    30.  
    31. }
    32.  
    33. private void _AddRotationForce(Rigidbody rigidbody, Vector3 torque) {
    34.     rigidbody.AddTorque(torque);
    35. }
    36.  
    37. private Vector3 OrientTorque(Vector3 torque)
    38. {
    39.     // Quaternion's Euler conversion results in (0-360)
    40.     // For torque, we need -180 to 180.
    41.  
    42.     return new Vector3
    43.     (
    44.         torque.x > 180f ? torque.x - 360f : torque.x,
    45.         torque.y > 180f ? torque.y - 360f : torque.y,
    46.         torque.z > 180f ? torque.z - 360f : torque.z
    47.     );
    48. }