Devlog #02, and this one got deep — literally. Eldoria has lakes to wade into, rivers to follow, and, eventually, oceans to be quietly terrified of. So water was never going to be a background detail. The only real question was how to build it — and somewhere along the way we decided to build the whole thing ourselves.

Work in progress. Everything here — the materials, the Blueprints, the effects — is a test or a prototype, not the final game. Nothing's locked: not the look, not the architecture, not the feature list. But it's real, hands-on development — genuinely how the water in Islands of the Blessed is getting built, one experiment at a time.

Why not just use the Water Plugin?

Unreal ships a Water Plugin, and it's genuinely impressive. It's also big, opinionated, and a little tangled to bend toward a stylised look — and it quietly ties a chunk of your project to it. We wanted the opposite: a small framework we fully understand, that gives us total control over the rendering, drops cleanly into any UE5 project, and behaves itself in an open world with several players running around.

So we started over. The goal was a water system that's:

100% Blueprint — readable, hackable, no black box.

Stylised & ours — a custom master material, not a preset.

Plugin-free — nothing to install, nothing to lock us in.

Open-world & co-op friendly — built with both in mind from day one.

Reusable — interfaces + components, so it travels to any project.

Easy to grow — lakes today, rivers now, oceans and marshes later.

The shape of it

Under the pretty surface, the framework is really just four pieces that talk to each other:

  1. A custom master material — one stylised water surface that serves lakes, rivers and (later) oceans. Total control over how it reads, zero dependency on the plugin.

  2. Water Bodies — the actual bits of water in the level: BP_Lake and BP_River, each knowing its own shape and where its surface sits.

  3. A shared interfaceBPI_WaterBody, so anything can ask the water questions without caring whether it's a lake or a river.

  4. An underwater componentBPC_Underwater, a reusable part you bolt onto any character to handle being submerged.

Top-down view of the water test level — a lake feeding a river, with placeholder geometry
The test pool — a lake feeding a river, where all of this gets poked at.

Lakes and rivers

Two kinds of water, two very different ways to build them.

BP_Lake

A lake is a circular body built from a grid of instanced tiles (ISM/HISM), so even a big stretch of water stays cheap to render. It's not just a flat plane, either — there's the surface you see and an underwater volume beneath it, so you can actually go under and the game knows you're in there.

A stylised lake surface with a sphere and a cube half-submerged, test geometry around the edge
The lake surface, with a couple of test objects breaking through.

BP_River

A river is the opposite — you draw it. Lay down a spline through the landscape and it does the rest: it auto-generates the spline meshes for the surface, and builds a collision volume per segment so the water lines up with the shape you drew. Bend the spline, the river follows.

A spline-based river flowing from a platform, with its per-segment collision volume shown as a wireframe box
A spline river — the wireframe box is one of the auto-generated collision volumes.

Talking to water without a single Cast

Here's the part we're quietly pleased with. A lake and a river are built completely differently — but the rest of the game shouldn't have to know or care. So they both answer the same little interface:

interface BPI_WaterBody
  GetWaterSurfaceZ(WorldLocation)   // how high is the surface, right here?
  IsPointInsideWater(WorldLocation) // am I actually in the water?

Two questions, asked the same way no matter what kind of water you're standing in. No Cast To BP_Lake, no Cast To BP_River, no spaghetti — and when we add oceans or marshes later, they just answer the same two questions and everything else keeps working.

Going under

Being near water is easy. Knowing the exact moment a player's head dips below the surface — and reacting smoothly — is the fiddly bit. That's the whole job of BPC_Underwater, a component you can drop onto any character.

When you swim into a water body, its box collision quietly hands itself over:

// on the water body's box collision
BeginOverlap  →  RegisterWaterBody(self)

Now the component knows which water it's in. Every tick, it just asks the interface those two questions and does a little maths:

// every tick, while we have a water body
inside  = CurrentWaterBody.IsPointInsideWater(PlayerLocation)
surface = CurrentWaterBody.GetWaterSurfaceZ(PlayerLocation)

bIsUnderwater = inside AND (PlayerZ < surface)
Underwater view looking up at the surface from below, with blue volumetric water and the pool floor
Below the line — the underwater post-process kicking in.

The second bIsUnderwater flips, it drives an underwater post-process — and it eases in and out rather than snapping, so breaking the surface feels like a transition instead of a light switch. Best part: because it all goes through the interface, the exact same component works in a lake or a river without changing a thing.

What's next

Right now it works — next we want it to feel like somewhere you'd hold your breath. The list of things we're chasing under the surface:

Caustics — those rippling light patterns, projected triplanar onto the geometry.

Refraction — the surface bending what's behind it.

Total internal reflection — that mirror-ceiling look when you glance up from deep down.

Volumetric fog & god rays — local, underwater, shafts of light coming through.

Colour & absorption — water that drains colour and clarity the deeper you go.

River currents — flow direction read straight off the spline, with proper underwater volumes.

And further out: waterfalls where rivers fall, and stretching the same framework to oceans, marshes and a few stranger waters Eldoria has in mind.

It all lives in Blueprint on purpose — readable, reusable, quick to throw new ideas at. The parts that need to scream get validated and optimised down the line, same as everything else we build, but the architecture stays friendly. That's the whole point of doing it ourselves.

That's a wrap on #02. See you in the next one — try not to drown.

More devlogs

What would you want under the surface?

Drop by the Discord and tell us — sunken ruins, things that shouldn't be down there, a perfectly calm lake to just float in. We read everything, and the good ideas have a way of sneaking into the game.