Here’s something I did on Weird West that I thought was cool: fire propagation across grass and foliage. Lots of stuff is flammable in the game, and there’s a general elemental signal system that handles most of those interactions, but foliage needed some special handling.
Maps full of foliage had already been made using instanced foliage meshes, which are super performant but aren’t Actors, so they don’t have Components, which everything else uses to catch fire/get wet/electrified etc, and I didn’t want LDs to have to do anything for this to work.
One approach is to swap each foliage instance out for an actor, either in-editor or at runtime when some firey event happens, but that’s potentially pretty bad perf-wise (spawning very many actors), and doesn’t account for the arbitrary density of these instances – that is, you might have a field where every blade of grass is an instance, or maybe it’s in big clumps, or it’s multiple foliage types so it’s both, and you just want a nice even fire spread across this field. As you may now have guessed, here I cluster the instances.
When stuff burns, it calls this function, which checks for foliage in that location/radius and looks those meshes up in a data table. The table also has stuff like “what fx to play if we cut this plant with a machete” + actors to spawn on break (eg corn plant spawns corn if cut).
If the foliage we found is burnable/chunkable, we spawn a single actor to represent that whole radius of foliage, add meshes to the actor at the same transforms as the original instances, and delete the foliage instances, swapping a few meters of foliage instances for 1 actor. That actor can now use our Signal system for burning/getting wet/whatever, just like characters do, and starts doing this process again for any foliage around it. Keeping this performant is just a balance of how fast your fire spreads vs runs out of fuel.
Our fire rules are pretty much the same for most types of object, but foliage wants to act a little more impressive even if it means being a touch unpredictable, so we have a few specific settings, eg wind contribution. I like to keep these in a data asset so designers can get at ’em without touching code (including BP).
For performance, none of these fires actually creates any light directly. When there’s a foliage fire going on, we create one non-shadow-casting fire light that moves and changes size to cover the entire burning area. Ditto sound. Same idea as my old fire system.
We also use all the Cool Kid Shader Perf Tricks, like having the burning foliage turn to embers and threshold out using Time in the shader rather than wasting any CPU on it, which ends up meaning we can have very large dangerous exciting fires with generally quite a low perf hit. I’m pretty happy with the result, and it ends up a system where you get these kinds of anecdotes, so who can complain:
For cutting foliage, we use the same function but it’s much simpler: check in front of the player for foliage, look it up in the table, destroy the foliage, spawn the tabled FX/items etc for that foliage, or replace with an actor. This game doesn’t do it, but if we wanted to be able to cut down trees with an axe using this system we could have it going in like 20 minutes. Also, this was all done in Blueprint. Blueprint is the best.
Leave a Reply