2D water reflections in Unity 5

Some people asked me how I’m doing the water reflections in Last Voyage Of The Orlova, so here’s a quick look at the shader. Download at the bottom of the post.

I’m 90% sure I got the base code from this Unify community shader, so I can’t take any credit for inventing this, but the shader didn’t behave quite like I wanted it to and threw some errors in Unity 5, so I hacked some stuff together to get the effect you see below.

UPDATE:
I edited the reflection shader to support tinting, so now you no longer need a texture to give the water color. I have a limited understanding of shader programming so it might not be 100% perfect – for instance it doesn’t support transparency (though that can be easily added by changing the RenderType). I also updated the script to use the newer MirrorReflection4 code which was written for Unity 5.

 

This solution consists of two components: a shader for the groundwork, and a script to render it on a 2D plane (or quad in this case).

The shader has a texture slot and a color picker. The texture is optional, you can just change the water color using the color picker.

The script has settings for the reflection resolution, offset, and which layers should be reflected. I keep the resolution intentionally low (256) because otherwise the reflection is too perfect and it doesn’t look like water anymore. And I like the way it shimmers when you walk.

I’ve packaged the files up so you can try this in your own project right now:
Click here to download.
Let me know here or on twitter if you use it, I’d love to see it in action in other places.

If you’re looking to add waves (with physics!) to the water surface, the Zippy Water 2D asset is pretty good. I tried it and this method works on their water prefab.

Known issues:
When working in Unity, you sometimes get a never-ending Screen position out of view frustum error in the console. This is because the camera is rendering the reflection using the resolution setting (0, 0, 256, 256 by default) which falls outside of Unity’s camera bounds (0, 0, 1, 1). If you turn off the script on the water object, or turn off 2D mode for the scene view, the error will stop (it seems it needs at least one perspective camera active to make sense of what it’s doing). While annoying, this error shouldn’t affect any standalone builds, and is a known issue with the Unity engine.
It looks like changing line 72 in MirrorReflection.cs from reflectionCamera.projectionMatrix = projection; to reflectionCamera.projectionMatrix = cam.projectionMatrix; stops the error.

 

 

15 thoughts on “2D water reflections in Unity 5

    1. Oh yeah good point, I talked about coloring the water but didn’t include the texture, woops! Just make a little square image with whatever color you want the water to be, import that into Unity, then set the texture’s wrap mode to repeat and put it into the water shader component’s texture slot, and then your water should be colored.

      Like

  1. Hi HedgeField, I’m delighted to find your article since I am trying to do a 2d reflection in unity too. I used the instructions from Unify with your code, but I’m getting some lag + lots of errors:

    Screen position out of view frustum (screen pos 512.000000, 0.000000, 252418.296875) (Camera rect 0 0 512 512)
    UnityEngine.Camera:Render()
    MirrorReflectionTwoDimension:OnWillRenderObject() (at Assets/Scripts/MirrorReflectionTwoDimension.cs:101)
    UnityEditor.DockArea:OnGUI()

    Do you know what might be the issue? I’m using the code on a quad, placed on the water surface.

    Like

    1. Hey there! From your post I couldn’t fully understand whether you used the original Unify code or the code from the download in my blogpost? Are you on Unity 5? I’ve seen this error once or twice before but I’m not sure what causes it yet. Some people have solved it by switching the camera between orthographic and perspective, making sure the near clipping plane is not set to zero, or closing and reopening the game and scene windows. I hope one of these solutions work for you! http://forum.unity3d.com/threads/solved-screen-position-out-of-view-frustum.60851/

      Like

    2. Hey so I looked into that error some more and it looks like it’s a problem with Unity itself. I added my understanding of it to the Known Issues section in the updated post above. Hope that helps!

      Like

  2. Thanks a ton!
    And about the annoying “Screen position out of view frustum” error I got it work by changing in the MirrorReflection class. More details, I comment out the line 72 (approximate) “reflectionCamera.projectionMatrix = projection;” and add this “reflectionCamera.projectionMatrix = cam.projectionMatrix;”. I just guess the far/near info of the reflectionCamera was just not right, so it caused the error. After changing it no longer spams errors, no more! Yeah.

    Liked by 1 person

  3. Hi, its wonderful,

    But i have an issue with canvas screen space camera, Quad object added Reflection Script and It will over GUI canvas (2D Game).

    Please help me fix this issue ?

    Thanks

    Like

    1. Hey there, I see the problem. To fix it, set the Plane Distance on the GUI canvas to 1, and the Order In Layer to something like 5000. Or switch the GUI to Screen Space – Overlay mode.

      Unity renders alpha-tested things (like 2D graphics) before it renders transparent objects, so by changing those values you force the screen-space GUI to render over the water.

      (Unity render queue order: background=1000, geometry=2000, alpha test=2450, transparent=3000, overlay=4000)

      Like

  4. Hi,
    Thank you for this script, it is really helpful !

    Personally, I replaced the offset parameter by a Transform object that I use as a pivot, so that moving the mesh does not affect the reflection plane.
    I’ll probably also update it to add movement to the water (Such as in Kingdom:New Lands)

    Anyway, thanks again, it work great !

    Liked by 1 person

  5. Hey, this script is awesome and I am using it with the Zippy 2D water, but I notice that all my sprites render on top of the water, but I actually want my floor to look partially submerged. Any way that I can get this to render on top of sprites? I have tried changing the layer order inside the zippy script, but that only works with a standard sprite shader, not your reflection shader?
    Thanks!

    Like

    1. Never mind, fixed by adjusting the rendering queue, which I had already done but didnt seem to work, so not sure why its suddenly started working now…

      Like

      1. Ah glad you figured it out! Unity can be weird like that. Yeah you have to set the render queue in the water material inspector. If need be you can manually increase the number even further to make sure it renders in front of everything you need it to. And thanks for the praise!

        Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s