DuskWorks

DuskEngine Devlog 2 - Entirely too much navmesh I've had enough edition

The previous month no navmeshing happened even though it should have, this month so much happened I've had enough. There's more than just navigation to talk about however, so let's get to it.

Navmesh & Pathfinding

I started out using Recast for this, and for a while things went approximately well, especially because of Ravbug's sample which provided a nice starting point.

In order to have obstacle support you need to use a tiled navmesh rather than a basic one, and after days of trying to figure out which of the bazillion parameters Recast expected weren't right (the navmesh was always either broken or wrong in some subtle way), or if it was my geometry causing issues, I decided I have better things to do with my time, so I put together a quick grid-based solution instead.

It needs a lot more work, but it's a starting point. Characters are able to pathfind anywhere in the scene and I can prototype gameplay.

NavPlane entities define the areas that are meant to be walkable:

Image

In this image the NavPlane normally covers the entire floor, but I made it smaller 'cause it's easier to see.

Entities with the NavCarver component dig holes into the NavPlanes:

Image

The NavPlanes themselves are not grids, there is only one global (infinite) grid, and it's the parts of it that are covered by navplanes that are considered for pathfinding. Indeed, this means the objects in the scene need to be more or less aligned to this infinite grid, to make efficient use of the space when pathfinding.

At the end a NavGrid object gets built - it's the thing that gets queried for paths and updated for obstacles. It is built by taking all the information from NavPlanes and putting it together.

Dynamic obstacles such as doors are also working:

Image

Sphere is the only obstacle shape supported right now, for the door a box would be better but that will be implemented sometime later.

I'm not sure if in the future I'll still be using grids. I know for sure I'll be forced to add an extra dimension once buildings with multiple floors are required. This will likely happen next year. In that case NavPlanes would become NavVolumes or NavCubes, and rather than a 2D grid I'll likely deal with 3D voxel space. Agent height would also suddenly matter.

Dynamic obstacles are important (doors, or placing boxes or other obstacles in front of doors, stuff like that), and grids and their kin make supporting them extremely simple. Navmeshes would require rebuilding the parts that overlap with the obstacles, which is much more expensive than updating some flags on a grid.

I'm using a basic A* implementation to pathfind in the grid at the moment.

OK, enough about pathfinding. The rest of the cool new things follow:

Extra vegetation system features

DuskEngine features a vegetation system with which you can place vegetation patches in a scene. A vegetation patch is essentially a rectangle in which vegetation (meshes that sway in the "wind" and get pushed away by volumes such as characters) get spawned. You can use a brush to hide or show some of the spawned plants.

Like this:

Up until now, grass and flowers were the only use case, so the vegetation system didn't need much in the way of shadows (it kinda made the grass look very crowded actually).

I modeled some cattail meshes and also made the system support shadowcasting vegetation. Grass still doesn't cast any shadows, but cattail needs to because it's large and looks weird without shadows.

Image

Asset importing/cooking/baking made nicer

The following is only relevant when running the engine editor.

When something wants to load an asset, the asset manager first checks if there's a pre-baked version of the asset. If there isn't, or if it's outdated (because the source file changed since it was baked), it triggers a re-bake.

Because this is done on-demand, it introduces stuttering as new stuff comes into view, or presents a black screen for a pretty long time when a scene is first loaded, assuming for example that the entire asset cache has been cleared.

I made the editor first check that everything's properly pre-baked before even trying to give the engine instance something to do:

Image

I love this dialog, it looks so legit.

Showing this dialog wasn't the only reason I did it though. A big feature that the asset manager is missing is async asset loading.

Having this initial reimport step, before anything interesting even starts to happen, gives me a place where I can experiment with async loading without risk of breaking any of the existing functionality.

After I figure out what works and what doesn't, I can look into updating parts of the engine to benefit from async loading.

This will happen sometime in the future, as it's not necessarily high priority right now.

Making Lua gameplay scripting a bit nicer

Errors raised in gameplay Lua scripts used to crash the engine entirely, and I used to restart the whole thing after changing a script, in order to get it reloaded (or rebaked 😝).

Errors are now logged appropriately and the engine stays running. There's also a file watcher that evicts scripts that changed from the cache, so when they're next requested, they're in their latest version.

LOD vertex deduplication

LODs have been supported in the engine for a while now, but each LOD level was treated as an entirely separate mesh. This worked fine, but in most cases there is a very large overlap between the vertices in a lower LOD and those in the higher LODs, which means the same vertices get put into VRAM multiple times, which is wasteful.

So now as part of the mesh bake process, the engine will go through the lower LODs of that particular mesh and merge them with the original, while avoiding duplicated vertices. Essentially, creating one big buffer with verts, and a big buffer containing the concatenated indices for the original and lower LOD meshes.

That's it

That's about it for this month's devlog. I'm continuing work on pathfinding and steering behaviors for NPCs, among other things which I'll show on the next entry and on my bsky. See you next month!


For any questions or feedback, find me on Bluesky
Firefly in the Dusk🌙