googlevr / gvr-android-sdk

Google VR SDK for Android
http://developers.google.com/vr/android/
Other
3.28k stars 1.28k forks source link

Unexpected behavior of positional coordinates for 6DOF HMD (Lenovo Solo) #584

Open MikhailAMD opened 6 years ago

MikhailAMD commented 6 years ago

I observe unexpected behavior of positional coordinates for 6DOF HMD (Lenovo Solo). I've added some code to "ndk-hellowvr" sample to demonstrate this: I get matrix by calling gvr_get_head_space_from_start_space_transform() and decompose the matrix into position and Euler angles and log them. The library I use for decomposing is a copy of MSFTs DirectXMath (XMMatrixDecompose). The actual data have some noise in values.

log details: pos(x,y,z) in meters; euler(roll, pitch, yaw) in degrees

  1. For application starting place I get: pos(0,0,0) euler(0,0,0) - correct
  2. Make one step back: pos(0,0,-0.4) euler(0,0,0) - correct; Z coordinate changed
  3. Turn head right 45 degrees: pos(-0.28,0, -0.28) euler(0,0,45) - wrong; why does X and Z positions have changed? expected: pos(0,0,-0.4) euler(0,0,45)
  4. Turn head right another 45 degrees to 90 degrees: pos(-0.4 ,0,0) euler(0,0,90) - wrong; why X and Z position changed? expected: pos(0,0,-0.4) euler(0,0,90)

It almost looks like rotation returns in reset point coordinate system but position coordinate system changes with rotation. It may happen when order of matrix multiplication is wrong.

sigmaxipi commented 6 years ago

You are right that the order of matrix multiplication is different from what you expected. The gvr_get_head_space_from_start_space_transform() API was meant for use when rendering the scene from the camera pose. If you want to extract the head position, you need to use the inverse of this.

Also, note that the value in step 2 above is incorrect. In OpenGL, if you step backwards, the Z position of your head in the world will increase. However, the position of the world with respect to your head will decrease. Similarly, you should check the value in step 3 since turning your head to your right will cause your head's yaw to decrease.

If you want to extract the head's position & rotation, you want to take the inverse of the gvr_get_head_space_from_start_space_transform() matrix and read the translation from that matrix. You can use a standard matrix inverse algorithm, but this may be slow. You can also take advantage of the fact that the head pose is a rotation + translation matrix and have something like:

  head_space_from_start_space_rotation = extract_rotation(head_space_from_start_space_matrix);
  head_in_world_rotation = transpose(head_space_from_start_space_rotation); // The transpose of a pure rotation matrix is the same as its inverse but faster to calculate
  head_in_world_position = -1 * head_in_world_rotation * head_space_from_start_space_matrix;
MikhailAMD commented 6 years ago

Yes, I figured out a simple correction. But you may consider to change documentation which currently states: "Gets the position and rotation from start space to head space. The head space is a space where the head is at the origin and faces the -Z direction." To something like: "Gets transformation matrix that converts coordinates from start space to head space" Thanks