Unlit water shader with foam

I’d like to share a water shader that might be useful when rendering scenes with NPR-techniques. The great thing about this code is the ability to detect obstacles in the water and then render a nice foam around them. I’ve seen this effect in Unity some time ago and I though it would be useful to have this in three.js.

The shader should work with perspective and orthographic cameras, it supports output encoding, inline tonemapping and fog and is much faster than the (more realistic) water shaders of the official repo.

Live demo: https://gojcn.csb.app/

Editable code at Codesandbox.

23 Likes

Looks very nice, the illusion is broken when you move the camera around, you really need a depth buffer perpendicular to water plane to figure out where the edges are, I have a much less good looking shader in Might is Right that simulates the shore-line (foam, whatever) - I use the inverse of terrain height-map to figure out where the shore is.

I get that that’s extra processing in general, so maybe not suitable for everyone.

Looks very lovely :slight_smile:

1 Like

Really like it! Feel there are many more uses for it other than just water, after tweaking your settings a bit I could see it being useful for other effects like heat waves coming off of an object.

Very cool stuff, really enjoy the cartoon look too!

1 Like

This is really nice, but I don’t think your initial settings do it justice. This looks much more like water to me.

2 Likes

Of course it’s a matter of taste. I’ve just implemented the style of the Untiy showcase where the foam is white and only visible at the intersection points:

http://halisavakis.com/my-take-on-shaders-unlit-waterfall-part-1/
http://halisavakis.com/my-take-on-shaders-unlit-waterfall-part-2/

Also a nice reference for water in cel shading:

5 Likes

Updated the water effect with the waterfall from the article:

Live demo: https://x4fl4.csb.app/

Editable code at Codesandbox .

The particle effect on the waterfall’s bottom and a bloom pass are still missing.

6 Likes

Next level achieved! The waterfall has now a nice particle effect based on THREE.InstancedMesh and MeshBasicMaterial enhanced with a simple dissolve shader.

Live demo: https://7rkse.csb.app/

Editable code at Codesandbox.

Um, a generic particle system based on THREE.InstancedMesh could be usable for much more interesting effects :thinking:.

8 Likes

Looks sweet! :grin:
Will definitely try it out with a bloom pass when I have some time.

Arent sprite billboards way more popular as particles? I feel like most p systems make great uses of alpha textures.
It obviously depends on the case, but what do you think? What are the adventages of using THREE.InstancedMesh for particles? Or rather which effects would be better suited for it, instead of billboards?

A typical particle system usually renders points similar to the following example:

https://threejs.org/examples/webgl_points_billboards

The waterfall’s particle system uses spheres (THREE.SphereBufferGeometry) for its foam. So a geometry rendered with gl.TRIANGLES instead of gl.POINTS. You can’t achieve the same volumetric effect with a 2D primitive. Check out the volumetric particles here:

It would be obviously bad to render each particle with a single draw call. That’s not an issue when rendering points but when rendering meshes. Using instanced rendering solves this issue.

2 Likes

I guess the 3D shape is the obvious point (pun unintended :cowboy_hat_face:). I was just trying to come up with different uses for gl.TRIANGLES type particles and Im failing miserably :thinking:

My job has twitter blocked :sweat_smile: but I’ll make sure to check it out later. I’ll try to look up some more volumetric effects as well.
Thanks for the resources! :+1:

1 Like

Wow this is progressing! Looks awesome!

1 Like

@Mugen87 for webgl2 the example could use THREE.DepthTexture() too right?
renderer.extensions.get(“WEBGL_depth_texture”) returns false on webgl2

Yes, you can always use depth textures with WebGL 2. The extension test will return false since WEBGL_depth_texture is only available with WebGL 1.

1 Like

thx this helps a lot,
still have some problems with the DepthMap if objects are moving

the idea was only use the Terrain object3d for the target Render pass like
const terrain = scene.getObjectByName(“Terrain”)
renderer.setRenderTarget( this.target );
renderer.render( terrain, camera );
renderer.setRenderTarget( null );

this works, but slow because i cannot set the overrideMaterial ?

any suggestions are welcome

looks like found the solution

create a new Scene() and add the object3D cloned
terrain = new THREE.Scene().add(scene.getObjectByName(“Terrain”).clone())

@Mugen87 Beautiful stuff as usual Mugen87

I’ve been fiddling with the sandbox a while, but can’t seem to understand how the water can be scaled up to. say - 100, 100. It just stretches the shader

Also, is this under CC0? Can I use it for a game?

TBH, I don’t have the time to look into this right now.

The code has no license so you can use it to whatever you like with no restrictions.

2 Likes

Nice work! Thank you so much for sharing your project!

I’ve just made some changes, and it is now looking like this:

ezgif.com-video-to-gif

For those who prefer this look like me, feel free to get the code from:

GitHub Repository: Unlit Water Shader with Foam

What does it look like from a top-down perspective?

I assume this is using the depth-buffer to determine where foam should be placed, in which case it will only show on the parts that the camera actually faces (underwater), meaning 2 directions never have foam. :thinking:

I’m asking because I’ve been struggling with this a couple of weeks ago :sweat_smile:

@Mugen87 I referred to the method of obtaining the depth map in your demo,since I need to get the depth map of the entire scene ,so I don’t need to hide anything,But this leads to a problem. When I don’t use overrideMaterial only use THREE.DepthTexture, I get a warning(Feedback loop formed between Framebuffer and active Texture) that interrupts rendering. Can you explain to me why this warning appears?