Actor foliage performance

Hi there!

I made a base tree blueprint that receives damage and when chopped down to 0 HP it activates physics simulation and gets a force applied so it smoothly falls to the ground. After that, you can chop it down again to destroy it and spawn a trunk actor instead.

I now tried to use it as a foliage actor on my landscape and when I reach an actor count of > 1500 trees, the performance gets really bad (dropping below 20 fps). I actually expected something like that to happen, but now that it did, I don’t quite know how to solve it.

Can this be considerably improved using LOD? It might do so for mesh rendering itself, but I think the real problem is the actor count…

If I were to use something like described in this post, where I’d basically use standard foliage and just remove foliage instances and place my actors instead, where / how would I best handle the chopping down of trees (taking multiple hits, persisting the number of hits, preferably still using damage)?

Actors would’ve been great in theory, I wanted to spawn trees next to other trees sometimes and maybe scale them to make a growing effect or even exchange the meshes… But such a high count of foliage actors seems to be too big of a performance hit.

Thanks in advance!

Hi, I spawned Actors when needed and replaced them by Instanced Static Meshes when not needed anymore. I used a “procedural foliage spawner” to spawn the trees. When a tree gets hit by bullet it gets replaced by an actor (I used a dictionary from static mesh → actor class to obtain the actor class).

Then I spawn the actor and remove the instance.

Below is my “Base Tree” class from which all tree actors inherit (but I think you’ve already got something like that).

When the health is at 0 I the tree falls down and after a delay I replace the actor by an instanced static mesh again. Also when a delay time is over the actor gets replaced by an instanced static mesh (So the actor would get removed eventually for performance). Here’s the function to replace the actor (“Add Instance World Space” is the important part)
289815-
If you want to add trees you could get the “Instanced Static Mesh Component” (that’s the “Hit Component” in the first image) from the tree type you want to add and again use “Add Instance World Space”. If you want to scale them there’s a node called “Update Instance Transform” that can be called from the “Instanced Static Mesh Component” where you would input the index of the tree of that you want to change the transform.

Apparently onw image is listed but not uploaded… That’s to replace the Actor with an instanced static mesh again.

Hm, yeah. I could replace it to an actor before and still use the damage based system I got…

This could be a solution, I’ll try once I have time for it. Thanks for your input, I will report back.

I tried deriving from FoliageType_InstancedStaticMesh and FoliageInstancedStaticMeshComponent to try and get some variable on my foliage so I could maybe do this without having to have an extra dictionary from static mesh to the actor to spawn, but it didn’t work. Derived FoliageTypes can’t be used in the foliage painter (which is pretty sad and to me not really understandable, this would be great actually). Deriving from Foliage-MeshComponent would work, but you can’t modify its class defaults from the FoliageType so you’d have to make a child class for each possible actor (which is ugly)…

I would’ve liked to make the mapping in some sort of global dictionary that I could somehow reference instead of defining it in my WeaponBase, but I didn’t find anything suitable. In the end I used a DataTable so I can define the mapping outside of the blueprint.

Let’s see how this’ll work out in the end. Other interesting questions

  1. Foliage you can harvest from like berry bushes, apple trees, maybe even ore deposits. I’d probably need another DataTable (or refactor it so the rows only contain dictionaries and I have one row for destroyable foliage, one row for usable foliage, etc.)

  2. Foliage changing over time, for example young trees having a random timer and getting replaced by grown trees.

  3. Forest growing “naturally”, so the players have a steady source of wood without having to plant seeds themselves. Trees would preferably spawn in the vicinity of other trees.

Is there some kind of foliage blueprint that could be used to handle things like that? Sound like I need some sort of static FoliageManager.

  1. Do you want to make a RPG/FPS or an RTS game? So should it yield the resource only once, or should it be something like a resource deposit where you can collect several times from?

  2. From the “Instanced Static Mesh Component” (ISMC) there’s a node called “Get Instance Transform” and “Update Instance Transform”, there you could change the scale of the tree to simulate a growing effect, or if you want to switch the mesh you could use “Remove Instance” on one ISMC and “Add Instance” on another. So you could set up a timer and iterate over all the instances (and use some randomness how much you scale and whether you scale that specific tree). And also if the tree gets too big, you could remove it → 3) to later respawn.

  3. Easy approach: every time you remove a tree save the transform and use a timer in which you would iterate over all these transforms and use “Add Instance” with that location (and maybe some random rotation). And before spawn you could check if there are other trees close by and only spawn then (so if you cut down a part of the forest, it will respawn from the edge and not in an area whithout any trees). If you want the location to be a little bit more random you could try saving all transforms of all trees on the map at the beginning into an array and if you remove a tree add the index of its transform to another array. Then you would iterate over the index array and spawn the tree with an offset location. Otherwise I think you would have to write your own foliage simulator.

