How to get a Vector3 rotation between two Quaternions - c#

I'm writing a script which rotates a Rigidbody using a Configurable Joint. I've got the targetRotation figured out, but now I'm struggling with targetAngularVelocity, which should help me avoid wobbliness if set correctly.
targetAngularVelocity is defined like this in the documantation: "This is a Vector3. It defines the desired angular velocity that the joint should rotate into". The problem is that I don't know how to get this Vector3 based on two Quaternions - current rotation of the object and the target rotation.
Am I not understanding it correctly? Is there a function that returns a rotation vector based on two Quaternions?

So mathematically a Quaternion represents the orientation of a rigid body. Consider the forward problem first, and see how the orientation q_1 transforms to another orientation q_2 after a rotational velocity ω is applied for t time.
Mathematically the rotation vector has a magnitude ω and a direction k such that ω = ω* k
This is done with quaternion multiplication as
q_2 = q_ω * q_1
Where q_ω represents a rotation about the axis of k of an angle θ=ω*t.
In reverse, you need to find q_ω with
var q_ω = q_2 * Quaternion.Inverse(q_1);
and extract the rotation axis and angle
q_ω.ToAngleAxis(out float angle, out Vector3 axis);
and compose the rotational velocity vector, that corresponds to this transformation in time seconds.
var ω = (angle/time)*axis;

Related

Unity3d Quaternion LookRotation not returning proper value

I wanted a projectile to look at the target object, to do that I am using Quaternion LookRotation as below
targetRotation = Quaternion.LookRotation(targetPosition - projectile.transform.position);
if(targetRotation.eulerAngles.magnitude <= 60)
projectile.transform.rotation = targetRotation;
here I have put if condition to make it more realistic turn towards target, otherwise projectile should not turn if its more 60 degree turn.
now as in below image, we can see that the target object in not more than at 60 degree angle, but still while debugging I am getting 328 as targetRotation.eulerAngles.magnitude, which is getting the if condition failed and projectile is not rotating towards the target object.
Quaternion.LookRotation(targetPosition - projectile.transform.position) means "Give me a quaternion that represents a rotation of a vector from up towards targetPosition - projectile.transform.position". eulerAngles is just another representation of the rotation and you won't get anything meaningful from its magnitude.
I suspect you don't want that. Instead, I suspect you want to know whether or not the projectile would need to turn more than 60 degrees from its current forward direction. In that case, you probably want to check the angle between the projectile's forward vector and its direction vector towards the target.
I don't have Unity open so I don't know if this compiles, but it should go something like this:
var directionToTarget = targetPosition - projectile.transform.position;
var angleToTarget = Vector3.Angle(projectile.transform.forward, directionToTarget);
if (angleToTarget < 60) ...
You mentioned you want a more "realistic" turn. What do you want the projectile to do if it's more than 60 degrees?

Calculating LookAt without applying it

I need to clamp the rotation of a bone while using LookAt.
The LookAt function works great, but it doesn't offer any clamp possibilities, and to my knowledge, LookAt doesn't provide a way seeing the resulting rotation without
without applying it to a transform.
I would therefore like to know if it's possible to first calculate the results of LookAt without applying it first.
Calculate the direction vector you need:
Vector3 direction = bone.transform.position - targetTransform.position;
Use Quaternion.LookAt to calculate the rotation you require:
Quaternion newRotation = Quaternion.LookAt(direction);
Now perform any mathematics you want to perform on the supplied rotation, for example if you only want to rotate the bone a maximum of 10 degrees per second you would do this:
newRotation = Quaternion.RotateTowards(bone.transform.rotation, newRotation, 10f * time.deltaTime);
Finally, apply the rotation to the bone:
bone.rotation = newRotation;
Just apply LookAt, see the result and then clamp the result, applying the final rotation.
It's not uncommon to apply intermediate transforms during a frame (update function or similar). The important thing is that at the end of the Update (or LateUpdate or FixedUpdate) function the transform to be the desired one.

Calculate target angle given current angle and target position?

