How do I switch between 6DoF and 3DoF in the same scene?

If you have 6DoF devices, and your devices are running in 6DoF mode, we can assume that the content is able to switch between 6DoF and 3DoF.

In Unity, if your content needs to switch between 6DoF and 3DoF, you need to know the following:

Controller and HMD

In 3DoF, controllers are usually in front of your eyes with a fixed transform. This transform keeps a distance from the controllers to your eyes (head), and the distance may not be able to changed according to the controller’s motion. However if you switch to 6DoF, this fixed transform should be removed. Otherwise, there will always be a separation between the controllers and your eyes.

In 6DoF, the controllers are usually put in the same place with the HMD. The place is the position sensor’s origin, Vector3(0, 0, 0). If you switch to 3DoF, the controllers and the HMD will always be fixed at the origin.

If there is no other manipulation to the HMD and the controllers’ GameObject, in the VR world, you will probably see the controller’s model come out from your head and also your head will lie on the floor. We do not think this makes for a good user experience. Therefore, you will need a fixed transform to keep a distance with the controllers and the ground.

Pose Tracker

Set the “track position” of the WaveVR_PoseTracker to false in 3DoF mode. This flag will not update the position to the GameObject’s transform. You can do this in your script.

controllerGameObject.GetComponent<WaveVR_PoseTracker>().trackPosition = false;

Set to “true” if you want to switch to 6DoF mode.

Render

The Render will set the origin type to “system” in each frame when acquiring the pose. The origin decides how the pose’s coordinates (0, 0, 0) should be (the origin can be changed in runtime). If you want 3DoF, you should set the WaveVR_Render’s origin to WVR_PoseOriginModel.WVR_PoseOriginModel_OriginOnHead_3DoF. For details, please see the SDK API’s description.

var render = WaveVR_Render.Instance;
render.origin = WVR_PoseOriginModel.WVR_PoseOriginModel_OriginOnHead_3DoF;

Eye to Head transform

Basic knowledge of Eye to Head transform

The eye to head transform is a transform to change the eye space coordinates to the head space coordinates.

For example, if your left eye sees an apple in front, at position (0, 0, 1), the apple’s actual location in the world is:

HeadPose * EyeToHeadTransform * (0,0,1)

Assume the EyeToHeadTransform is

| 1 0 0 -0.03 |
| 0 1 0     0 |
| 0 0 1     0 |
| 0 0 0     1 |

and the HMD’s transform is

| 1 0 0   0 |
| 0 1 0 1.8 |
| 0 0 1   0 |
| 0 0 0   1 |

We can get the eye’s translation, (-0.03, 0, 0), from the head’s space. The apple is at (-0.03, 0, 1) in the head’s space. The apple is at (-0.03, 1.8, 1) in the world’s space.

We can also get the apple’s position from the world space to the eye’s space by the inversed transforms.

EyeToHeadTransform^-1 * HeadPose^-1 * (-0.03, 1.8, 1)

Differences Between 6DoF and 3DoF

The EyeToHeadTransform may have different values in 6DoF and 3DoF. For example,

left eye in 6DoF
| 1 0 0 -0.03 |
| 0 1 0  0.05 |
| 0 0 1  0.05 |
| 0 0 0     1 |

left eye in 3DoF
| 1 0 0 -0.03 |
| 0 1 0     0 |
| 0 0 1 -0.15 |
| 0 0 0     1 |

The transform’s values in 6DoF are changed according to your HMD. For 3DoF, the values are based according to your head’s rotation center which usually has z with -0.15 for a better user experience.

Once you switch between 3DoF and 6DoF, the EyeToHeadTransform needs to change as well. In the same way, use WaveVR_Render.Instance.origin to change the origin. WaveVR_Render will detect the changes and update the transform for both eyes.