Search Unity

[SOLVED] Rendering pixels only behind a certain plane for Water Reflections

Discussion in 'Shaders' started by swanijam, Sep 7, 2018.

  1. swanijam

    swanijam

    Joined:
    Nov 14, 2016
    Posts:
    23
    So I'm developing some water visual effects for a virtual reality project I'm working and have spent some time on the reflections. The project takes place in a river environment, which we hope to have bustling with fish and assorted objects underwater. I've tried a few strategies for the water visuals, each so far with its own pros and cons:

    1. Using depth on a transparent shader to apply a highlight color wherever the water is shallow.
    pros
    : this is a relatively simple and cheap effect that looks pleasant and doesn't require any more setup in the scene than applying the material
    cons: does not include reflections. Most of the really stunning water i've seen involves highly reflective water, and I'm into that, so this is a big con.

    2. Using screen space reflection.
    pros:
    relatively light scene set up, and depending on the SSR implementation, looks great
    cons: not compatible with transparent shaders, as SSR requires that the water surface write to depth in order to do its raymarching calculations. I'd really like to see the fish, so, I'm not satisfied yet with this one.

    3. Using reflection probes.
    pros:
    compatible with a transparent shader. Capable of making the water look reflective but allowing transparency to show things under the water.
    cons: reflections don't line up with the objects above the water. This is extremely offputting if you water's bump/normals aren't very noisy.

    4. extra camera under water, mirroring the abovewater camera.
    pros
    : compatible with a transparent shader, as the reflection comes from a render texture. reflections look GREAT. This strategy has had the most promising appearance so far, so I'm really hoping to make this work.
    cons: has a lot of trouble when objects have a great portion of their volume underwater than above. the mirror cam can sometimes have underwater objects obstruct the ones above water, creating incorrect reflections. Here's what I mean:

    Capture2.JPG

    In the first image, that relfections are mostly correct, and look awesome. Nice. I hope there aren't any excep-

    Capture.JPG
    tions. Darn it. Here's the same sphere copied three times, moving progressively deeper into the water.
    As you can see, the third sphere ends up occupying enough underwater space that its underside is visible behind its topside.


    diagram.png Here's a bad diagram of the problem. Everything under that blue (the water surface) is visible to the mirror camera, even though the mirror camera is only interested in what exists above the line.

    diagram2.png

    The goal is to be able to flip the image of the world above the water as seen from below. When you look at a reflective surface, the light bounces off at an angle. If instead of trying to 'reflect' light, we use the mirror camera to look along the resulting angle.

    However, things below the water can get in the way.

    I'd like to be able to tell the camera not to render things below the water surface. There's a few ideas I've had but I haven't yet managed to think any through to a feasible solution:

    a revealing plane:

    usually 'revealers' are just geometry that writes to depth but not to color. This doesn't work for this case because the geometry that doesn't get depth masked can still be underwater - or, i have yet to think of a shape for the depth masking object that would work. Other revealers user stencil masks to reveal objects inside the stencil. This would require me to use a custom shader for a every single object that should be reflected using the stencil mask, and doesn't resolve the issue of objects still writing to depth even if their pixels get clipped. ( i might be misunderstanding how stencil-based clipping works. Maybe there is a way to use stencils for this? )

    carefully managing all the geometry in every scene to avoid putting anything below the surface:
    One of the original reasons for trying this solution was so that I could see fish and terrain and underwater vegetation. Avoiding that would defeat the point.

    Having a duplicate scene for the mirror cam to view that doesn't involve subsurface objects.
    sounds like a mess and a cpu hog, and becomes less and less managable the more stuff I put in my scene.

    Using in a oblique camera near clip plane.
    This seems like a possibility, but the correct near clip plane would eventually just be parallel to the camera's forward vector, and after moving even further would go from intersecting with the top of the camera frustrum to intersecting the bottom of the camera frustrum. I'm not sure if that amount of flexibility is possible with an oblique frustrum. Also, i think oblique camera frustrums can warp an image. Also, this is a VR app, and some fo the properties of the left/right camera eyes is managed by the SDKs I'm using. I'll continue to look into this if this option looks promising.

    Using custom shaders for all reflecting objects that clips self when a pixel is below a certain y position.
    In addition to being a lot of work to set up, this strategy wouldn't prevent a pixel from writing to depth when it got clipped, as the depth gets written before the fragment shader is run. This means that there would be no reflection instead of an incorrect reflection, and that objects could cut holes out of distant objects if they were positioned in a certain way.



    If anyone could offer a potential strategy for correctly clipping beneath the water plane so that I can use the mirror camera strategy, OR offer a potential strategy for using Screen Space Reflections with a transparent water surface, I would appreciate it very very much!

    Thank you! :D
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    swanijam likes this.
  3. bart_the_13th

    bart_the_13th

    Joined:
    Jan 16, 2012
    Posts:
    498
    isnt the standard water asset do the reflection nicely? or is it too heavy?
     
    swanijam likes this.
  4. swanijam

    swanijam

    Joined:
    Nov 14, 2016
    Posts:
    23
    This ended up being the key! It turns out that the solution I was trying to work through was actually the same strategy that Unity Standard Assets water uses. I overlooked it because it was incredibly slow and I didn't realize that only a few adjustments would have got me where I wanted.

    The script MirrorReflection4 above ended up being what I used, although it doesn't work in VR due to stereo rendering. I found another thread where people provided stereo options: https://forum.unity.com/threads/mirror-reflections-in-vr.416728/

    I recommend the threads above, or even just using Water Pro.

    Apologies for not wrapping this thread up after I asked it!
     
  5. JanMaza

    JanMaza

    Joined:
    Feb 9, 2021
    Posts:
    2
    Hey! I know it's been a while, but I am struggling with this as well. Sadly the first link doesn't work. Can you share the script MirrorReflection4?