Yes, there’s a solution as long as you’re not using single pass rendering. I have struggled with this too and was just as surprised as you were when I found out about this problem, but got around it by having two cameras when it’s running OpenVR, both placed at the same spot but NOT parents of each other (this is vital, otherwise one eye will go screwy).
Set one camera’s TargetEye to “left” and the other camera’s TargetEye to “right.” This fixes the reflections in the water when using OpenVR.
More detail:
To support all three (Oculus, OpenVR and regular non-VR) here’s how I set things up:
-
Player settings VR SDK list is Oculus first, OpenVR second. This way it will use Oculus library for sure if it’s Oculus and only use OpenVR if it’s Vive or whatever else uses OpenVR. (If you have OpenVR first in the list it will use that even if it’s Oculus, so make sure the order is Oculus first, OpenVR second if you aim to support both SDKs which a Unity staff member recommended.)
-
In each scene I have one parent root object for the camera(s) which you probably already have if you’re doing VR. Under that goes the (now two instead of one) cameras. Again, make sure the cameras are siblings of each other and not child/parent. They must have the same position/orientation, don’t try to get fancy and move one to be at the actual position of left or right eye, just treat them like two identical copies of your one current camera you have now. Unity figures out what to do from there and move them appropriately. Their transforms will always match.
These two cams are set initially in the scene to TargetEye “left” and “right” respectively as described.
- This extra camera is only needed for OpenVR in order to make the water reflections work, so when a scene starts, I destroy one of the extra cameras if we’re not using OpenVR. Then we’re just back to what you probably have now: One camera in the scene.
In my case it matters which camera is actually destroyed because I’m doing some weird custom particle effects in a compute shader attached to one of the cameras and have to make sure not to do them twice or delete the camera that’s running the compute shader, so I have an empty class called DestroyIfNotOpenVR that I put on the camera that should be destroyed if we’re not running the OpenVR SDK. You probably don’t need to do this, it might be fine for you to just destroy either one of the cams and go on your merry way. However, just in case there’s some reason you care which cam is destroyed and which one is left, here’s how I do it:
This is done one time in a scene manager:
void Awake()
{
if (VRSettings.loadedDeviceName == "Oculus" || GameManager.riftMode == false)
DestroyExtraCamForOpenVR();
GameManager.riftMode is my own class and field that’s set true if any virtual reality device is running (Rift or Vive, doesn’t matter). It would probably be better to do it like this instead:
if (VRSettings.loadedDeviceName != "OpenVR")
DestroyExtraCamForOpenVR();
Now the extra camera is destroyed by searching the scene for anything with a DestroyIfNotOpenVR component on it:
private void DestroyExtraCamForOpenVR()
{
DestroyIfNotOpenVR [] destroyIfNotOpenVR = Resources.FindObjectsOfTypeAll<DestroyIfNotOpenVR>();
for (int i = 0; i < destroyIfNotOpenVR .Length; i++)
{
DestroyImmediate(destroyIfNotOpenVR [i].gameObject);
destroyIfNotOpenVR [i] = null;
}
}
The remaining camera then has its TargetEye set to “both” so the Oculus will run normally in both eyes as it did before:
if (VRSettings.loadedDeviceName != "OpenVR")
{
Camera cam = .....//the remaining camera
cam.stereoTargetEye = StereoTargetEyeMask.Both;
}
If it’s not VR at all then it doesn’t matter what eye it’s set to. I actually just leave it as left eye but the above is probably better anyway just so it runs 100% of the time that it’s not OpenVR.
Presto, water reflections work the same in both OpenVR and Oculus, but only in multipass rendering mode, and you’re left with one camera in the scene unless it’s OpenVR. Single pass rendering is unfortunately not working with Unity’s water asset.