2D water reflections in Unity

2D water reflections in Unity

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.

The solution consists of two components: a shader for the groundwork, and a script to render it on a quad.

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.

To get started, add these files to your project’s Assets folder, and drag the reflection prefab into your scene. You can adjust the size and position of the prefab to your needs.

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 applied this shader to their water prefab and it works.

0 thoughts on “2

  1. Hey. Your shader works amazing, i got a question though. How do you manage to get a colorfull water? When i tried it, it was like mirror.

    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.

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

    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/

    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!

  3. 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.

  4. 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

    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)

  5. 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 !

  6. 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!

    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…

      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!

  7. I was so happy to find this resource…unfortunately I don’t see how to make it work 🙁
    Does the quad need to be perpendicular to the sprites to be reflected? I doubt, it would prevent to use an orthographic camera! So the quad is co linear to the sprites?
    How does it come that moving view in scene editor seems to change the reflection on the quad?
    I may surely sound a little bit stupid…but I will face it cause I need to be able to use this resource! 😉
    Would you please have some time to tell me how to proceed to get a good result?..or point me to a downloadable scene with your script/shader in action, please?

    1. Hi there Jayme, thanks for getting in touch. I realize I didn’t give explicit instructions on how to set this up, so I can understand your trouble. I’ve created a test project that you can download from http://timhengeveld.com/files/reflectiontest.zip. It’s made in Unity 2017.2, and shows how the shader should be applied. I also updated the original download link with some extra stuff needed to get started.

      1. p.s. If you change to position or size of the reflection quad and the reflection looks strange, try adjusting the clip plane offset value on the mirrorreflection script. Negative values move the reflection down, positive values move it up.

  8. thank you very much for this! but I’m having some problems, my game is top down, I could make the reflection be in the right place (by creating a variable to say if this specific water should use transform.up, transform.right etc…) but I also need to rotate all the reflection so it doesn’t look like everything is face to face, what would be the best approach to do this?

  9. Hi Dralks, I’ve tried to find a way to rotate the reflections 180 degrees (which I think is what you want, right? Now your character is reflected vertically but it has to be reflected horizontally) but unfortunately I have not found a solution yet. I’m sure it’s possible but it’s a little too complicated for me.

    If it is important to you to have this, perhaps https://assetstore.unity.com/packages/vfx/shaders/pidi-2d-reflections-111417 is something to check out? It has a lot more features, although I cannot say with 100% certainty that it would work for you, but at least worth it to investigate.

  10. Wow this is a super awesome shader!! Is it is possible though for the shader to have transparency in areas where it doesn’t detect an object in its Reflect Layers? Currently the shader shows background color as whatever color is currently on the camera (or skybox) and I would rather have it be transparent in those areas for my project. I don’t have any experience with shaders and was wondering how (if possible) I could get it to render the camera’s background color as transparent.

    1. Hi Natalie, thanks for the kind words! The script renders a reflection based on what the ‘fake’ mirror camera picks up, but unfortunately you cannot disable the skybox rendering of a camera (at least as far as I know). Even turning off everything under a Camera’s culling mask still shows the skybox/background color, it cannot be set to render transparency. You can lower the alpha under the Tint option in the material to make the water transparent, but the reflections will also become transparent.

  11. I can’t get it to work. :^(
    Well, in scene it works, but in game it does not.
    I compare with the test project but still I don’t find out what I’m doing wrong

Leave a Reply to kimizahiCancel reply