Flatten a Quaternion Rotation into 3 Unit Axes Rotations - c#

Hi I have an arbitrary rotation quaternion, which is constructed from a series of operations done by the user (they select the object, rotate it around the plane constructed from the camera view direction, then maybe rotate it from another angle etc).
I then need to decompose this rotation object down into a rotation around the X, Y and Z axes. Note that it doesn't have to be that order. The user interface allows a user to attach rotation blocks together in any order, so they could chain them up like this:
In code, I then loop through each block and do:
finalRotation *= Quaternion.CreateFromAxisAngle(blockAxis, toRadians(blockAngle))
So how could I convert an arbitrary quaternion back to this block representation? I've tried projecting the quaternion onto the X, Y and Z planes as per this answer:
Component of a quaternion rotation around an axis
and then connecting up the blocks in an [X][Y][Z] order, but so far the results seem to come out incorrectly. Would someone be able to explain how I should approach this problem? Note I am restricted to rotating around one axis at a time, per block.
Edit: To clarify I am using the MonoGame framework, not Unity.

Related

OpenGL - Cannot get cumulative rotation around correct axis and origin

I am implementing an Arcball rotation in an existing project I wrote several years ago, using OpenTK & C#, and have got stuck at the final hurdle.
This is 'old-style' non-shader OpenGL. I am confident that the Arcball rotation is working correctly, the problem is just applying the resulting matrix. It should be fairly straightforward but it isn't working out that way.
I get the Arcball rotation as a quaternion (qCurrent) then convert that to a matrix. I have then tried a couple of approaches:
Simply apply that as an additional rotation to the existing scene:
GL.PushMatrix();
Matrix4 arcball_rot = Matrix4.CreateFromQuaternion(qCurrent);
GL.MultMatrix(ref arcball_rot);
... render objects in scene
GL.PopMatrix();
This applies the correct rotation around the correct origin (the camera target), but with respect to the world coordinate system, not the viewer. This makes sense because I am effectively applying the rotations in the wrong sequence.
Apply the rotations in sequence, with the arcball rotation first, which means starting from scratch. Here, rtn_complete is a matrix storing the modelview matrix as initialised, before the Arcball rotation:
Matrix4 modelview = Matrix4.LookAt(camera.camerapos, camera.cameratarget, camera.cameraup);
rtn_complete = modelview;
Then...
Matrix4 mm = Matrix4.CreateFromQuaternion(qCurrent) * rtn_complete;
GL.LoadIdentity();
GL.MultMatrix(ref mm);
This applies the correct rotation wrt the viewer, but around the wrong centre of rotation. It is a point a long way away from the camera target.
Obviously this approach needs a forward/backward translation either side of the rotation, but I have tried pretty much every possible combination of these and none of them work.
Camera and target positions are as follows :-
camera.camerapos = (-51.3, -67.9, 37.7), and
camera.cameratarget = (0.0, 0.6, 7.3)
When I add translations as below (and countless other permutations) I still get the scene rotating around the wrong origin.
GL.LoadIdentity();
GL.Translate(camera.cameratarget);
GL.MultMatrix(ref arcball_rot);
GL.Translate(-camera.cameratarget);
GL.MultMatrix(ref rtn_complete);
My feeling is that the root of the problem is likely to be the translation applied by using LookAt, which I am not taking into account when doing the above transformations.
However, when I check the rtn_complete matrix (which is the modelview matrix following the LookAt) the fourth column does not contain a translation. The matrix looks like this:
0.80, 0.20, -0.56, 0.00
-0.60, 0.27, -0.75, 0.00
0.00, 0.94, 0.34, 0.00
0.38, -7.02, -92.8, 1.00
I would have expected to a see a translation here.
EDIT 1:
Found it eventually. I was on the right track with my suspicion about the translation resulting from using Matrix4.LookAt().
The way I had listed the matrices for debugging resulted in a transpose, so the translation was there for me to see but I was missing it but it was in the fourth row not the fourth column. The translation is (0.38, -0.72, -92.8) Applying this translation on either side of the Arcball rotation results in the expected rotation behaviour, initially.
GL.LoadIdentity();
GL.Translate(0.38, -7.02, -92.8);
GL.MultMatrix(ref mm);
GL.Translate(-0.38, 7.02, 92.8);
GL.MultMatrix(ref rtn_complete);
EDIT 2:
Having worked out the above I am very close, but it's still not quite right when I move somewhere else in the scene. Again I have got a couple of problems, and can solve one or the other but not both simulataneously.
Because of the Matrix4.LookAt I separated out the translation and the rotation components of the rtn_complete matrix (respectively 'rtn_complete_trans' and 'rtn_complete_rot').
If I do this, the rotations are spot on:
GL.LoadIdentity();
GL.Translate(rtn_complete_trans); // modelview translation component
GL.Translate(camera.cameratarget); // translate to rotation centre
GL.MultMatrix(ref arcball_rot); // ongoing Arcball rotation
GL.MultMatrix(ref rtn_complete_rot); // modelview rotation component
GL.Translate(-camera.cameratarget); // translate back from rotation centre
But there is an unwanted translation each time the view is initialised. If I rotate, release and repeat a few times the object gradually moves off screen.
If I change the position of the second camera translation this unwanted shift no longer happens, but the centre of rotation is off:
GL.LoadIdentity();
GL.Translate(rtn_complete_trans); // modelview translation component
GL.Translate(camera.cameratarget); // translate to rotation centre
GL.MultMatrix(ref arcball_rot); // ongoing Arcball rotation
GL.Translate(-camera.cameratarget); // translate back from rotation centre
GL.MultMatrix(ref rtn_complete_rot); // modelview rotation component
Can anyone explain?

