Get rotation matrix between two two transform matrices (XNA) - c#

I have an marker detection system for AR at the moment, it detects markers in the scene and gives the transform matrix of the camera for each marker in the scene.
Let's say I have found 2 markers. I am trying to find the rotation matrix I will have to apply to one of the markers in order to get it to match the orientation of the other marker.
I figured it should be the same as computing the transform matrix of one marker to another and decomposing the transform to obtain the x,y,z euler rotation matrix but I cannot seem to get this to work. I am using C# with XNA.
In code:
Matrix marker1 = markerTransforms[0];
Matrix marker2 = markerTransforms[1];
Matrix relativeTransform = Matrix.Invert(marker1) * marker2;
Quaternion rotation;
Vector3 scale;
Vector3 translation;
relativeTransform.Decompose(out scale, out rotation, out translation);
Matrix rotationMatrix = Matrix.CreateFromQuaternion(rotation);
This above doesn't seem to work.
Another question would be how to extract out the x,y,z euler rotations from the rotation matrix?
EDIT:
I found a function to convert the quaternion to euler following x,y,z order here: http://forums.create.msdn.com/forums/p/4574/23763.aspx
Applying this to my code I got the following results:
The actual rotation should be: x:0 y:0 z:-0.52
I also noticed that the y and z changed a lot depending on how I positioned the camera.
The two transform matrices I obtain from the marker detector contain the orientation and translation of the camera relative to one of the markers as explained here: http://www.hitl.washington.edu/artoolkit/documentation/tutorialcamera.htm
I have converted them to XNA format and I know them to work correctly as I can draw the corners onto the screen and it matches up with what the camera is seeing.

The solution I like the most is using quaternions. If you have one orientation described by q1, and other described by q2, you can get from one orientation to the other by
q1=q*q2
being q the rotation you are looking for.
q = q1 * (q2)^-1; q = q1 * conj(q2);
You just have to convert from rotation to quaternion and quaternion to rotation.
Just make sure that you normalize quaternions so the equivalences are true. In the pages I linked you have all the necessary formulas, explanations, even code in Java, c++. Really worth adding to favorites.

Related

How to tilt an object depending on the direction of the player on a spherical map

How do I correctly calculate the rotation angle so that the object dodges the player? It means that whichever side the player comes from, the object must turn away from the player depending on its direction. I want the effect like in the video but without Joint, only rotation angle: https://www.youtube.com/watch?v=GJhiR3SOyXs
I have the answer from this post:
but right now I need it for a spherical map. It looks like this right now:
I have same trees and I got different results for them:
I have correctly result for this tree:
BUT not for this tree:
The coordinates of the correctly tree:
The coordinates of the incorrectly tree (number 1):
The coordinates of the incorrectly tree (number 2):
The coordinates of the incorrectly tree (number 3):
If you're on a sphere you need to use the normal of the ground as the up direction. Since you've probably initially rotated the tree the right way up, you could do the following:
[SerializeField] Transform player;
[SerializeField] float effectMaxDistance=1;
[SerializeField] float maxAngle=50;
Quaternion initialRotation;
Vector3 initialUp;
void Start(){
initialRotation = transfrom.rotation;
initialUp = transfrom.up;
}
void Update(){
Vector3 dir = player.position - transform.position;
Vector3 axis = Vector3.Cross(dir, initialUp);
float angle = (1-(Mathf.Clamp(dir.magnitude, 0, effectMaxDistance) / effectMaxDistance)) * maxAngle;
transform.rotation = initialRotation * Quaternion.AngleAxis(angle, axis);
}
put a rigidbody on each bush.
Set the mass of each bush to 0, so it doesn't move the player (if you want it to push the player, you can set it higher)
Add a spring joint to your bush, and a sphere collider.
sphere collider should mainly cover the bush, and should touch the ground.
Set the connected anchor to right below your bush. (this is in local space, relative to the bush, so maybe set it to (0, -1, 0) or something close)
Set spring and damper, so you can customize.
If you want there to be a max stretch distance (Try spring joint first), you could use a HingeJoint, and add spring onto it
If you notice any unexpected behavior, could you please describe it. thanks :).

Changing the x and y rotation weirdly changes the z too in Unity

I tried to make a first person controller in Unity so that I know every single detail of it. I made the movement, but when I created the camera rotation i simply got stuck. Ok, it worked on the x axis, on the y axis, but why does the z axis also change?
void Update () {
transform.position = Character.transform.position + offset;
float h = Input.GetAxis("Mouse X") * horizontalSpeed;
float v = Input.GetAxis("Mouse Y") * verticalSpeed;
transform.Rotate(h, v, 0, Space.World);
}
When working with rotations and euler angles you have to understand that there are different coordinate spaces, like the object's local space and a world space. the x,y,z directions in world space will always look at the same direction, whereas the local space is the coordinate space of the local object (for example your camera). Thats why I would recommend you to rotate vertically in local space and horizontally in world space.
transform.Rotate(0,h,0,Space.World);
transform.Rotate(-v, 0, 0, Space.Self);
Rotating your camera vertical in local space will change the object's local up axis (y-axis). this is why then rotating around that axis will give you your unwanted result. Just select the gameobject in your Scene view and observe it's local coordinate system while rotating and you might be able to better visually understand.
To also give you a simple,fun reallife example to observe yourself, sit upright on your office chair and look straight ahead and rotate on your chair. If you now look a little upwards or downwards and rotate your head instead you will notice a difference in rotation between rotating your neck and rotating on your chair, which should always have the same up-axis, which is different from the local up axis of your neck.
ps.: there are already many solutions to implement a first person camera, like in Unity's own standard assets, or SmoothMouseLook
Looking at tutorials, following them and trying to understand them might bring you further than trying to figure it out on your own.
Euler angles are weird. When you rotate with euler angles, the rotations stack, and a rotation around one axis changes the other axis of rotation. It's best not to "add" euler angles (essentially what transform.Rotate() is doing) and best to work with them in absolute terms. In this case, your code should keep the "z axis" at 0 if you do the following:
void Update () {
transform.position = Character.transform.position + offset;
float h = Input.GetAxis("Mouse X") * horizontalSpeed;
float v = Input.GetAxis("Mouse Y") * verticalSpeed;
# Get the current euler angle in absolute terms
Vector3 eulers = Character.transform.localEulerAngles;
# now modify that euler angle, creating a new absolute euler angle
eulers.x += h;
eulers.y += v;
eulers.z = 0;
# and now assign the new euler angle back to the transform, overwriting the old value
Character.transform.localEulerAngles = eulers;
}
In general I'd advise against using Transform.Rotate() for... most everything. I would also advise using quaternions wherever you're able. You don't need a complete understanding of quaternions for them to be very powerful.

