Forum Discussion
AndyTheBald
12 years agoHonored Guest
The eye pose, and left-handed game engines
Hi there
I'm struggling at the moment combining the pose's orientation with our view matrix, in our left-handed game engine.
If I convert the quat as-is to a matrix, and then multiply it by our view matrix, then if I Pitch down the view pitches up, roll left, the view rolls right, yaw left and the view yaws right.
If I invert the quat, then for simple movements from the reference pose, then everything moves in the correct direction. However if I pitch the hmd 90deg down, and then roll the hmd 90deg left, it produced the wrong transform. It's as if it has rolled, and then pitched.
Logically, this makes sense, as internally you could consider the pose quat as the combination of the 3 axis rotations (I'm not sure which order you actually apply heading/pitch/roll, but I believe that's irrelevant). Inverting it, will be the inverse of the 3 individual rotations applied in the opposite order - which matches what I see.
So what I've been struggling with is coming up with a transform, which I can apply to the pose, that gets everything working right. I feel there ought to be a simple transform which corrects this, but everything I've tried hasn't worked.
How do you solve this?
Cheers
Andy
I'm struggling at the moment combining the pose's orientation with our view matrix, in our left-handed game engine.
If I convert the quat as-is to a matrix, and then multiply it by our view matrix, then if I Pitch down the view pitches up, roll left, the view rolls right, yaw left and the view yaws right.
If I invert the quat, then for simple movements from the reference pose, then everything moves in the correct direction. However if I pitch the hmd 90deg down, and then roll the hmd 90deg left, it produced the wrong transform. It's as if it has rolled, and then pitched.
Logically, this makes sense, as internally you could consider the pose quat as the combination of the 3 axis rotations (I'm not sure which order you actually apply heading/pitch/roll, but I believe that's irrelevant). Inverting it, will be the inverse of the 3 individual rotations applied in the opposite order - which matches what I see.
So what I've been struggling with is coming up with a transform, which I can apply to the pose, that gets everything working right. I feel there ought to be a simple transform which corrects this, but everything I've tried hasn't worked.
How do you solve this?
Cheers
Andy
13 Replies
- cyberealityGrand ChampionWhat engine/API are you using?
- jhericoAdventurer
"AndyTheBald" wrote:
If I invert the quat, then for simple movements from the reference pose, then everything moves in the correct direction. However if I pitch the hmd 90deg down, and then roll the hmd 90deg left, it produced the wrong transform. It's as if it has rolled, and then pitched.
First off, quaternions don't have handedness. You do need to ensure that you have the correct X/Y/Z mappings when using a quaternion, but handedness is something that's accounted for at the time of conversion from a quaternion into another type that does include handedness (like Euler angles or a matrix).
The reason you have to invert the quaternion when applying it to the modelview matrix is that the head pose is in user/camera space, while the modelview matrix is in view space, which is the inverse of user space.
Depending what math library you're using you can take a variety of approaches. The OVR C++ math library Quat type includes a GetEulerAngles(T *a, T *b, T *c) method that allows you to specify the handedness and direction of spin for each axis. If you copy the head pose ovrQuat into that type you should be able to get the Euler angles you need for your handedness and construct you matrix from that. - AndyTheBaldHonored Guest
"cybereality" wrote:
What engine/API are you using?
It's a proprietary engine I'm contracting to add some VR stuff to. So this is being done with the CAPI (and not with SDK render, as their Present() is a bit intertwined). I've looked over the C++ API, but don't really feel it will help. I have full source of their maths + render code, and don't see anything erroneous in the maths (have replaced all their key fn's with my maths lib, to the same effect, just to rule out any weirdness there).
I do have to transpose your left-handed projection matrix. When I do that, then I get what appears to be the non-centered version of the same viewport that I get without uploading your projection matrix at all, so I believe that's working. - AndyTheBaldHonored Guest
"jherico" wrote:
handedness is something that's accounted for at the time of conversion from a quaternion into another type that does include handedness (like Euler angles or a matrix).
Hi Brad
Thanks for taking the time to reply. I am converting from a quaternion to a matrix, and doing the multiply with the two matrices, as there's no Mat * Quat in their maths lib. Are you saying there are two forms of quaternion => matrix? I've scoured the net, suspecting that may be the case, but didn't find an alternative implementation.
I was really keen to avoid going via Euler angles, as I thought you got a singularity/gimbal issue ?
I was unsure whether the pose should be applied to the camera's matrix, or the view matrix and have tried both, to no success.
Andy - AndyTheBaldHonored GuestHi Brad
Sorry, just reread your link, and saw the link off that to osdir.com. So the two forms are just the transpose of each other? - In which case, I've certainly tried both ways around. - vrdavebOculus StaffInstead of inverting the quaternion, try pre- and post-multiplying the rotation matrix you get by a [-1, -1, -1] scaling matrix. [-1] *
* [-1] - AndyTheBaldHonored GuestThank you so much, the pre- and post- transform scaling did the trick.
For the benefit of anyone else out there, the transform that worked for me was just on 2x axes: S = [-1, -1, 1], so, view = view * S * R * S. - AndyTheBaldHonored GuestTo further qualify that, as it bugged me why I had to pre/post scale by 2x axes. If you multiply out the algebra, you will see that a pre/post scale of [-1, -1, 1] is identical a pre/post scale of [1, 1, -1] (negating the [0][2], [1][2], [2][0], [2][1] terms of the resulting matrix).
Now that makes perfect sense, and I feel comfortable writing:
The ovrPosef.Rotation is supplied as a quaternion encoded around an axis system, where X is right, Y is up, and Z is out of the screen (right-handed). If this does not match your game's coordinate system, then you will need to transform your matrix into the OVR coordinate system to combine with the pose's rotation, and then transform the result back to your coordinate system. This is typically done by scaling the axis/axes which do not match the OVR axis system.
e.g. if your engine uses a left-handed axis system where X is right, Y is up and Z is into the screen, you will pre and post multiply by the diagonal scaling term S =[1, 1, -1] to flip the Z axis prior to combination with the OVR pose.//Convert to X=right,Y=up,Z=in
S = [1, 1, -1];
viewMat = viewMat * S * R * S;
Does that sound correct?
(I hereby place this post into the public domain, and am free to do so - Cyber/Brad please feel free to use) - AirstrikerHonored GuestYou've made my day! Thank you so much! This works like a charm!
- owenwpExpert ProtegeTo be clear, for anyone else with similar problems, quaternions absolutely do have a handedness. The imaginary part (x,y,z) is a vector in the same coordinate space as any other vector in your engine, pointing along the axis of rotation.
As an example, a 90 degree rotation about the Y axis would be expressed in quaternion form as the unit vector (0, 1, 0) multiplied by sin( 90 / 2 ), with a w component of cos( 90 / 2 ). That unit vector is a direction in your coordinate space, so its handedness is the same as any other vector you might use. So if you need to convert it to a different coordinate space you do the exact same transpositions and negations of the XYZ components that you would do for those other vectors.
If you were going from a Z up to a Y up coordinate system, you would reorder the components like this:
myQ = {q.x, q.z, q.y, q.w}
Just think of a quaternion as a scaled axis vector plus an angle.
Quick Links
- Horizon Developer Support
- Quest User Forums
- Troubleshooting Forum for problems with a game or app
- Quest Support for problems with your device
Other Meta Support
Related Content
- 6 months ago
- 2 years ago
- 9 months ago
- 3 years ago