FOVE's Eye Tracker returns the gaze direction (both the combined gaze and the individual gaze) as directional unit vectors. They are just vectors that point in the given direction of the gaze.
As unit vectors, the magnitude is always one. This is simply a convenience as it will still point in the same direction regardless of the length.
In the HMD coordinate system, which is always used by the FOVE SDK (including C/C++/Python bindings), the gaze vectors always represent the direction of the gaze relative to the users head.
X axis represents the horizontal direction (negative left, positive right).
Y axis represent the vertical direction (negative down, positive up).
Z axis represents the forward direction (negative is behind the users head, positive is in front).
Since the users eyeball cannot rotate backwards (and if it did, we would loose tracking anyway), in practice negative Z values are never used. Also, fully to-the-right for example (1, 0, 0) is not possible. If you ever get such values, it's a bug or a very inaccurate result, and you should let us know.
When tracking is lost we return a data error in the SDK (Data_Unreliable), so we recommend you check error codes. Just for consistency, in these cases we set the data value to (0, 0, 1). If, in lieu of checking errors, for example if you're looking at some recorded data stream without errors saves, and you see (0, 0, 1), it generally means that there's an error. The actual likelihood of getting an exactly 100% forward result is low. It's much more likely to see numbers like z=0.9853 from real data.
Please note the FOVE Unity plugin has other coordinate systems which change the reference direction (eg. including the headset rotation or in-engine transform object). These are not discussed in this article, but the principles are the same.
How can I take the angular difference between two different gazes?
The angle between two vectors is the inverse cosine of the dot product. So, as a simple example:
If initially the eye is looking forward, you will get a value of V0=(x=0, y=0, z=1).
Later, let's say the eye looks right, and you get a value of V1=(x=0.7, x=0, z=0.7)
dot = V0.x * V1.x + V0.y * V1.y + V0.z * V1.z = 0 * 0.7 + 0 * 0 + 1 * 0.7 = 0.7
angle = acos(dot) * radiansToDegrees = 0.795 * 180 / PI ~= 45 degrees
How can I get the X / Y angles?
Since we want 2D angles, we need to discard one axis to get a 2D vector, then take the angle. To take the angle of a 2D vector we can simply use arctangent.
For X axis, discard y, and pass x/z to atan: xangle = atan(v.x / v.z) * radiansToDegreesConstant = atan(0.7 / 0.7) * 180 / PI ~= 45 degrees
For Y axis it is y/z to atan: yangle = atan(v.x / v.z) * radiansToDegreesConstant = atan(0/ 0.7) * 180 / PI ~= 0 degrees
If your math library has it, prefer atan2 to atan