I would put 2) and 3) in one blueprint and there get all the ISMC of your trees at the beginning of the game, then use a timer for the growing and a timer for respawn.

I’m thinking more of a small clan PvE survival game actually.

  1. It should definitely be possible to collect several times from nodes… I am not quite sure how things like an ore deposit should “spawn naturally” so that the player doesn’t run out of it…

  2. I’d like it to be in different positions than before so the forest can actually slowly grow back when cut down. Thinking it a bit further, I don’t know if it wouldn’t be annoying if the player has to keep the forest from eventually growing over the whole map. Maybe I should stick to dropping seeds and letting the player decide where the forest grows.
    Even if the forest should have a very slow natural growth (spawning trees in the vicinity of other trees, but not too many), how would you try and do that?

All in all this leads to an extent of logic that would really point towards some game unique “ManagerBP”.

  1. I found the idea cool and implemented it, and the forest is slowly growing back with above setup :slight_smile: (view images 1,2, final, and sim is what it looks like when you spawn the trees small and let them grow over time and remove old trees), and yes that is one single blueprint.

If you want to spawn trees next to other trees you could do something like getting a random existing tree (from your instance component so “Get Instance Transform”) then use “Get Random Reachable Point In Radius” (I assume you have a navmesh) and then do a sphere collision to see if there are other trees too close. If not spawn a new tree. And you can also count the trees in the sphere and spawn only when there are not too many.

A more efficient way would be to somehow detect the edge of the forest and only check there instead of random. One way I can think of would be

  1. Get a location on your map (random)
  2. Multi Sphere Trace for objects (if one of the hit components is equal to your ISMC then there are trees there)
    2.1) There are no trees in the sphere → make a random direction (for example x=1, y=0), do multi sphere traces along that direction until you hit a tree or are out of the map. If you hit a tree you have found an edge of the forest and can look for spawning new trees there
    2.2) There are trees in the sphere → same as 2.1) only until you have no trees in your sphere trace

You could even find the edges at the beginning of the game and update them asynchron in runtime (search for new edges, or when there are no trees in the edge remove it). But don’t know how much performance that will use (so maybe you could use a mix of random and edges).

  1. I would use actors for all of them, if that chews up too much performance you could use one actor per type. So you would create a new DataTable (Type, Transform, CurrentYield) and have an array of that DataTable inside your actor.
  1. I would use actors for all of them, if that chews up too much performance you could use one actor per type. So you would create a new DataTable (Type, Transform, CurrentYield) and have an array of that DataTable inside your actor. And spawn ore pickups at rivers maybe, and else you could spawn them randomly at predefined locations at mountains/caves.

Nearly forgot that.

I really like what you did with that! :open_mouth:

The forest edge detection would be a thing, but I don’t think it’d be necessary, after all, you’d want the forest to have “internal growth” too if you previously chopped a few trees inside, and looking for edges might avoid that.

Other thoughts I had would be the number of trees you’d have to spawn.

  1. If you have a rather dense forest (currently I have about 4.5k trees) it should probably grow faster (spawn more new trees) than if there is only a few.
  2. If you have a very large forest, you’d need to somehow balance it so not all trees spawn on the same side of the forest (which would be unlikely, but still… ^^)

Maybe you could limit the number of new trees in a certain area with distance checks to the nearest newly spawned ones.

How is the performance? How often do you spawn trees, if you don’t find valid positions, do you just keep looping random ones? How many trees do you spawn during one go?

What I did is I used the procedural foliage tool to generate the trees (little over 10k at the map). As for performance right now I let them all grow at the same time, spawn all trees at the same time, so one epoch takes around 0.5s. If you would do it over time then I don’t think it’s much of an performance issue.

The setup with edge detection is different from the one I used it was only what I could think of because you wrote

I’d like it to be in different
positions than before
I don’t find new positions I spawn them on the same positions they were at the beginning :slight_smile:

I have a variable called “Free Transforms Spots” and every time I remove a tree, I add the transform of that it to the array. As for spawning them

So for every free transform it checks wether there is another tree in range and if so it spawns a tree; if there is no tree in range no tree gets spawned (so it spawns new trees only nearby existing trees).

Theres still sort of a bug in “transformtorespawn” cause I remove it in a running loop (thats why they only got spawned from one side).

In the construction script I add sphere collisions, at the beginning of the game all trees inside these spheres will be removed and added to “Free Transfrom Spots” (I add sphere collisions so I can see where I move them in the editor). So you could also remove the trees completly (not add them to “Free Transform Spots” so not respawn them).

And thats one growth simulation step

Construction and Event Begin Play

And of course somewhere you would have to set up timer to call the growstep function and the steprespawn.