- Home /
Calculating offset for different rotations
Excuse me for a vague title, I don't really know how else to explain it.
So, I'm developing my graduation project, which is a VR game with a home-made VR controller. the controller is a gun which contains a gyroscope to measure the angle of the gun. Through a bluetooth connection I push the 3 axis to unity.
Now, in unity, I have a google cardboard setup, with my FPS gun prefab attached underneath it as a child:
The gameobject with name VR setup
rotates with the direction of the player his or her head. The Gun holder object has a FPS model with a gun pointing straight forward at a local rotation of 0, 0, 0.
Now, when I start the game with my gun straight forward, everything works fine. I am able to rotate my head around, and the gun is alligned with the controller I am holding. Now, because the gun-controller can, for example, lay on my desk when launching the game, and pick it up and hold it straight forward, it'll be in a different angle, and I actually have to point the gun to the left, right, up, or whatever direction to get it in front of my in-game.
To catch this, I added a button to my gun controller. The idea behind this is that the user can hold the gun straight forward, and when the button is pressed, it'll sync the in-game gun straight forward too.
Solid plan? yes, if it would work.
I'll explain what I tried here:
public void GetRotation() {
newRot = Quaternion.Euler(z, x, -y);
if (isSync) {
isSync = false;
syncRot = objectVisual.transform.rotation;
}
newRot *= Quaternion.Inverse(syncRot);// * Quaternion.Euler(0, -30, 0) ;
//newRot = Quaternion.Euler(newRot.eulerAngles.x - syncRot.eulerAngles.x, newRot.eulerAngles.y - syncRot.eulerAngles.y, newRot.eulerAngles.z - syncRot.eulerAngles.z);
}
The function GetRotation
gets called every frame, right after I received and decoded my bluetooth data into the global variables x, y and z. Because the gyroscope is not alligned in my gun to it's own axis, I had to switch some of these values to create the Quaternion called newRot
.
EDIT: objectVisual is the gameObject called gun holder in the hierarchy picture! The newRot is also applied to the objectVisual, or gun holder gameobject. Because it is a child of the head rotating transform, substracting the localrotation from itself should put it to 0, right?
When the button was pressed on my gun controller, it'll set the isSync boolean to true so I know I want to update my syncRotation the next time I calculate my rotation.
Now, when I want to sync, I grab the current rotation on the gun and subtract is from the new rotation I decoded from my bluetooth device.
I made a nice drawing to explain it some more:
So, if I was to press the synchronize button on my gun, this should happen:
The received rotation from my bluetooth device is (0, 45, 0), my in-game rotation is (0, 0, 0). The sync rotation should be (0, 45, 0), because every frame, we're gonna subtract the sync rotation from the received rotation, to get it synchronized straight forward => newRot = newRot - syncRot => newRot = (0, 45, 0) - (0, 45, 0) = (0, 0, 0), right??
The result however, is that it only snaps to (0, 0, 0) when it's a little bit away from (0, 0, 0). When I point my arm completely to the right, it synchronized to something like (0, 20, 0). Actually it's always different with a different angle :(
Is there something wrong with my code? I have tried many different ways, such a substracting euler values, or raw x, y, z, w values, but nothing seems to work.
Thanks guys, and sorry for this big ass long post.
Have you tried multiplying the quaternions in the opposite order? Quaternion multiplication is noncommutative, so it doesn't hurt to double-check that you have them organized properly.
For example:
if (isSync) {
isSync = false;
syncRot = objectVisual.transform.rotation;
invertRot = Quaternion.Inverse(syncRot);
}
newRot = invertRot * Quaternion.Euler(z, x, -y);
Yea quaternion are indeed noncummutative.
Your suggestions works, but only the first time I run the game and press the button. When I try this again, it spits out weird values.
One step closer, but still far away :( Thanks a lot for this
Answer by See_Sharp · Jun 03, 2016 at 11:28 AM
Phew, I found it.
public void GetRotation() {
if (isSync) {
isSync = false;
Quaternion offset = Quaternion.Inverse(objectVisual.transform.rotation * Quaternion.Inverse(headParent.transform.rotation));
syncRot = offset * newRot;
}
newRot = syncRot * Quaternion.Euler(z, x, -y);
}
So, with a lot of thanks to @Eno Khaon I figured it out. The problem was that I just can't overwrite my offset, because the rotation depended on it. All I had to do it multiply it and poof! Easy solution tho.
I still hate quaternions. And I always will.
Your answer
Follow this Question
Related Questions
quaternion - rotate camera based on original facing at scene start? 0 Answers
Make Quaternion affected by float 1 Answer
Need help with storing Rotation in a Quaternion 1 Answer
Adding quaternions using a seperate axis 0 Answers
Copy rotation of targetObject to current object with an influence in the range from 0-1. 0 Answers