The Liquid Shader (3D) animates the liquid by displacing the vertices of its mesh, so it needs a mesh that is dense and evenly tessellated. It also needs to know where the liquid meets the shore, in order to fade out the emission there.
LiquidSurface.cs provides both. It turns the first spline of the Spline Container on the same GameObject into a liquid surface mesh: it fills the spline with an evenly tessellated grid of triangles, generates the UVs for it, keeps optional colliders in sync, and writes an edge mask into the red channel of the vertex colors, which the shader uses to fade the emission out towards the outline of the surface.
The surface faces the local +Y axis, so draw the spline in the local XZ plane, as seen from above. How the mesh is built depends on whether the spline is closed or open:
- A closed spline is filled. The interior blends smoothly between the heights of the outline, so a level outline produces a flat surface, and an outline that rises on one side produces a tilted one.
- An open spline becomes a strip of Open Spline Width, centered on the spline. The strip follows the height of the spline along its length and stays level across its width – ideal for a river running downhill.
Add the component via Add Component > Project GAMEDEV > Essential 3D Shaders > Liquid Surface. It exposes the following settings:
Mesh Detail
The density of the generated mesh (1 – 128), i.e., the number of vertex columns and rows per local unit. The cells of the mesh are kept square, so the waves and the ripples keep their shape whichever direction they travel in. This is the single most important setting of the component: higher values produce smoother, more detailed vertex displacement, at the cost of a heavier mesh. Small pools can afford the maximum, while large lakes and seas need far lower values – see the warning below.
Open Spline Width
The total width of the generated strip when the spline is open rather than closed. The spline stays centered inside the strip. This setting is ignored for closed splines, which are simply filled.
UV Mode
How the textures are projected onto the surface. The projection is always planar, from above. Three modes are available:- Local Tiling (default) – the textures repeat every Tile Size units in the local space of the GameObject, so they move, rotate, and scale together with it.
- World Tiling – the textures repeat every Tile Size units in world space, so that neighbouring liquid surfaces line up seamlessly. The mesh is rebuilt whenever the GameObject moves, rotates, or scales.
- Stretch To Bounds – a single copy of the textures is stretched across the bounds of the surface, repeated Stretch Tiling times.
Tile Size
Stretch Tiling
Edge Mask Width
The horizontal distance from the outline of the surface over which the edge mask fades out. The mask is stored in the red channel of the vertex colors and is used by the shader to darken the emission near the outline – a wide value produces a broad, cooled rim, while a very small value effectively disables the rim.
Edge Mask Softness
The softness of that falloff (0 – 1). At 0 the mask ends abruptly, giving a hard border; at 1 it fades smoothly across the full edge mask width.
Bounds Padding
Update Colliders
All settings are also available in code. Each one is exposed as a property of the same name, with the exception of UV Mode,
which is exposed as UVProjection. Changes are picked up on the next Update; call Rebuild()
to apply them immediately. The component lives in the ProjectGamedev.Shaders.Essential3DShaders.LiquidShader3D namespace.
liquidSurface being the Liquid Surface component of your liquid, change the settings like so:liquidSurface.MeshDetail = 32;
liquidSurface.UVProjection = LiquidSurface.UVMode.WorldTiling;
liquidSurface.EdgeMaskWidth = 1f;
liquidSurface.UpdateColliders = false;
liquidSurface.Rebuild();
public int MeshDetail
public float OpenSplineWidth
public LiquidSurface.UVMode UVProjection
public float TileSize
public float StretchTiling
public float EdgeMaskWidth
public float EdgeMaskSoftness
public float BoundsPadding
public bool UpdateColliders
public void Rebuild()
Update.