I have a 3D point and the x,y,z rotations (qInitial) for that point.
I want to rotate that point more (by some degrees that could be 0 up to 360) around y axis (qYextra). How can I calculate the final Euler rotation (qResult.eulerAngles) that is a combination of these 4 rotations (x-y-z-y)?
I have tried calculating the initial quaternion rotation, and the extra rotation to be applied. And then multiply these two quaternions. However, I get weird results (probably gimbal lock).
Code in C#. Unity.
1.Quaternion qX = Quaternion.AngleAxis(rotationFromBvh.x,Vector3.right);
2.Quaternion qY = Quaternion.AngleAxis(rotationFromBvh.y,Vector3.up);
3.Quaternion qZ = Quaternion.AngleAxis(rotationFromBvh.z,Vector3.forward);
4.Quaternion qYextra = Quaternion.AngleAxis(angle,Vector3.up);
Quaternion qInitial = qY * qX * qZ; // Yes. This is the correct order.
qY*qX*qZ has exactly the same Euler x,y,z results as
Quaternion.Euler(rotationFromBvh)
Quaternion qResult = qInitial * qYextra;
return qResult.eulerAngles;
I can confirm that the code works fine (no gimbal lock) when 4th rotation is 0 degrees (qYextra = identity). Meaning that qInitial is correct. So, the error might be due to the combination of those 2 rotations (qInitial and qYextra) OR due to the convertion from Quaternion to Euler.
EXAMPLE: (qYextra angle is 120 degrees)
RESULTS:
qInitial.eulerAngles gives these results: applying_qInitial_rotation
qResult.eulerAngles gives these results: applying_qResult_rotation
EXPECTED RESULTS:
The expected results should be like qInitial but rotated 120 degrees around y.
Any suggestions? I haven't yet found a solution, and probably I won't.
In your question, you write:
How can I calculate the final Euler rotation that is a combination of these 4 rotations (x-y-z-y)?
However, in your code, you write
Quaternion qInitial = qY * qX * qZ; // Multiply them in the correct order.
I don't know unity, but I would have expected that you would want the order of the rotations to match x, y, z, rather than y, x, z.
You stated that it works when the y-rotation is 0, in which case the place of the y-rotation in the order becomes irrelevant.
Do you get the correct result if you instead write the code below?
Quaternion qInitial = qX * qY * qZ; // Multiply them in the correct order.
Related
So... I'll try to be as clear as possible, if I let something unclear please let me know.
I have a vector that comes from origin and go to a point in space, and I have an object that I want it's transform.up (Or Y vector) to be colinear with this vector, but the Y rotation of this object is driven by another factor, and I dont want to change it.
So far, what I'm trying to do is project this vector in the local XY and local ZY planes and measure the angles and apply rotation:
float xInclination = Mathf.Atan(Vector3.ProjectOnPlane(orbitMomemtumVector, transform.right).z / Vector3.ProjectOnPlane(orbitMomemtumVector, transform.right).y)*Mathf.Rad2Deg;
float yInclination = Mathf.Atan(initialPos.z / initialPos.x) * Mathf.Rad2Deg;
float zInclination = -Mathf.Atan(Vector3.ProjectOnPlane(orbitMomemtumVector, transform.forward).x / Vector3.ProjectOnPlane(orbitMomemtumVector, transform.forward).y)*Mathf.Rad2Deg;
if (initialPos.x < 0 && initialPos.z > 0)
{
yInclination = 180f - Mathf.Abs(yInclination);
argumentPeriapsis = argumentPeriapsis - yInclination;
}
else if (initialPos.x < 0 && initialPos.z < 0)
{
yInclination = 180f + Mathf.Abs(yInclination);
argumentPeriapsis = argumentPeriapsis - yInclination;
}
else
{
argumentPeriapsis = argumentPeriapsis - yInclination;
}
transform.rotation = Quaternion.Euler(xInclination, (float)argumentPeriapsis, zInclination);
This image shows the problem, I need the Y arrow to be collinear with the blue line
Let me be clear on this, don't use Euler angles in 3d space. In fact, avoid them in 2d games as well. Unless your object truly rotates on a single axis, and you never have to get the angle between two rotations, or lerp your rotations, don't use them.
What you want is Quaternion.LookRotation(A, B).
A being a vector to which Z will be colinear, X being orthogonal to the plane defined by A and B, and Y belonging to that plane.
Followup:
To match other axis to A, there are multiple solutions. First would be to simply apply the lookRotation to a parent object, while the child object is rotated inside to match whatever rotation you want. You can also edit your entire mesh to do so.
The other way is to simply apply another rotation, so that both combined get your desired result, like so:
Quaternion zMatched = Quaternion.LookRotation(zAxisTarget, direction)
Quaternion yMatched = zMatched * Quaternion.AngleAxis(90f, Vector3.right);
transform.rotation = yMatched;
This will rotate the object so that the y axis becomes collinear to the previous z axis.
This is however nor perfect. If you reach this point, you should consider building your own clearer solution based on combining AngleAxis results. But it works well enough.
Hello I tried a lot diffrent ways to get bending angle in Leap Motion. But I couldn't get true values. I used this method for reading. Thanks in advance.
Bone bone1 = finger.Bone(Bone.BoneType.TYPE_INTERMEDIATE);
Bone bone2 = finger.Bone(Bone.BoneType.TYPE_PROXIMAL);
double angle = 180 - ((bone1.Direction.AngleTo(bone2.Direction) / Math.PI) * 180) * 2;
In this example I'll use array accessors as a quicker way of accessing bones from Finger objects.
For reference, bone indices are: 0 = metacarpal, 1 = proximal, 2 = intermediate, 3 = distal. You can validate this by looking at the definition of BoneType.
(Careful, the thumb has one fewer bone than the other fingers.)
Vector3 bone0Dir = finger.bones[0].Direction.ToVector3();
Vector3 bone1Dir = finger.bones[1].Direction.ToVector3();
float angle = Vector3.Angle(bone0Dir, bone1Dir);
This example retrieves the angle in degrees between the metacarpal bone and the proximal bone of the finger object.
Note that Vector3.Angle returns the unsigned angle between the two bones; if you desire a signed angle, you can use the SignedAngle function instead. You'll need to pass it a reference axis; Vector3.Cross(hand.PalmarAxis(), hand.DistalAxis()) would be suitable for this.
EDIT: Ah, apologies, the answer is a bit different if you're outside of the Unity engine. In that case, Leap.Vector.AngleTo is sufficient, but there's a simpler way to convert radians to degrees:
Vector bone0Dir = finger.bones[0].Direction;
Vector bone1Dir = finger.bones[1].Direction;
float angle = bone0Dir.AngleTo(bone1Dir) * Vector.RAD_TO_DEG;
Again, this will return the unsigned angle, but fingers don't usually bend backwards, so this should be sufficient for your use-case. You can also use Math.Asin((bone0Dir.Cross(bone1Dir).Magnitude)) * RAD_TO_DEG to get a (right-handed) signed angle.
I am getting 2d coordinates from Vector3. I have to correct positions to get right results. Indeed it seems I get correct positions like this but I do not know how to correct position when rotated.
Here my worldViewMatrix that I do operations but those operations not passed to my VertexData then I try to correct positions.
WorldViewMatrix = Matrix.Scaling(Scale) * Matrix.RotationX(Rotation.X) * Matrix.RotationY(Rotation.Y) * Matrix.RotationZ(Rotation.Z) * Matrix.Translation(Position.X, Position.Y, Position.Z) * viewProj;
I am trying to correct it like:
public Vector2 Convert_3Dto2D(Vector3 position, Vector3 translation, Vector3 scale, Vector3 rotation, Matrix viewProj, RenderForm_EX form)
{position += translation;
position += translation;
position = Vector3.Multiply(position, scale);
//ROTATION ?
var project = Vector3.Project(position, 0, 0, form.ClientSize.Width, form.ClientSize.Height, 0, 1, viewProj);
Console.WriteLine(project.X+" "+ project.Y);
return new Vector2(project.X, project.Y);
}
What can I do to correct rotated position ?
If you can, post a little more information about "correct positions". I will take a stab at this and assume you want to move your vertex into world space, then work out what pixel it occupies.
Usually you order multiplying your order by
Translate * Rotate * Scale;
if you want Viewprojection to apply correctly, I believe it should be at the start. V * (t * r * s).
The following link on gamedev stackexchange goes into this. matrix order
Also, your project takes in a Vector3 that has been already multiplied into wvp matrix, I dont see you have multiplied it in your convert_3dto2d function.
Basically, execute a TRS matrix multiply on your original vert, then multiply your WVP matrix then execute your project. You will then get your screen space pixel.
I stumbled on a working concept for a fast rotation & orientation system today, based on a two-term quaternion that represents either a rotation about the X axis (1,0,0) in the form w + ix, a rotation about the Y axis (0,1,0) in the form w + jy, or a rotation about the Z axis (0,0,1) in the form w + kz.
They're similar to complex numbers, but a) are half-angled and double-sided like all quaternions (they're simply quaternions with two of three imaginary terms zeroed out), and b) represent rotations about one of three 3D axes specifically.
My problem and question is...I can't find any representation of such a system online and have no idea what to search for. What are these complex numbers called? Who else has done something like this before? Where can I find more information on the path I'm headed down? It seems too good to be true and I want to find the other shoe before it drops on me.
Practical example I worked out (an orientation quaternion from Tait-Bryan angles):
ZQuat Y, YQuat P, XQuat R; // yaw, pitch, roll
float w = Y.W * P.W;
float x = -Y.Z * P.Y;
float y = Y.W * P.Y;
float z = Y.Z * P.W;
Quaternion O; // orientation
O.W = x * R.W + w * R.X;
O.X = y * R.W + z * R.X;
O.Y = z * R.W - y * R.X;
O.Z = w * R.W - x * R.X;
Quaternions in 2D would degenerate to just being a single component being no diferrent than an rotation angle. That's propably why you do not find anything. With quaternions you do f.e. not have the problem of gimbal lock, appearing when two rotation axes align because of rotation order. In normal 2D space you do not have more than a single rotation axis, so it has neither order (how do you sort a single element) and there are no axes to align. The lack of rotation axes in 2D is because you get a rotation axis when being perpendicular to two other axes.
This gives 3 axes for 3D:
X&Y=>Z
X&Z=>Y
Y&Z=>X
But only one for 2D:
X&Y=>Z
I know this is probably a very simple question, but I can't seem to figure it out. First of all, I want to specify that I did look over Google and SO for half an hour or so without finding the answer to my question(yes, I am serious).
Basically, I want to rotate a Vector2 around a point(which, in my case, is always the (0, 0) vector). So, I tried to make a function to do it with the parameters being the point to rotate and the angle(in degrees) to rotate by.
Here's a quick drawing showing what I'm trying to achieve:
I want to take V1(red vector), rotate it by an angle A(blue), to obtain a new vector (V2, green). In this example I used one of the simplest case: V1 on the axis, and a 90 degree angle, but I want the function to handle more "complicated" cases too.
So here's my function:
public static Vector2 RotateVector2(Vector2 point, float degrees)
{
return Vector2.Transform(point,
Matrix.CreateRotationZ(MathHelper.ToRadians(degrees)));
}
So, what am I doing wrong? When I run the code and call this function with the (0, -1) vector and a 90 degrees angle, I get the vector (1, 4.371139E-08) ...
Also, what if I want to accept a point to rotate around as a parameter too? So that the rotation doesn't always happen around (0, 0)...
Chris Schmich's answer regarding floating point precision and using radians is correct. I suggest an alternate implementation for RotateVector2 and answer the second part of your question.
Building a 4x4 rotation matrix to rotate a vector will cause a lot of unnecessary operations. The matrix transform is actually doing the following but using a lot of redundant math:
public static Vector2 RotateVector2(Vector2 point, float radians)
{
float cosRadians = (float)Math.Cos(radians);
float sinRadians = (float)Math.Sin(radians);
return new Vector2(
point.X * cosRadians - point.Y * sinRadians,
point.X * sinRadians + point.Y * cosRadians);
}
If you want to rotate around an arbitrary point, you first need to translate your space so that the point to be rotated around is the origin, do the rotation and then reverse the translation.
public static Vector2 RotateVector2(Vector2 point, float radians, Vector2 pivot)
{
float cosRadians = (float)Math.Cos(radians);
float sinRadians = (float)Math.Sin(radians);
Vector2 translatedPoint = new Vector2();
translatedPoint.X = point.X - pivot.X;
translatedPoint.Y = point.Y - pivot.Y;
Vector2 rotatedPoint = new Vector2();
rotatedPoint.X = translatedPoint.X * cosRadians - translatedPoint.Y * sinRadians + pivot.X;
rotatedPoint.Y = translatedPoint.X * sinRadians + translatedPoint.Y * cosRadians + pivot.Y;
return rotatedPoint;
}
Note that the vector arithmetic has been inlined for maximum speed.
So, what am I doing wrong? When I run the code and call this function with the (0, -1) vector and a 90 degrees angle, I get the vector (1, 4.371139E-08) ...
Your code is correct, this is just a floating point representation issue. 4.371139E-08 is essentially zero (it's 0.0000000431139), but the transformation did not produce a value that was exactly zero. This is a common problem with floating point that you should be aware of. This SO answer has some additional good points about floating point.
Also, if possible, you should stick with radians instead of using degrees. This is likely introducing more error into your computations.