c# quaternion reference system - c#

I'm working on an Android app which extracts a Quaternion relative to a rotation, then sends its axis/angle representation to C# in order to operate a 3D rotation of a vector.
I need this to be done outside Android (in my C# application), but for testing I'm doing it on both Android and C# to be sure the results are the same.
The result is not the same, and I noted that the Quaternion in C# is different from the original one on Android.
I'm assuming this is because C# and Android use a different reference coordinate system.
Here's my code:
On Android. Quaternion and Vector3 imported from libgdx
Quaternion q = (Quaternion) bundle.getSerializable("QUATERNION");
Vector3 axis = new Vector3();
q.getAxisAngle(axis);
float angle = q.getAngle();
The transformation I do afterwards is the following:
Vector3 vi = new Vector3(input[0],input[1],input[2]);
Vector3 output = vi.rotate(axis,angle);
On C#. Quaternion and Vector3 are imported from System.Numerics
public static float[] TranslateQuaternion(Vector3 axis, float angle, float x, float y, float z) {
Vector3 input = new Vector3(x,y,z);
Quaternion q = Quaternion.CreateFromAxisAngle(axis,angle);
Console.WriteLine("Quaternion: " + q.ToString());
Matrix4x4 m = System.Numerics.Matrix4x4.CreateFromAxisAngle(axis,angle);
Vector3 output = Vector3.Transform(input,m);
return new float[3]{output.X,output.Y,output.Z};
}
My Vector3 transformation leads to a different result than the one I get on Android, and I think the cause is due to a different Quaternion.
My starting Quaternion from Android is:
x=0.00 y=-0.67 z=0.01 w=0.74
//The axis I pass to C#:
x = -0.00 y=-1.00 z=0.01 angle=83.74
While my C# Quaternion is this:
x=0.00 y=0.86 z=-0,01 w=-0,52
How can I get around this? Is there some mapping I can do to have matching coordinates systems? Is there a C# way to perform the rotation of Vector3 from axis/angle directly as I've done in Android?
I'm getting quite crazy about that...
Thanks in advance guys!

Related

C# Vector3 Rotation with Quaternion / Matrix4x4

I've got a sensor that delivers object data in a coordinate system according to ISO 8855-2011.
My sensor is positioned at [0, 0, 0] but can be "misaligned". Therefore I want to compensate for roll, pitch and yaw.
In my App I perform the necessary rotations with the System.Numerics Lib and more specifically with a vector3 as the data point ([x, y, z]) and tried either a Matrix4x4 or a Quaternion as the rotation matrix.
Without having evaluated this final result a rotation in three steps seems to work quite well (at first glance looks like to be expected in my visualization). To perform the rotation I start by specifying three Quaternions for each axis and perform the rotation one after the other.
Vector3 vecMeas = new Vector3(x, y, z);
Quaternion rotRoll = Quaternion.CreateFromAxisAngle(new Vector3(1.0f, 0.0f, 0.0f), rollAngle);
Quaternion rotPitch = Quaternion.CreateFromAxisAngle(new Vector3(0.0f, 1.0f, 0.0f), pitchAngle);
Quaternion rotYaw = Quaternion.CreateFromAxisAngle(new Vector3(0.0f, 0.0f, 1.0f), yawAngle);
var vecRolled = Vector3.Transform(vecMeas, rotRoll);
var vecPitched = Vector3.Transform(vecRolled, rotPitch);
var vecResult = Vector3.Transform(vecPitched, rotYaw);
While this seems to work, it looks clumsy to me as the class Matrix4x4 and Quaternion offers a method called "CreateFromYawPitchRoll". I tried every combination of inputs for this method (if I remember correctly 6 combinations for the order of pitch, roll, yaw combined with 48 combinations of inputs for the order and sign of [x, y, z]), but was not able to produce the same as my rotation in 3 steps.
Example (one of ~288 combinations):
Vector3 vecMeas = new Vector3(x, y, z);
Quaternion rot = Quaternion.CreateFromYawPitchRoll(pitch, roll, yaw);
var vecResult = Vector3.Transform(vecMeas, rot);
The above shown "one step" solutions always looks off.
Unfortunately I was not able to find a a lot of information about the handedness (or the absence thereof) of the expected inputs for Matrix4x4 / Quaternion or the order in which the rotation of "CreateFromYawPitchRoll" is being performed. Do you have any idea, how I could refactor my code to be more elegant (aka maybe a one step solution) or how to properly use CreateFromYawPitchRoll? A multiplication of the rotation elements did not deliver the expected results (rotRoll * rotPitch * rotYaw).
Thanks in advance!
Update:
Sorry, I think I figured it out.
In my case I have to do the following:
Quaternion rot = Quaternion.CreateFromYawPitchRoll(yawAngle, pitchAngle, rollAngle);
var vecRot = Vector3.Transform(new Vector3(Y, Z, X), rot);
The result will be:
var vecRes = new Vector3(vecRot.Z, vecRot.X, vecRot.Y);

Simulate Gravity & Orbit in Unity

Hey and thanks for your help in advanced.
I've watched a few youtube videos on how to add Solar System and orbiting Gravity in Unity and ended up using the this for help for the solar system gravity part.
https://www.youtube.com/watch?v=Ouu3D_VHx9o&t=114s&ab_channel=Brackeys
But right after i decided to trying to make my planet orbit the sun i used this Wikipage for the math equation
https://en.wikipedia.org/wiki/Orbital_speed
But for some reason either my planets flies away of the sun start flying towards the planet. I've been looking around for 2 days and can't seem to make it work and tried diffrent type of possiblies.
Here is my code
public class Planets : MonoBehaviour
{
const float G = 100F;
public Rigidbody rb;
public float CurrentV;
private void FixedUpdate()
{
Planets[] attractors = FindObjectsOfType<Planets>();
foreach (Planets AllPlanets in attractors)
{
if (AllPlanets != this)
{
Orbiting(AllPlanets, CurrentV);
Attract(AllPlanets);
}
}
}
void Attract(Planets objToAttract)
{
Rigidbody RbTpAttract = objToAttract.rb;
Vector3 direction = rb.position - RbTpAttract.position;
float distance = direction.magnitude;
float ForceMagnitude = G * (rb.mass * RbTpAttract.mass) / Mathf.Pow(distance, 2);
Vector3 Force = direction.normalized * ForceMagnitude;
RbTpAttract.AddForce(Force);
}
void Orbiting(Planets objToAttract, float CV)
{
Rigidbody RbTpAttract = objToAttract.rb;
Vector3 direction = rb.position - RbTpAttract.position;
float distance = direction.magnitude;
float ForceMagnitude = Mathf.Sqrt((G * rb.mass) / (2 / distance - 1 / RbTpAttract.mass));
Vector3 Force = direction.normalized * ForceMagnitude;
RbTpAttract.velocity += Force;
}
}
The problem is that the formula for orbital speed is used to derive the speed of an object in orbit, but you're using it as a form of constant thrust applied to each body towards each other. That's a bit like calculating the speed of a moving car, and then applying the same speed back to it as an impulse!
The only force experienced by objects in orbit is the one you get from Newton's law G * m * m / r*r. In order to actually orbit though, the planets will need an initial velocity - this can be calculated from the orbital speed formula. Calculate it at the given distance, and apply it on Start() in a direction perpendicular to the orbital plane and the direction to the sun (or whatever you want to orbit), you can get this from dir = Vector3.Cross(sunDir, Vector3.up).normalized
Note that gravitational systems are not numerically stable in physics engines relying on euler integration (such as PhysX). You need things like Runge-Kutta integration for that, or the planets will eventually lose their orbit if you leave the simulation running for long enough.

normalizing euler angles rotation vector

I need to display the rotation in Euler angles of an object's certain axis.
I am aware that retrieving the rotation of an object in Euler angles gives inconsistent results, some of which can be solved by simply using modulo 360 on the result. however one permutation that unity sometimes does when assigning a vector with the value of "transform.localRotation.eulerAngles" is instead of retrieving the Vector3 "V", it retrieves "(180, 180, 180) - V".
to my understanding, "(180, 180, 180) - V" does not result in the same real world rotation as V, unlike "(180, 180, 180) + V" which does leave the actual rotation unaffected.
what is the explanation for the phenomenon, and what is the best way of normalizing an Euler angles rotation vector assuming I know the desired and feasible value of one of its axes? (for example, to normalize it such that all of it's values are mod 360 and it's Z axis equals 0 assuming it does have a representation in which Z = 0)
I don't know about the first part of the question (it is different enough to be its own question imo) but I can answer your second one.
So, you have these inputs :
Quaternion desiredRotation;
float knownZ;
And you're trying to find Vector3 eulers where eulers.z is approximately knownZ and Quaternion.Euler(eulers) == desiredRotation.
Here's the procedure I would use:
First, determine the up direction rotated by desiredRotation and the up and right direction rotated by a roll of knownZ:
Vector3 upDirEnd = desiredRotation * Vector3.up;
Quaternion rollRotation = Quaternion.Euler(0,0,knownZ);
Vector3 upDirAfterRoll = rollRotation * Vector3.up;
Vector3 rightDirAfterRoll = rollRotation * Vector3.right;
We know the local up direction after desiredRotation is applied and that the only thing that can adjust the up direction after the roll knownZ is applied is the rotation done by the euler pitch component. So, if we can calculate the angle from upDirAfterRoll to upDirEnd as measured around the rightDirAfterRoll axis...
float determinedX = Vector3.SignedAngle(upDirAfterRoll, upDirEnd, rightDirAfterRoll);
// Normalizing determinedX
determinedX = (determinedX + 360f) % 360f;
...we can determine the x component of eulers!
Then, we do the same with the yaw component of eulers to make the new forward direction line up with the end forward direction:
Vector3 forwardDirEnd = desiredRotation * Vector3.forward;
Quaternion rollAndPitchRotation = Quaternion.Euler(determinedX, 0, knownZ);
Vector3 forwardDirAfterRollAndPitch = rollAndPitchRotation * Vector3.forward;
Vector3 upDirAfterRollAndPitch = upDirEnd; // unnecessary but here for clarity
float determinedY = Vector3.SignedAngle(forwardDirAfterRollAndPitch, forwardDirEnd, upDirAfterRollAndPitch );
// Normalizing determinedY
determinedY = (determinedY + 360f) % 360f;
Vector3 eulers = new Vector3(determinedX, determinedY, knownZ);
To ensure that the given quaternion can be made with the given component, you could check if the axes given to SignedAngle actually can rotate the input vector to the target vector, or you can just compare the calculated eulers and the given quaternion:
Quaternion fromEuler = Quaternion.Euler(eulerAngles);
if (fromEuler==desiredRotation)
{
// use eulerAngles here
}
else
{
// component and quaternion incompatible
}
Hopefully that helps.
I'm not quite sure I understand your question correctly, but the euler angles just represent the angles of 3 rotations applied around the 3 axis in a specific order, right? So why would you normalize it by adding 180 everywhere? You should bring each angle individually into the range 0-360 by modulo-ing them.
Your question seems to imply that you can obtain any orientation by only rotating around two axis instead of three... is that what you are trying to achieve?
Using quaternions could possibly help you, in fact an orientation can be defined with just 4 scalar values: an axis and an angle

how can i get the location of the player along a specific axis during play mode?

my player runs forward during play time so what i want to do is store his current position along a specific axis lets say z in a variable inside the update function and use that position elsewhere. i also want to know what kind of datatype we have to use to store such value like the current position of player on the z axis if doing so is even possible. i saw this code somewhere:-
var playerPos:Vector3 = playerObject.transform.position;
but idk how its working if it is in the first place
You are close but the current syntax in your code is for Javascript.
You use transform.position to get the position of all axis. transform.position returns a Vector3 and that Vector3 contains all axis for your GameObject position.Vector3 has x, y and z properties which are all float datatype.
ACCESSING THE POSITION:
Assuming that playerObject is the name of your GameObject, below is an example of how to access each individual axis.
To get the X axis
float x = playerObject.transform.position.x;
To get the Y axis
float y = playerObject.transform.position.y;
To get the Z axis
float z = playerObject.transform.position.z;
You can also get the position once and store it into a Vector3 variable then access each individual axis from there:
To get the All axis (x,y,z)
Vector3 playerPos = playerObject.transform.position;
float x = playerPos.x;
float y = playerPos.y;
float z = playerPos.z;
MODIFYING THE POSITION:
Modifying the position is different from accessing the it. You can access like this
float x = playerObject.transform.position.x;
but cannot change the x like this:
playerObject.transform.position.x = 6f;
You must create a new Vector3, modify the axis you want to (x, y and z), then change the transform.position variable with that new variable(Vector3).
It should something like this:
Vector3 newPos = playerObject.transform.position;
newPos.x = 5f;
newPos.y = 4f;
newPos.z = 3f;
playerObject.transform.position = newPos;
My suggestion to you is to always use the Documentation. It shows you what each property or method returns. This will prevent you from asking such question like this. For example, the Transform.position returns Vector3.
When you click on that Vector3, you will see many other variables you can access from it.
Your code snippet is in javascript.
The player position is a Vector3 where the single values (x, y and z) are floats. So this will give you the single values:
Vector3 pos = playerObject.transform.position;
float x = pos.x;
float y = pos.y;
float z = pos.x;
This can be shortened, but for the purpose of demonstration I did it like this. Obviously you need to get the playerObject in some way.
Doing something like this is like the very basics of coding in unity, so if you aren't familiar with that I'd recommend you have a look on the unity tutorials here -> https://unity3d.com/learn/tutorials

Correct rotation with Quaternion

I have some problems with a rotating marble.
I've tried it with Matrix.CreateFromYawPitchRoll and Matrix.CreateRotation but there were some problems, I think it's due to the Gimbal lock effect.
So, I've tried using quaternions instead, but nothing changed.
When moving on only an axis it works fine, but when the rotation occurs on two different axes the marble still rotates on wrong axes.
Here's my code:
// declarations
Vector3 Position = Vector3.Zero;
Vector3 Rotation = Vector3.Zero;
Quaternion qRotation = Quaternion.Identity;
AbsoluteBoneTransforms = new Matrix[Model.Bones.Count];
Model.CopyAbsoluteBoneTransformsTo(AbsoluteBoneTransforms);
In the Update method:
Position += speed;
Rotation = speed * MathHelper.ToRadians(-1.5f);
Quaternion rot = Quaternion.CreateFromAxisAngle(Vector3.Right, Rotation.Z) *
Quaternion.CreateFromAxisAngle(Vector3.Backward, Rotation.X);
qRotation *= rot;
And in the Draw method:
effect.World = AbsoluteBoneTransforms[mesh.ParentBone.Index] *
Matrix.CreateFromQuaternion(qRotation) * Matrix.CreateTranslation(Position);
What's wrong? Is it wrong to use Quaternion.CreateFromAxisAngle on multiple axes?
EDIT
I've tried calculating directly the axis of rotation of my marble, instead of using combination of multiple axes:
angle += speed.Length() * angularVelocity;
qRotation = Quaternion.CreateFromAxisAngle(Vector3.Cross(speed, Vector3.Up), angle);
qRotation.Normalize();
angle is a float that keeps track of the current movement.
This solution doesn't seem to create Gimbal lock, but marble rotations aren't correct, it seems that the rotating speed is not constant, but became faster and slower over time, I can't understand why.
If I "concatenate" the quaternions I get every frame using
qRotation *= Quaternion.CreateFromAxisAngle(Vector3.Cross(speed, Vector3.Up), angle)
the Gimbal lock effect is still visible.
Here's how I've tackled that:
I'm assuming speed is a vector representing the direction the ball is rolling and whose magnitude represents the rate it is traveling in that direction.
Vector3 axis = Vector3.Cross(speed, Vector3.Up);
float angle = speed.Length();//factor by delta time if neccesary
Quaternion rotationThisFrame = Quaternion.CreateFromAxisAngle(axis, angle * (1/radiusOfBall));
then you can concatenate that to your qRotation. Also, you may need to normalize your quaternion after concatenation.
Update: The correct answer to this question/thread was reversing the order that quaternions concatenate in. With respect to XNA, matrices combine left to right, quaternions combine right to left.

Categories

Resources