How can I find the rotation of the head in Google Cardboard Unity3D?

Hey guys how do I find the rotation of the phone with Google Cardboard SDK in Unity3D, like the way the persons head is facing? I need to find if it is facing more towards the east, the west, or the north. Do I find the rotation of the head, or the parent Main camera?
The Cardboard class contains a property called HeadRotation which is a Quaternion.
Quaternion crtRot = youCardboardController.HeadRotation;
To use its rotation like you'd in Unity with directional vectors you may simply multiply it by Vector3.forward.
Vector3 lookDir = crtRot * Vector3.forward;
Visualizing the vector in editor might help narrow down issues
void Update () {
// ..
Debug.DrawRay( pos, lookDir * 100, Color.blue );
// ..
}
From here you only need to know where North is, in meaning of the facing vector. Do a Vector3.Angle() and you have the angle between your avatar's and North's vector. You might want to evaluate both vectors with their y axes set to 0.
You could also use Vector3.Dot() (the dot product) to determine how much both vectors look into the same direction.
I had an issue with HeadPosition, which wasn't updated properly. So if you operate from HeadPosition keep in mind it may stick to 0,0,0 .
Take Head.transform.rotation - that's the orientation of the user's head.
I'm not really sure what do you mean by North or West. If the mobile device has a magnetometer, then maybe you could read it's data to determine where North is, but I've never done that
It would be the rotation of the Head object, although the Main Camera usually has the same rotation.
But if you want the direction relative to the real world, that information is not available in the SDK. The compass cannot be used because of the magnet, so there is no way to get the real direction.
Just take the rotation angle of the main camera in the scene. It will gives you the head rotation angles with respect to x, y and z axis.
In GVR based VR scenes the system is internally rotating the camera with respect to our head movements. So it's easy to get the head rotation using main camera rotation angles.
For that,
//local rotation of the Transform of the camera
Camera.main.transform.localEulerAngles.y
//The world Y rotation
Camera.main.transform.rotation.y

