Search Unity

Am I missing something obvious or are water reflections broken in steamVR

Discussion in 'AR/VR (XR) Discussion' started by Custard1, Mar 4, 2017.

  1. Custard1

    Custard1

    Joined:
    Aug 14, 2012
    Posts:
    6
    Surely I am not the only person using water in steamVR. The reflections are offset to each eye in all water assets I have tried. Seem fine in OVR.

    Has anyone else encountered this issue?

    Please someone save my sanity, even its just to confirm that this issue really exists, please, oh heavens PLEASE!

    Thanks
     
  2. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,062
    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:

    1) 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.)

    2) 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.

    3) 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:
    Code (csharp):
    1.  
    2. void Awake()
    3. {
    4. if (VRSettings.loadedDeviceName == "Oculus" || GameManager.riftMode == false)
    5.             DestroyExtraCamForOpenVR();
    6.  
    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:

    Code (csharp):
    1.  
    2. if (VRSettings.loadedDeviceName != "OpenVR")
    3.             DestroyExtraCamForOpenVR();
    4.  
    Now the extra camera is destroyed by searching the scene for anything with a DestroyIfNotOpenVR component on it:

    Code (csharp):
    1.  
    2. private void DestroyExtraCamForOpenVR()
    3. {
    4. DestroyIfNotOpenVR [] destroyIfNotOpenVR = Resources.FindObjectsOfTypeAll<DestroyIfNotOpenVR>();
    5.         for (int i = 0; i < destroyIfNotOpenVR .Length; i++)
    6.         {
    7.             DestroyImmediate(destroyIfNotOpenVR [i].gameObject);
    8.             destroyIfNotOpenVR [i] = null;
    9.         }
    10. }
    11.  

    The remaining camera then has its TargetEye set to "both" so the Oculus will run normally in both eyes as it did before:


    Code (csharp):
    1.  
    2. if (VRSettings.loadedDeviceName != "OpenVR")
    3.             {
    4.                 Camera cam = .....//the remaining camera
    5.                 cam.stereoTargetEye = StereoTargetEyeMask.Both;
    6.             }
    7.  
    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.
     
    Last edited: Mar 5, 2017
    Akshara likes this.
  3. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,062
    By the way, if Unity fixes this OpenVR problem with the water, it would be nice if staff could say so here so I can update the above post accordingly. Please look at single pass rendering too, it's totally borked in OpenVR (water or not) and water in Oculus single pass doesn't work right either. Hopefully some day!
     
    ROBYER1 likes this.
  4. ROBYER1

    ROBYER1

    Joined:
    Oct 9, 2015
    Posts:
    282
    Would be great to have some kind of single-pass water shader for my projects, did you find anything that works? This seems to be the only asset I can find that apparently works with single pass forward VR rendering (so hopefully the Oculus Quest/Go)
    https://assetstore.unity.com/packages/vfx/shaders/realistic-water-33434