Search Unity

The Legend of Zelda: Wind waker styled water

Discussion in 'Shaders' started by Kazen, Feb 17, 2015.

  1. Kazen

    Kazen

    Joined:
    Feb 17, 2015
    Posts:
    68
    Hello, new to the forums here.
    I would like to know, if it's possible to create a water similar to the one in The Legend of Zelda:Wind Waker, working in unity free and on mobile. I think it's a shader question, but maybe it could be moved to the right place if I'm wrong.

    If it is possible, how would it work? I've researched it a bit and according to http://www.polycount.com/forum/showthread.php?t=98578 (Image heavy) they're using an alpha-mask for the white edges, which they move at a certain speed along the edge. It would be great if this was dynamic, so if there's an obstacle or something placed inside the plane, that one would produce those white edges too. I also think that they use some kind of flowmap to make the water travel around obstacles (when it's a river), or maybe they're just UV-scrolling in some awesome way?

    Any help is appreciated. I've tried searching for adding textures on edges but didn't come up with anything.



    And here's someone that attempted the same (and maybe succeeded, but I don't know)



    Also, the polycount-forum also contains a nice gif of a waterfall that must be doing something similiar (Image heavy) http://www.polycount.com/forum/showthread.php?t=98578

    Edit: Also, I haven't really worked with shaders before.
     
    Last edited: Feb 17, 2015
    VortexStudios likes this.
  2. Foestar

    Foestar

    Joined:
    Aug 12, 2013
    Posts:
    338
    Here you go mate. This guy not only did this, but put it on his site for free.
    His YOUTUBE video. Just follow the link in his description to find and dl it. Then just drag and drop it in. Pretty easy enough.
    Or you can just click HERE to view his portfolio. He's done some pretty awesome stuff.
     
    Kazen likes this.
  3. Kazen

    Kazen

    Joined:
    Feb 17, 2015
    Posts:
    68
    Hey, thanks so much for the link. The .zip-file doesn't seem to work though, did it work for you? "Couldn't open as a zip-file". If it works for you, could you maybe repackage it or tell me what I'm doing wrong? Also, it doesn't look like there's some sort of texture for edges, which I would also like to have/do, so I would need some sort of information on how to place textures along edges (and scroll/"animate" the texture along the edge). It's definitely a good start if I could download it correctly :)
     
  4. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,786
    Its a simple texture and vertex manipulation shader, the shores can be done with either hand painted or mathematically calculated alpha maps. The latter is tricky but can be done with unity free as well, but the proper way of doing it is via depthmap support which you dont have access with unity free.

    EDIT: Search the unity blog, i think unity people shared some code on how to effectively do the depth intersection somewhere.
     
    Kazen likes this.
  5. varfare

    varfare

    Joined:
    Feb 12, 2013
    Posts:
    227
    It is possible in Unity Free but you probably won't be able to do water intersection (the part where water touches dry land). The best (and probably the only) way of doing this is to perform depth check, the same way particles with Soft Particles Factor do. You are basically checking if distance from water pixel to the nearest depth pixel is smaller than the factor. If it is then you can use this information to show additional texture. The code snippet:

    Vertex program part
    Code (CSharp):
    1. o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
    2. o.projPos = ComputeScreenPos (o.vertex);
    3. COMPUTE_EYEDEPTH(o.projPos.z);
    Fragment program part
    Code (CSharp):
    1. float sceneZ = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture,UNITY_PROJ_COORD(i.projPos)));
    2. float partZ = i.projPos.z;
    3. float fade = saturate (_DepthFactor * (sceneZ-partZ));
    4. myWaterIntersectionTexture.a *= abs(1 - fade);
    But getting depth map is probably unity-pro only feature so this part can/have to be skipped.

    As it goes for water texture with this "distorted look" it is totally doable. You will need
    * tiled water texture like this http://answers.unity3d.com/storage/temp/8104-imagescak1mb7g.jpg
    * tiled noise texture https://www.filterforge.com/filters/231.jpg
    * a shader which does the following
    1. Has water texture and noise texture input
    2. Noise texture UV is panning over time
    3. Noise texture color values are multiplied or added to the water texture UV
    4. The resoult will be a distorted water texture with this wobbly look
     
    Kazen likes this.
  6. Kazen

    Kazen

    Joined:
    Feb 17, 2015
    Posts:
    68
    Alright, thank you, I'll see what I can do with this information, and thanks for sharing the info when using Unity Pro too, I might purchase that if I feel that I can't get the water to look good without it.

    Thanks again, really appreciate it.
     
  7. Foestar

    Foestar

    Joined:
    Aug 12, 2013
    Posts:
    338
    To get the file of Kaisirak's to work in unity you simply download it, extract the files to a folder. Then go into unity to
    "Assets/Import Package/Custom Package" and find the "windwalkertest.unitypackage".

    Now create a flat plane by going to "Game Object/3D Object/Plane".
    Under the "Project" tab where you can see a list of all your folders and project items there is a search bar in the top right. Type "waterZelda" and you will see both the texture and material. Drag and drop the Material onto your flat plane.
    At this point you just need to adjust the sliders while in game to get the desired look you want for your water.
     
  8. Lars-Kristian

    Lars-Kristian

    Joined:
    Jun 26, 2013
    Posts:
    64
    This seems like an interesting effect to recreate.

    The way I think it can be done.
    1. Generate static meshes at the water edge.
    2. Use a transparent cutout shader.
    3. Animate UV scale and offset from a script.

    For added effect you could use textures with a blurred alpha channel and animate the alpha cutoff value.

    The first minutes of this video is great for reference.


    I made a river prototype and this is my progress so far.
    Zelda Water A.gif
     
    Last edited: Feb 21, 2015
  9. Lars-Kristian

    Lars-Kristian

    Joined:
    Jun 26, 2013
    Posts:
    64
    This is the result I got from using the method I posted above.
    The colors and textures are not quite the same as in game but the effect is there I guess.

    River:
    Zelda River.gif

    Pond:
    Zelda Pond.gif
     
    CJ_Various likes this.
  10. kebrus

    kebrus

    Joined:
    Oct 10, 2011
    Posts:
    414
    thats pretty damn close, how are you generating the shore mesh?
     
  11. Lars-Kristian

    Lars-Kristian

    Joined:
    Jun 26, 2013
    Posts:
    64
    It is done by using an array of Vector3. Then generate some guideline vectors and build polygons between every array element. The uv coordinates are adjusted accordingly. I can change width, make it pointing inwards or outwards, and switch uv direction.

    WireFrame.png

    My plan was to later on do some mesh / plane intersection detection. Then generate an array of Vector3 and send it to the mesh builder.
     
  12. kebrus

    kebrus

    Joined:
    Oct 10, 2011
    Posts:
    414
    Thats pretty clever, it should be easy to do the plane intersection.

    good job
     
  13. kyleyoungblom

    kyleyoungblom

    Joined:
    May 1, 2014
    Posts:
    29
    That looks really great, @Lars-Kristian. I'd be really interested in reading a bit more about how you accomplished it if you ever feel like writing up a quick summary.
     
  14. Kazen

    Kazen

    Joined:
    Feb 17, 2015
    Posts:
    68
    Oh I thought I wrote this on answers, so I totally missed these posts. Lars-Kristian, those are very cool effects and sounds (and looks) like a good way to try and recreate the effect. Maybe I could try and replicate you way of doing it. A plane/mesh-intersection sounds like a smart way to generate the vectors too! Really nice.
     
  15. picobots

    picobots

    Joined:
    Jun 7, 2012
    Posts:
    7
    Amazing work @Lars-Kristian, that's really cool. Does anyone have any idea how a similar shoreline effect can be created on a water plane that has changing/dynamic vertices (on the y-axis, to create a wave effect)?

    I'm thinking specifically of this type of water in Monument Valley (starting at 0:14), which has a similar flat look to Wind Waker. That shoreline effect is amazing! The waves and spray are simple enough—the waves can be achieved with code like this, and the spray is just a particle system. But how did they achieve that morphing/wobbling white band that dynamically hugs the shoreline (and moves and changes as the water level lowers and more land becomes visible)? Any ideas?
     
    kyleyoungblom likes this.
  16. kyleyoungblom

    kyleyoungblom

    Joined:
    May 1, 2014
    Posts:
    29
    I've been looking for a way to accomplish the same thing, with no luck. The closest solutions I've found rely on using depth information to render light-colored dropoff beneath the water, rather than on the surface. If anyone has any suggestions I'd love to hear them as well!
     
    Last edited: Aug 13, 2015
  17. INedelcu

    INedelcu

    Unity Technologies

    Joined:
    Jul 14, 2015
    Posts:
    86
  18. kyleyoungblom

    kyleyoungblom

    Joined:
    May 1, 2014
    Posts:
    29
    That solution looks great for more photorealistic water, but I think what @theremin and I are looking for is a solution that behaves more like the image on the right, rather than the depth-based one on the left:



    Where the effect is applied along the surface of the water, creating a uniform "stroke" along the intersecting points. Lars-Kristian seems to have accomplished exactly that, but I haven't been able to find any examples of how to achieve it. Sorry for my super non-technical explanation :)
     
  19. INedelcu

    INedelcu

    Unity Technologies

    Joined:
    Jul 14, 2015
    Posts:
    86
    The solution I used there is depth-based and because of this will create foam around any geometry intersecting the water dynamically but yes you'll have that issue. You should access the height map of the terrain during water shading to achieve the effect from the right image but I don't know if it's possible right now. There's no built-in variable for that at least.
     
  20. serious

    serious

    Joined:
    Apr 26, 2013
    Posts:
    5

    since this post was from August I'm wondering if you ever did find a solution to this. the uniform "stroke" running along the shore line is an incredible look.
     
  21. varfare

    varfare

    Joined:
    Feb 12, 2013
    Posts:
    227
    You can posterize the depth value. For example:
    if (depthValue > threshold) depthValue = 1;

    Or use frac, modulo, multiply depth value by 1000000 and clamp it in 0-1 range.
     
  22. kyleyoungblom

    kyleyoungblom

    Joined:
    May 1, 2014
    Posts:
    29
    No. I decided I was overthinking it given the scale of my project, and just ended up building edging into my shore geometry.
     
  23. Zenchuck

    Zenchuck

    Joined:
    Jun 2, 2010
    Posts:
    283
    Last edited: Oct 27, 2015
    serious likes this.
  24. Luiz_Thiago

    Luiz_Thiago

    Joined:
    Feb 27, 2013
    Posts:
    32
    Hey!!! Can u share some code??
     
  25. Lars-Kristian

    Lars-Kristian

    Joined:
    Jun 26, 2013
    Posts:
    64
    Hi, everyone. Sorry for not being active here, I guess? Life happend. xD
    I made a quick guide/summary on the water effect if someone is interested. I am not good at making tutorials but I tried. Hope you like it. :D
    Here is the Link (WARNING: .gif-heavy): https://docs.google.com/document/d/1RzJT-xNhWWyeCfjUjhdx2vVU2guMg0MhSB-h-J-FU9k


    Sorry, but no.
    Check out: http://catlikecoding.com/unity/tutorials/
    They got some good tutorials on generating mesh at runtime.
     
  26. JeffersonTD

    JeffersonTD

    Joined:
    Feb 5, 2013
    Posts:
    265
    A related question: how big is the performance cost of using DepthTextureMode.Depth?
     
  27. varfare

    varfare

    Joined:
    Feb 12, 2013
    Posts:
    227
    If you are using deferred path - it is almost free. Depth buffer is generated each frame anyway. This is the way deferred rendering works.

    If you are using forward rendering path - the cost depends on scene complexity (vertex amount). This is because camera needs to re-render whole scene with special shader that computes depth buffer.
     
    JeffersonTD likes this.
  28. JeffersonTD

    JeffersonTD

    Joined:
    Feb 5, 2013
    Posts:
    265
    So is it in the right ballpark to say that it is equal to having an extra pass for every single shader rendered by that camera? That would sound like quite a significant addition to rendering cost.

    I'm just thinking about this, because I might only use this for one effect. Well, at least I could do some optimization by switching that off whenever there is no possibility of needing it, and if using it is costly, maybe also switch it off when the effect would be only seen in a far away distance (which would then also mean having to fade the effect in and out in the shader based on distance).
     
  29. varfare

    varfare

    Joined:
    Feb 12, 2013
    Posts:
    227
    Yea. If you are using Forward Rendering you are basically creating new render pass on your demand. But it's not created per-shader call. It is created once every frame by your current camera. So if you are using it you probably should use it elsewhere to make it profitable.
    http://docs.unity3d.com/Manual/RenderingPaths.html
     
    JeffersonTD likes this.
  30. JeffersonTD

    JeffersonTD

    Joined:
    Feb 5, 2013
    Posts:
    265
    Simply posterizing the left doesn't result in the one on the right, as the one on the right goes along the surface of the water, not along the edge of the terrain. I'm actually trying to create a gradient like the one on the left, but along the surface of the water like on the right, and regardless of what is below the surface of the water.

    So simply using the depth buffer doesn't actually seem to be a suitable option for that. I did try making a nasty hack involving a for loop within the shader to achieve that, and although it sort of works from some angles, it's angle dependent and doesn't work at all if the camera doesn't see the intersecting point. And even if it did work properly, having a for loop with many iterations isn't probably performancewise a very good idea to do in a shader even if this shader was only used for 1-3 objects(?).

    I've thought that one option would be to programmatically create a mesh shaped particle system to create a similar, effect, but that would probably be pretty problematic. Luckily this isn't an effect I absolutely need, but it would be a cool effect.

    By the way. One weird thing is that the depth buffering seems to work for what it does regardless of the camera setting. When trying out the depth buffer I did right away set the camera to have depthTextureMode = DepthTextureMode.Depth;, but even after removing that code (and debug logging to make sure the depthtexturemode in fact is None), the depth buffering with the effect similar to the one in the image on the left, still worked. And the camera does use Forward rendering, so it shouldn't be automatic. Can it be that Unity 5.3. automatically puts the depth buffer on, if a shader tries to access the depth texture?
     
  31. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    11,156
    Realtime directional shadows use the depth buffer, so it gets enabled on cameras even if it's not set if one exists.

    To do what you want you need a depth map, not the screen depth but the terrain depth. You can do this either by using an extra orthographic camera to render it out in real time or export the heightmap and import it as a texture. If you use that by itself and a "height" offset value you can get a nice gradient that matches the terrain below it. If you just want it to be a constant width edge you'll need to do additional work in the shader to do edge detection or use an external graphics tool to do the same.
     
    JeffersonTD likes this.
  32. JeffersonTD

    JeffersonTD

    Joined:
    Feb 5, 2013
    Posts:
    265
    Ah, in my previous post I was about to write that what I'm after here isn't actually water, but then I thought that that information would be irrelevant. Well, so it happens that it actually wasn't irrelevant. :) In my case it isn't just one terrain object that might collide with the surface that would have the effect, but pretty much any mesh of any shape. So the problem with the ortographic camera solution is that looking from further away there might be objects in front of this effect surface that shouldn't cause any changes to the surface. And if I go too close with the orthographic camera, it won't see the objects that actually collide with the surface.

    Thanks for the ideas nevertheless - they help in creating a better problem-solving mind, when it comes to shaders.
     
unityunity