I've been struggling with what I think should be a very simple problem:
.
I know the current heading angle (say 15 deg), and given a target gameObject's transform, I want to calculate the angle that I should rotate towards to face the target. In the above example I want to calculate say 335ish deg.
Note that I need to calculate the target angle, I have another class that, given an angle, takes care of rotating the heading to the desired angle. I'm aware of the Transform.LookAt() and other similar functions, they don't apply in this situation because reasons (in the other class I basically calculate a Euler Quaternion and Lerp until I reach the target angle, due to project constraints, Transform.LookAt() doesn't work).
In the first approach, I tried calculating angle theta with the Dot product of Vector3.forward and the direction vector, didn't quite work right (either rotated forever or in the wrong direction)
targetAngle = Vector3.Angle(Vector3.forward, (target pos - current pos).normalized);
I thought maybe if I could calculate the current heading direction vector, I could take the Dot product of that and the target direction vector to get angle theta, then use theta and the current angle to figure out the target angle (360 - theta or something?) to get the angle I want to rotate to. Thing is, I only have the current angle and current pos, I don't understand how to calculate the current heading direction vector from that info. Do I just add some arbitrary constant to the current position's Z value and subtract from that the current position, to get a dir vector? Seems hacky and like it shouldn't work.
Any ideas are welcome.
Edit: Additional Info
The orientation code /u/Asad asked about:
// Calculate the target Quat to rotate all children by
Quaternion targ = Quaternion.Euler(0, 0, targetAngleHeading);
// Calculate the Linear interpolation to apply to all children
Quaternion lerp = Quaternion.Lerp(children[0].transform.localRotation, targ, Time.deltaTime * speedHeading_dps);
foreach (GameObject c in children)
{
// Apply lerp calcualted above to all children
c.transform.localRotation = lerp;
}
// Update the current heading angle 1st child's local z angle
currentAngleHeading = turrets[0].transform.localEulerAngles.z;
Then in FixedUpdate() I have:
if (currentAngleHeading != targetAngleHeading)
{
DesiredHeading();
}
You can take your transform's forward, and the vector to your target, and get an angle or rotation from those:
Vector3 vectorToTarget = target.transform.position - transform.position;
Vector3 facingDirection = transform.forward; // just for clarity!
float angleInDegrees = Vector3.Angle(facingDirection, vectorToTarget);
Quaternion rotation = Quaternion.FromToRotation(facingDirection, vectorToTarget);
Note that the rotation is relative; i.e., it's the rotation you need to apply from the current position to be facing the target.
try this instead
you can directly take the vector distance vector from transform.position and then
vector3.normalize (target.position - object.position)
this is the angle object'll want to move

xna get correct direction 3d

How do I get the vector indicating the direction to travel if I have a starting position vector3 and rotation vector3? I get a normalized vector to indicate how it's rotated but of course that only indicated how it's rotated not the direction of travel. i.e. if I rotate on the y that should affect the direction of travel on the x and the z rather than what normailzing a vector rotated on the y would do which would indicate just indicate it has been rotated on the y.
At some point you will probably take that 'rotation Vector3' and make a Matrix from it. That Matrix has a Vector3 property (Matrix.Forward) that is the direction in that corresponds to the 'rotation Vector3'. If you don't want to mess with a matrix you already have, this method should do the job.
Vector3 DirectionToTravel(bool rotationVecIsInRadians, Vector3 rotationVec)//rotation vec must not be normalized at this point
{
Vector3 result;
if (!rotationVecIsInRadians)
{
rotationVec *= MathHelper.Pi / 180f;
}
float angle = rotationVec.Length();
rotationVec /= angle; //normalizes rotation vec
result = Matrix.CreateFromAxisAngle(rotationVec, angle).Forward;
return result;
}
In addition to Steve H's answer, you may find you need to use Quarternions to do rotation in an 3D space more effectively. I've provided some links that might help you out if you decide to use Quarternions.
Quarternion Structure (MSDN)
Quarternion Tutorial (MSDN Social)
Quarternion Rotation in XNA (Stackoverflow Question)

2 vectors difference to rotation

I've been hanging my head around this issue for some time now and I'm at the top of my head not figuring this out.
The issue:
Currently trying to do a fake "swing" moment. Where I have the player object becoming a child to an object you can latch onto during a keypush.
With this in mind, I need to get the correct rotation on the grappleobject, making the velocity of the player becoming the correct rotation on the grappleobject.
This is not meant to be 2D, but 3D. Which causes this headache.
http://img843.imageshack.us/img843/7434/rotations.jpg
I figured that if I could get the vector of position, and the vector of the direction where the player is going towards, as in velocity of the character motor, to get an unique Vector, and this vector info should be able to rotate the grappleobject correctly.
However, that's what I thought was easy, but I've been hacking at this for hours to get that vector difference to do the rotation as it was thought out to be.
tl:dr
2 Vectors, the difference of these two to one vector, this vector controls the rotation of grappleobject to "fake" a swing motion with the proper velocity.
Thank you in advance if there'll be an answer.
Added Info:
Current testings has been these.
///
Parent Orb is the grappleobjects which updates its transform depending on trigger events.
CurDirection is where the player is heading within the vector in world.
CurPos is where the player is at that point in time within the world.
CurDirection = (transform.position-ParentOrb.position);
CurDirection.Normalize();
motor.movement.velocity = (CurDirection);
CurPos = transform.position;
////
Also tried out to get the angle from the grappleobject to the player.
///
otherDirection = The direction of velocity in space.
OtherDirectionPre = Current position in space.
Vector3 targetDir = otherDirection;
Vector3 forward = otherDirectionPre;
angle = Vector3.Angle(targetDir, forward);
///
I assume these may not be helpful, but better to show where I have gotten so far.
I think you know the radius between the hit point and the center, let's call it r. With the velocity v of the player and the angular velocity ω (=omega) of the axis the player should be connected to you have the vector equation:
v = ω × r
Assuming all 3 vectors are perpendicular to each other you have ω = v / r.
EDIT: You get the radius r from the position of the center and the point of contact of your collision:
Vector3 r = collision.contacts[0].point - center;
float radius = r.magnitude;
float angularSpeed = rigidbody.veloctiy.magnitude / radius;

Categories

Resources