- Home /
AddTorque to rotate rigidbody to look at a point
So, I have a RigidBody that rotates around the Y axis only in an RTS style game. I need a script that will AddTorque to the rigid body in the right direction (clockwise / anticlockwise) until it is pointing at the point given.. or close to it. Kind of like the LookAt method, but using forces and therefore smooth.
Thanks - James
Thats little old but is there a reason for using time.deltaTime in FixedUpdate?
Answer by ungood · Feb 22, 2013 at 07:22 AM
I'm a bit late, but I wanted to add an answer for future googlers:
This is doable with AddTorque. What you need is two PIDs that operate on Vector3s instead of floats. One PID attempts to steer the up vector of your object towards the desired heading, while the other PID attempts to drive the angular velocity to zero.
First a simple PID (which I "borrowed" from somewhere and modified for Vector3s):
public class VectorPid
{
public float pFactor, iFactor, dFactor;
private Vector3 integral;
private Vector3 lastError;
public VectorPid(float pFactor, float iFactor, float dFactor)
{
this.pFactor = pFactor;
this.iFactor = iFactor;
this.dFactor = dFactor;
}
public Vector3 Update(Vector3 currentError, float timeFrame)
{
integral += currentError * timeFrame;
var deriv = (currentError - lastError) / timeFrame;
lastError = currentError;
return currentError * pFactor
+ integral * iFactor
+ deriv * dFactor;
}
}
And now the behavior:
public class LookAtController : MonoBehaviour
{
private readonly VectorPid angularVelocityController = new VectorPid(33.7766f, 0, 0.2553191f);
private readonly VectorPid headingController = new VectorPid(9.244681f, 0, 0.06382979f);
public Transform target;
public void FixedUpdate ()
{
var angularVelocityError = rigidbody.angularVelocity * -1;
Debug.DrawRay(transform.position, rigidbody.angularVelocity * 10, Color.black);
var angularVelocityCorrection = angularVelocityController.Update(angularVelocityError, Time.deltaTime);
Debug.DrawRay(transform.position, angularVelocityCorrection, Color.green);
rigidbody.AddTorque(angularVelocityCorrection);
var desiredHeading = target.position - transform.position;
Debug.DrawRay(transform.position, desiredHeading, Color.magenta);
var currentHeading = transform.up;
Debug.DrawRay(transform.position, currentHeading * 15, Color.blue);
var headingError = Vector3.Cross(currentHeading, desiredHeading);
var headingCorrection = headingController.Update(headingError, Time.deltaTime);
rigidbody.AddTorque(headingCorrection);
}
}
I realise this a pretty old question but I've just found another case on a different project where I need to do a similar thing. Your answer was really helpful but could you please explain what pFactor, iFactor and dFactor actually do and how they effect the behaviour?
Is there a way I could apply this but also limit the torque that the rigidbody can apply to itself in each axis? $$anonymous$$aybe it's just as simple as using $$anonymous$$athf.$$anonymous$$in() to limit it when calling AddTorque?
Thanks!
PID controllers are not that hard to understand, however if you never heard of them, i suggest to read ;)
@jt78 - The best way to learn about what P, I, and D do is to read about PID controllers, and play with the values a bit with a demo, it'll give you a better feel for how they interact.
As for clamping the torque, it's a bit harder than $$anonymous$$athf.$$anonymous$$, but you're on the right track. There exists a method on Vector3 that does what you want: http://docs.unity3d.com/Documentation/ScriptReference/Vector3.Clamp$$anonymous$$agnitude.html
how would one modify this so it only attempts to rotate the object on a single axis? ie, for a top down shooter.
@$$anonymous$$_$$anonymous$$98 In case you're still wondering, AddTorque can get multiple values at once. When you use AddTorque, you're not overwriting the previous Vector3 value, but simply add on it. For example, if you use Rigidbody.AddTorque(3,3,3); and then immediatly use Rigidbody.AddTorque(-3,-3,3);, you will end with an equivalent of Rigidbody.AddTorque(0,0,6);
The reason why there're 2 AddTorque in this PID is because it calculate the angularVelocityCorrection, then add its value to the torque. This allow the rigidbody to follow a curve based on its velocity (movement force). If you check the moving item from the Scene tab within Unity, you can see the result of this from the green line. Then based on the rigidbody's orientation, it get the "perfect" orientation values toward the target (magenta line). Then it calculate the orientation and "thrusting" (or forward velocity if you prefer) power so that the rigidbody turns and moves toward the target. (The heading is the blue line)
In other words, the first AddTorque add the force related to the past and current movements(velocity) while the second torque add the required correction onto the rigidbody. If we were to illustrate it with a rocket, the first AddTorque is like the gravity and force of movement of a rocket while the second AddTorque is its guiding and propulsion system.
Answer by aldonaletto · Dec 27, 2011 at 01:03 AM
This isn't so easy as you think: you would need a PID controller to rotate the object using torque, and it's a hard job in Unity because you can't have a reliable angle information to use as feedback. Take a look at this question, about a simulated controller. It simulates the torque effects, accelerating the object to the target angle and decelerating it to stop at the desired angle. It's physically correct, but doesn't use AddTorque to keep track of the current object rotation.