Comments and answers for "Determining the torque needed to rotate an object to a given rotation"
http://answers.unity.com/questions/48836/determining-the-torque-needed-to-rotate-an-object.html
The latest comments and answers for the question "Determining the torque needed to rotate an object to a given rotation"Comment by phobos2077 on phobos2077's answer
http://answers.unity.com/comments/1552847/view.html
I don't understand why this answer got so many votes. Looks like nobody was able to make it actually work. Yes it may work at certain conditions (very high acceleration/rotation speed, small angles).
1. If your target angle is exact opposite of the current angle, there will be no rotation at all due to how cross product works.
2. The answer completely ignores the fact that to correctly arrive at given target rotation you need to start slowing down at some point. This will just continue going until the rotations meet and then inertia swings rigidbody to opposite direction. Hence the "wobbliness" people mention here.Thu, 13 Sep 2018 16:24:49 GMTphobos2077Comment by dansav on dansav's answer
http://answers.unity.com/comments/1447717/view.html
@hellcats
I'm trying to use your solution with rigidbodies connected by fixedjoints, but I'm not sure how to get the inertiaTensor or inertialRotation.
[https://answers.unity.com/questions/1447715/get-inertiatensor-of-point-masses.html][1]
[1]: https://answers.unity.com/questions/1447715/get-inertiatensor-of-point-masses.htmlThu, 28 Dec 2017 20:00:55 GMTdansavComment by zuraneur on zuraneur's answer
http://answers.unity.com/comments/1413341/view.html
Hi and thank you for the answer.
Can you explain and demonstrate why you state that we are in "some weird diagonal space" ?
I understand physics theory but I can't figure out the meaning of those two line :
Quaternion q = transform.rotation * rigidbody.inertiaTensorRotation;
T = q * Vector3.Scale(rigidbody.inertiaTensor, (Quaternion.Inverse(q) * w));Thu, 28 Sep 2017 15:34:24 GMTzuraneurAnswer by 00jknight
http://answers.unity.com/answers/1268110/view.html
I'm using a vastly different algorithm to achieve a target rotation via torque over multiple frames.
I found the effect to be quite pleasing to the eye when using a damp scale of around 0.1f.
Note that there can be occasional jitter around the target rotation, and some epsilon and snapping should be added.
if (doDamp)
{
// Find Axis that will take us from current rotation to Identity
Vector3 currentRotation = m_rigidBody.rotation.eulerAngles;
Vector3 deltaAngle = currentRotation - targetRotation;
Vector3 deltaAngleWrapped = new Vector3(Mathf.DeltaAngle(deltaAngle.x, 0.0f), Mathf.DeltaAngle(deltaAngle.y, 0.0f), Mathf.DeltaAngle(deltaAngle.z, 0.0f));
Vector3 velocityProjected = Vector3.Project(m_rigidBody.angularVelocity, deltaAngleWrapped);
Vector3 torque = deltaAngleWrapped - velocityProjected;
torque = torque * dampScale;
if (doDampLog) {
Vector3 currentRotationWrapAngle = new Vector3(Mathf.DeltaAngle(currentRotation.x, 0.0f), Mathf.DeltaAngle(currentRotation.y, 0.0f), Mathf.DeltaAngle(currentRotation.z, 0.0f));
Debug.Log("Torque: " + torque + " rotation: " + currentRotationWrapAngle + " torqueAngle: " + deltaAngleWrapped + " velocity on angle: " + velocityProjected);
}
m_rigidBody.AddTorque(torque);
}Mon, 07 Nov 2016 08:06:52 GMT00jknightAnswer by _OK_
http://answers.unity.com/answers/1246681/view.html
I stumbled on this thread looking for the answer - so here it is for anybody else who's looking
this example allows an object to rotate to face another object using torque only
change speed etc with a float rotationTorque and change the ridged body angular drag to suit
Vector3 targetPosition = transform.InverseTransformPoint(new Vector3(target.transform.position.x,target.transform.position.y, target.transform.position.z));
requiredTorqueX = (targetPosition.x / targetPosition.magnitude);
requiredTorqueY = (targetPosition.y / targetPosition.magnitude);
rbody.AddRelativeTorque(((rotationTorque) *requiredTorqueY),((rotationTorque) * requiredTorqueX) * -1 , 0f, ForceMode.Force);Wed, 21 Sep 2016 19:12:17 GMT_OK_Answer by cchacon
http://answers.unity.com/answers/1161367/view.html
How to the answer provided to take as input the amount of degrees that we want to rotate instead of a oldPoint and newPoint inputs.
I have a gameObject: objectHeld, which I need to rotate using torque by rotationY degrees. Below code works, but it is not the proper solution for rigidbody, when I use this, if the object is near the walls it can go thru the walls.
objectHeld.transform.localRotation = Quaternion.Euler(0.0f, rotationY, 0.0f);
Thanks!Sun, 27 Mar 2016 13:53:46 GMTcchaconComment by cchacon on cchacon's answer
http://answers.unity.com/comments/1161368/view.html
How to change the answer provided to take as input the amount of degrees that we want to rotate the object instead of a oldPoint and newPoint inputs.
I have a gameObject: objectHeld, which I need to rotate using torque by rotationY degrees. Below code works, but it is not the proper solution for rigidbody, when I use this, if the object is near the walls it can go thru the walls.
objectHeld.transform.localRotation = Quaternion.Euler(0.0f, rotationY, 0.0f);
Thanks!Sat, 26 Mar 2016 20:35:56 GMTcchaconComment by mar10 on mar10's answer
http://answers.unity.com/comments/927236/view.html
Hi **aleiby**
i used your solution & it worked for me, thru experiments i managed to control the lag. thanks for the solution.
**var rotSpeed=3.0f;**
Quaternion q = transform.rotation * rigidbody.inertiaTensorRotation;
var T = q * Vector3.Scale(rigidbody.inertiaTensor, (Quaternion.Inverse(q) * (w*rotSpeed)));
thisTransform.rigidbody.angularVelocity = T;
thisTransform.rigidbody.maxAngularVelocity = T.magnitude;Wed, 18 Mar 2015 15:50:14 GMTmar10Comment by BenTristem on BenTristem's answer
http://answers.unity.com/comments/901626/view.html
Thanks for brining some real physis to the table. I got confused about which thread I was replying to, and have updated my answer significantly below.Sun, 15 Feb 2015 08:03:30 GMTBenTristemComment by BenTristem on BenTristem's answer
http://answers.unity.com/comments/901616/view.html
You're quite right Alex, in my eagerness to share what I've done I confused this thread with another one over here... http://forum.unity3d.com/threads/is-this-a-bug-in-the-physics-engine-rotational-stability.259514
I'll modify it, thanks.Sun, 15 Feb 2015 07:33:17 GMTBenTristemComment by BenTristem on BenTristem's answer
http://answers.unity.com/comments/901487/view.html
That's right Alex, however I only looked at this briefly. I've attached my prototype above, and will be going through it and thinking about it much more carefully soon.Sun, 15 Feb 2015 00:08:10 GMTBenTristemComment by Alex_K98 on Alex_K98's answer
http://answers.unity.com/comments/901400/view.html
BenTristem, your object is set to Kinematic and this is somewhat differs from what was initially asked - use of AddTorque to make desired rotation. Btw, did you intentionally shifted center of mass?Sat, 14 Feb 2015 21:35:46 GMTAlex_K98Comment by Alex_K98 on Alex_K98's answer
http://answers.unity.com/comments/901359/view.html
BenTristem, by saying 'transform them into the frame of the rotating object' you mean 'transform to local object coordinate system'?Sat, 14 Feb 2015 19:48:36 GMTAlex_K98Comment by BenTristem on BenTristem's answer
http://answers.unity.com/comments/901350/view.html
Mine is smooth as hell, here's my full project so you can take a look.[link text][1]
[1]: /storage/temp/40734-flipping-phones.zipSat, 14 Feb 2015 19:36:06 GMTBenTristemComment by BenTristem on BenTristem's answer
http://answers.unity.com/comments/901337/view.html
The way the Unity engine reports inertia tensor is a bit "squiffy". It always deals with diagonalised tensors, and seems not to transform them into the frame of the rotating object.
I found that by translating to the frame of the rotating object, we get the required behaviour. I'll be adding another section to my game physics course in March 2015 to go through this step-by-step.
I've also updated my answer above to remove the link to my course.Sat, 14 Feb 2015 19:24:13 GMTBenTristemAnswer by Alex_K98
http://answers.unity.com/answers/901187/view.html
Gentlemen, what is the sense of multiplying by 'inertiaTensorRotation' when it is always W=1 and XYZ=0, at least this is what Debug.Log shows me?Sat, 14 Feb 2015 19:12:06 GMTAlex_K98Answer by BenTristem
http://answers.unity.com/answers/862808/view.html
**Hi Sol. To be clear you will actually need two torques, one to start the object rotating, and one to stop it at the desired rotation. Then you need to decide how you want it to accelerate / decelerate.**
It's a bit like asking what force you need to get to the moon: Not much if you don't mind waiting a long time then smashing into the surface. However if you want to get there in an hour, and to accelerate smoothly you could accelerate at around 13g for 30 minutes, turn-around, then decelerate at the same rate for another half an hour. Same with your torques and rotation. Does that make sense?
So **the magnitude of the torque(s) you need depends not only the angle change, but on the time you want it to take** (as well as the acceleration / deceleration strategy). The rotation won't be very "physically correct" if it instantaneously moves from one rotation to another, unless the object has no rotational inertia.
So we must involve time in this, and you need to decide how long you want your rotation to appear to take. On that basis you're not really working out a torque, but a torque at a given time into the "animation". **What's the method signature you're after, would this pattern do?...**
/// <summary>
/// Animates the rotation.
/// Performs a realistic torque-driven rotation from one stationary position to another.
/// Half the time is spent accelerating, the other half decelerating.
/// </summary>
/// <returns>The rotation at the elapsed time</returns>
Quaternion AnimateRotation (Vector3 from, Vector3 to, float timeElapsed, float totalTime) {
Quaternion currentRotation;
// I'll write the code if you're stuck
return currentRotation;
}
If your object is 3D, and rotating around more than one axis you'll need an inertia tensor rather than the simplified "moment of inertia" about one axis (which is just one element of a 3x3 matrix). In which case read-on. If you do go down the inertia tensor route, bear in mind...
1. Unity diagonalises them, so "intermediate axis" instability doesn't work properly (see solution below).
2. Adding a 3D collider(s) to a rigidbody gives you access to `rigidbody.inertiaTensor`, which is only approximate.
3. You'll have to do your multiplications carefully, again see below.
====
On a related note in case it helps, I got a cool simulation of a phone flipping according to the [parallel axis theorem][1], so have managed to add significant value to the existing physics engine. It seems that we need to do a transformation to the local coordinates of the flipping object, then calculate the rotation for things to work properly. **[I've attached a zipped Unity package with the working mini-project.][2]**
I'll be going through this step-by-step when I add a section to my new [game physics course][3] in March 2015. I'll be removing the cumbersome single and double underscore notation don't worry!
[1]: http://en.wikipedia.org/wiki/Parallel_axis_theorem
[2]: /storage/temp/40735-flipping-phones.zip
[3]: https://www.udemy.com/gamephysicsFri, 26 Dec 2014 22:51:53 GMTBenTristemAnswer by remigillig
http://answers.unity.com/answers/842192/view.html
Taking hellcats's answer and fixing the "wobbliness" reported by aleiby, I came up with this :
var x = Vector3.Cross(currentDir.normalized, newDir.normalized);
float theta = Mathf.Asin(x.magnitude);
var w = x.normalized * theta / Time.fixedDeltaTime;
var q = transform.rotation * rigidbody.inertiaTensorRotation;
var t = q * Vector3.Scale(rigidbody.inertiaTensor, Quaternion.Inverse(q) * w);
rigidbody.AddTorque(t - rigidbody.angularVelocity, ForceMode.Impulse);
The fix is to substract the current angular velocity. I hope this will be useful for other people googling around for this.
If you modify the inertia tensor yourself, the ForceMode can sometimes be changed to `VelocityChange`.Thu, 27 Nov 2014 20:23:09 GMTremigilligComment by zeiphon on zeiphon's answer
http://answers.unity.com/comments/440105/view.html
This is a great answer, but would you mind explaining how you came to the calculations for transforming the inertia tensor from its "weird diagonal space"? I wish to perform some other calculations with the inertia tensor and can't quite work out what's going on here.Wed, 17 Apr 2013 18:08:50 GMTzeiphonComment by aleiby on aleiby's answer
http://answers.unity.com/comments/362639/view.html
daterre - I've been trying to figure that out myself (expanding to full rotation), but am missing something.
I find if I do not factor in the inertialTensor, and simply assign rigidbody.angularVelocity = w; then I get the exact desired rotation in a single frame. Factoring in the inertialTensor makes it lag.
ForceMode.Impulse assumes you have included mass in your value, however, switching to ForceMode.VelocityChange didn't have any effect in my case since my object's mass is 1.
Combining angular velocities is the sticking point for me.
Here's a straightforward expansion upon hellcats' presentation above, which provides full alignment:
<pre><code>
void UpdateAngularVelocity(Quaternion desired)
{
var z = Vector3.Cross(transform.forward, desired * Vector3.forward);
var y = Vector3.Cross(transform.up, desired * Vector3.up);
var thetaZ = Mathf.Asin(z.magnitude);
var thetaY = Mathf.Asin(y.magnitude);
var dt = Time.fixedDeltaTime;
var wZ = z.normalized * (thetaZ / dt);
var wY = y.normalized * (thetaY / dt);
var q = transform.rotation * rigidbody.inertiaTensorRotation;
var T = q * Vector3.Scale(rigidbody.inertiaTensor, Quaternion.Inverse(q) * (wZ + wY));
// too wobbly
//rigidbody.AddTorque(T, ForceMode.VelocityChange);
// stable, but still laggy
rigidbody.angularVelocity = T;
rigidbody.maxAngularVelocity = T.magnitude;
}
</code></pre>
I'd like to understand where that lag is coming from. I'm concerned that simply adding the two angular velocities (wZ and wY) only works here because they are getting scaled down small enough by the intertiaTensor.
I would expect rigidbody.angularVelocity to be in object space, but that appears to not be the case?Tue, 11 Dec 2012 23:43:44 GMTaleibyComment by daterre on daterre's answer
http://answers.unity.com/comments/346989/view.html
This simple and clear solution worked right away in my scenario. How can it be expanded to include rotation around the Z axis as well? This is not currently taken into account. Would simply multiplying the 'q' quaternion by Quaternion.FromToRotation using the local current and destination rotations do the trick?Mon, 12 Nov 2012 14:26:58 GMTdaterreComment by Anxo on Anxo's answer
http://answers.unity.com/comments/329223/view.html
Wow.... What is the meaning of life!?!
All jokes aside, very interesting answer. I have been trying to implement it for a while but I am not getting anything out of T. I might be a little confused as to what "old point" and "new point" represent. I replaced them with the position vectors of the object that I wish to rotate and the object I wish to rotate towards. Em I doing this wrong? While I love your answer and this all sounds like exactly what I am looking for but this is beyond me so if you could explain what oldpoint and new point is. That would be great.
I am trying to rotate an object towards another object by torque. Picture a arrow at a bottom of the screen and a ball at the top, the arrow is pointing down and I wish to have it point at the ball but using torque to do so. I think that this is what your explanation goes over but I have not been able to get it to work so far.Mon, 08 Oct 2012 03:35:57 GMTAnxoAnswer by BinaryAgent
http://answers.unity.com/answers/187928/view.html
Hi hellcats, thanks for the detailed answer.
I am trying to implement your solution in my project and I am running into difficulty.
Here's my situation: [http://imageshack.us/photo/my-images/706/explanationp.png][1]
My object is travelling at a fixed speed on a heading in a 2-d coordinate space (z is always 0). On a mouse click I would like to apply a relative torque to turn it to a new heading. The rotational axis is always (0,0,1) - the z-axis.
The way I see it, there are two ways to rotate an object with a rigidbody: 1) switch on kinematics and do it manually or, 2) apply a rotational force. I'd like to use the second option.
My FixedUpdate function looks like this:
void FixedUpdate ()
{
rigidbody.AddRelativeTorque ( GetTorque(), ForceMode.VelocityChange);
rigidbody.AddRelativeForce (forwardDirection * Time.deltaTime, ForceMode.VelocityChange);
}
The GetTorque function is:
Vector3 GetTorque()
{
m_vHeading = rigidbody.velocity;
toTarget = (target.transform.position - gameObject.transform.position);
x = Vector3.Cross(m_vHeading.normalized, toTarget.normalized);
angle = Mathf.Asin(x.magnitude);
Vector3 w = x.normalized * angle / Time.fixedDeltaTime;
Quaternion q = gameObject.transform.rotation * rigidbody.inertiaTensorRotation;
Vector3 T = q * Vector3.Scale(rigidbody.inertiaTensor, (Quaternion.Inverse(q) * w));
return T;
}
Where **totarget** is an empty gameobject controlled by mouse move.
Can anybody tell me if I am on the right track? Am I over complicating something that should be simple. Any and all help is greatly appreciated.
Thanks,
BinaryX
[1]: http://imageshack.us/photo/my-images/706/explanationp.pngMon, 21 Nov 2011 12:27:17 GMTBinaryAgentComment by Joshua on Joshua's answer
http://answers.unity.com/comments/110932/view.html
o.O nice answer!Tue, 12 Apr 2011 17:57:45 GMTJoshuaComment by hellcats on hellcats's answer
http://answers.unity.com/comments/102412/view.html
UPDATE: turns out you can change the max. angular velocity in Edit->Project Settings->PhysicsFri, 25 Feb 2011 05:13:30 GMThellcatsAnswer by hellcats
http://answers.unity.com/answers/49388/view.html
<p>Fun question. Just like F = m a for linear forces, T = I alpha for angular forces. T is the torque, I is the inertia 3x3 tensor, and alpha is the angular acceleration. So basically your question amounts to finding an angular acceleration from a given change in rotation, and then multiplying that by I to get T.</p>
<p>Angular acceleration is a Vector3 whose direction is the axis of rotation and magnitude is rotational acc. in radians/sec^2. Since you already have two direction vectors (which need to be normalized), you can simply compute x = Vector3.Cross(oldPoint, newPoint) to get the required axis of rotation. This is the direction of alpha, but you still need the correct magnitude. We want radians/sec^2, so we need the angle between the two vectors. The magnitude of cross product is sin(theta) |v| |u|, since length of v and u are both 1, we just need Asin(x.magnitude). </p>
<p>Since you want to fully reach your newPoint in one frame, you can instead apply an impulse which is sort of like an instantaneous acceleration or change in velocity. So to summarize.</p>
<pre><code>Vector3 x = Vector3.Cross(oldPoint.normalized, newPoint.normalized);
float theta = Mathf.Asin(x.magnitude);
Vector3 w = x.normalized * theta / Time.fixedDeltaTime;
</code></pre>
<p>This gives us the desired change in angular velocity (w). Now we just multiply by the inertia tensor. Unfortunately this is in some weird diagonal space. It is easiest to transform w into this space, compute T, then transform T back to global coords.</p>
<pre><code>Quaternion q = transform.rotation * rigidbody.inertiaTensorRotation;
T = q * Vector3.Scale(rigidbody.inertiaTensor, (Quaternion.Inverse(q) * w));
</code></pre>
<p>Then just apply T to the rigidbody:</p>
<pre><code>rigidbody.AddTorque(T, ForceMode.Impulse)
</code></pre>
<p>NOTE: PhysX seems to limit the speed of rotation, so this actually only works if the amount you are rotating by isn't too large.</p>Fri, 25 Feb 2011 05:09:46 GMThellcats