How to rotate parent to move child in Unity3D?

I have a relatively complicated math problem I need to solve for a game I'm working on in Unity. I've tried a couple things but nothing has worked.
Basically, I need to apply an offset rotation (Quaternion) to a parent, where the result of this rotation is to move its child in a given direction.
To explain it better, the problem would be simple if it could be guaranteed that the parent's forward vector was pointed at the child. Then I would simply create a ghost position by adding the desired direction to the child, and then use a LookAt rotation to rotate the parent to look at that ghost position. (The child doesn't need to be put in a specific position, it just needs to move generally in that direction)
What makes this complicated is that A. the parent could be at any rotation, and B. the child could be at any position relative the parent.
For context, I'm working on a procedural animation system and I'd like to have the bones bend in the direction of the Agent's velocity. With the IK'd bones this is easy, just move the IK. But for the actual bones, I need a way to move a bone in a direction by rotating its parent's bone.
Thanks for any help!
First, we need to have the child's current position and the target position in the coordinate system of the parent. It sounds as if the child's position already is expressed in this coordinate system. Then, if the target position is in world coordinates, you simply do this with the inverse parent world transform:
pTargetLocal = parent.worldMatrix^-1 * pTarget
Once we have this, we want to find a rotation R, such that pCurrentLocal is rotated towards pTargetLocal. Assuming unit vectors (as rotations preserve lengths), this equals:
parent.worldMatrix * pTargetLocal = parent.worldMatrix * R * pCurrentLocal
pTargetLocal = R * pCurrentLocal
Once we have R, we just need to update parent.worldMatrix = parent.worldMatrix * R.
This can be solved by representing R in axis-angle format. The axis would be axis = Vector3.Cross(pCurrentLocal, pTargetLocal) and the angle is angle = Vector3.Angle(pCurrentLocal, pTargetLocal). You can either calculate a quaternion or a matrix from these parameters and multiply it with the current parent transform.
I assumed that the rotation center is the origin of the parent's local coordinate system. You could also rotate about another center to incorporate a translation component.

How to add camera to Matrix4x4 rotation

I am trying to rotate a cube using System.Numerics.Matrix4x4 and SDL2 for graphic output. i have a hard time understanding the Matrix rotation concept.
I can do it, like so:
matrix *= Matrix4x4.CreateRotationX(deg);
matrix *= Matrix4x4.CreateRotationY(deg);
matrix *= Matrix4x4.CreateRotationZ(deg);
Then I'm using Vector3.Transform() on the points in the cube and draw lines between them. Looks... alright, it's rotating in place. But how do I get perspective? How to get a camera into the mix?
What about this method:
matrix *= Matrix4x4.CreateFromAxisAngle(new Vector3(2, 2, 2), (float)rad);
I am not sure how I'm supposed to use the vector there, or what it's supposed to do. My cube grows and stretches out weirdly... see pic of when the matrix is applied 10, 45 and 90 degrees on the cube:
https://www.dropbox.com/s/hui5jvky7cexciq/10_45_90.png?dl=0
How should I do this properly?

Rotation around a point

Can anyone help me with this please
I want to be able to rotate a 3D object around a stationary 3D object. Well there will be no movement involved as I just want to draw the objects at their locations once the game starts and then they will remain there for the remainder of the game.
Say for instance I have a object X that is stationary in 3D space. I then have 2 other objects, Y1 and Y2. Both of these objects are stationary as well and cant be moved. All 3 objects are on the same x and y axis. Lets say X is at (0,0,0) and Y1 is at (0,0,-50). I want to draw Y2 at a 45 degree angle from Y1 around the Y-axis but keep it the same distance from X.
Can anyone please suggest the best way of doing this please?
I have tried the following but that just rotates the object around its origin. So I guess I have to rotate it around the world origin? How is this done?
Matrix.CreateRotationY(Rotation)
I'm not sure what you want, but this is one method for rotate one object around another:
Vector3 Origin; // Stationary Object
float Yaw, Pitch; // Angles
float Distance;
Vector3 OrbitOffset = Vector3.UnitX * Distance;
// Other approach that consider the initial pos of the object to rotate
// Vector3 OrbitOffset = OrbitPos - Origin;
Matrix Rotation = Matrix.CreateFromYawPitchRoll(Yaw, Pitch, 0);
Vector3.Transform(ref OrbitOffset, ref Rotation, out OrbitOffset);
Vector3 OrbitPos = Origin + OrbitOffset; // Final position of the rotated object
if you dont need rotation about more than 2 angles at once, you can use basic Euler method.
see :
http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
thats a mathematical approach tough... but it works..
Just if you want a rotation around multiple axes, you will have serious problems with gimbal lock

Categories