Rotating about a Point in a Voxel Game Engine (C#)

I am continuing to build upon a voxel-based game engine made in OpenTK (a .NET/Mono binding of OpenGL). In this engine, there is a basic class called Volume which possesses traits such as position, rotation and scale, as well as rules to edit these values for animation.
How would I go about providing a function to rotate one point about another point?
I could quite easily rotate an object about its center (by changing its rotation property), but what if I need the object to rotate about origin or a random point in space? This would be useful for grouping blocks together, as I could therefore rotate objects as if they were stuck together - rather than them rotating individually.
I heard I would need to dive in at the deep end and learn about rotation matrices, but honestly it went over my head. The closest resource I have been able to find so far was this link, however it details rotating around an axis. Could somebody adapt these instructions: or even better, give me basic pseudocode for a function that rotates from a position and point of rotation?
EDIT:
The following solution doesn't seem to work. My code is as simple as:
void RotateAboutPoint(Vector3 point, Vector3 amount)
{
v.Translate(point);
v.Rotate(amount);
v.Translate(-point);
}
Should this work, and if not, could anyone help further now that the situation is explained properly?
As far as I can tell, this may as well just be:
void RotateAboutPoint(Vector3 point, Vector3 amount)
{
v.Rotate(amount);
}
Which defeats the object of performing this around a point.
These co-ordinates are not in relation to the object... Sorry if my poor explanation made this unclear before!
I answered a similar question here: Rotating around a point different from origin
in the link you provided author put the steps of rotation :
(1) Translate space so that the rotation axis passes through the origin.
(2) Rotate space about the z axis so that the rotation axis lies in the xz plane.
(3) Rotate space about the y axis so that the rotation axis lies along the z axis.
(4) Perform the desired rotation by θ about the z axis.
(5) Apply the inverse of step (3).
(6) Apply the inverse of step (2).
(7) Apply the inverse of step (1).
Actually in this process (2),(3),(5),(6) are unnecessary if you need to rotate about a point. These steps are the case if you need to rotate your object around a line.
In your case : lets say you want to rotate your object around (a,b)
GL.pushmatrix();
translate your object by (a,b);
rotate your object;
translate your object by (-a,-b);
GL.popmatrix();
EDIT:
Sorry I forgot to add encapsulation of your rotation process.(It was on the post I gave the link though)
Further info:
What is this encapsulation? why do we need this? Answer is simple. OpenGL stores a 4x4 matrice which is initially an identity matrice. When you perform a translate or rotate operation, opengl updates your matrice and at the final state opengl multiply each vertice with that matrice. (And if you do not perform any operation, vertices multiply with identity matrice give you the same vertice coordinates)
The problem in your code is when you don't apply an encapsulation to your rotation/translate block, The final matrice will be same for all your objects in the scene. With encapsulation we guaranteed that the updated matrice will be used only inside that block.

Rotate an object according to a plane normal

I am making a FPS game, I created a peaceful AI for the moment and when the character is died, I just want it to be oriented according to the normal below it. I show you the result for the moment :
as you can see, the character is flying, because the terrain is not straight.
I am trying (without success) to make something like that :
I have the (x,y,z) coordinates (character position) and the normal to the plane.
Yes the normal is always facing up, as you can see on my drawing, even if I drew it in the good pose. I dont understand when you are talking about the quaternion, which new normal are you talking about ?
I already have the normal of the plane under the character, so, part of the jobs is already done :)
Your character's death pose is always with the normal facing up, right?
And you want to rotate it to another normal.
You can find a Quaternion that represents the rotation between two vectors (up and the new normal) to rotate the mesh.
This question has the answer to that:
Quaternion from two vector pairs
To know the normal of your terrain, you can probably cast a ray down and get the normal from the collision information depending on the physics engine you are using.
Edit:
Some background info:
A quaternion represents a rotation. So what I'm suggesting is that you use the answer from the question I linked to calculate the rotation between the default orientation of the character's death pose (UP) to the new orientation (Terrain Normal)
Then you can just transform your dead character with the Quaternion and it'll follow the terrain's normal.
Here's a sketch: calculate Q from UP and N with the solution from the Link and rotate your character's model with Q:

Animation time based on quaternion difference

I'm trying to adjust the orientation of my camera using two quaternions, based on their difference. So for a minimal rotation, I want the animation to take little time, and a bigger rotation to take longer. I guess I want to rotate the camera at a certain velocity.
Is there any way to combine the yaw, roll and pitch to get a single radian, so I can use that to calculate what percentage of the quaternion I want to apply each frame?
If you vant to differenciate the two quaternion just use the ToAngleAxis of the delta quaternion. It returns the angle (you need this) and the axix of the rotation between the two quaternions.
You can use quaternions and the calculated speed to calculate spherical interpolation (slerp for short), which allows you to calculate intermediate states for your camera orientation.

Categories

Resources