I have not directly one asset because the trees are not directly growing but instead every tree actor only have a reference to where it’s own mesh is inside of a Hierarchical Instanced Static Mesh Component in a Tree Manager.
I have tested it with Preview 4 and I still get the log spam. But I noticed that it does not happen if only 1 or 2 Instances get updated, there I only get the log message once when an instance spawns. But if I reach 3 or 4 Instances, the message appears every time an instance get updated.
You might have tried it only with too few instances so you didn’t get the log spam?
If you also can’t reproduce it with more instances please tell me and I will try to reproduce it in a clean project!
You can’t reproduce it closely to what I have, because I have written my own “Shared Hierarchical Instanced Static Mesh Component” which is used by the trees to easily share the same HISMC with still being individual actors.
But this should not matter at all because internally it’s just one HISMC where Instances get updated.
Our developers took a look at UE=16224 and determined that the output log warning is working as intended. I did some more digging and discussed with them about the reasoning behind this. Hierarchical Instanced Static Meshes are not designed to be transformed every frame. These components are bound to a bounding volume tree, which needs to be rebuilt every time something is moved or changed. This ends up taking longer than rendering itself and becomes counter productive. The developers mentioned that while it isn’t the best idea to rapidly transform Instance static mesh components either, that is more dependent upon how many you are moving/changing at once and not as limiting in this regard as HISMC are. This is because it requires uploading the entire instance buffer to the GPU every frame plus additional data conversion.
It’s good to know that HISMCs are not designed to be used like this, I think this should be mentioned somewhere.
I have tried updating hundreds of instances simultaneously in a HISMC and I did not had any performance problems, so I think it works fine for me. But the output in the log is just really annoying. If your developers think it’s helpful, could they add something like a boolean to tick in the details panel of a HISMC which would be true by default but could be disabled? Or add an option for this in the ConsoleVariables.ini or any other ini file?
I also think that using a regular ISMC does not really work for foliage, right? They don’t support LODs, and that’s why the HISMC was introduced specifically for foliage, since foliage without LODs is comsuming way too much performance. So what would you suggest to use for trees instead? Having hundreds of trees as one ISMC does not work because LODs are missing. Having hundreds of trees as one HISMC does not work if they want to grow because your developers say it’s taking more performance then rendering itself. And having hundreds of trees as regular Static Mesh Components also seem to be like a waste of draw cells.
I’ll certainly pass on the suggestion for notes on the HISMC! Unfortunately the best alternative I can think of at this moment would be to create an individual blueprint that is one tree static mesh with it’s growth operation, then utilize a second blueprint that calls on all actors of class (tree) to run that function. I’ve never tried anything quite like it so it may take some time but I’ll have a look on my end to see if I can come up with a more viable solution in the meantime.
What is the end result you are looking to achieve?
What I want to achieve is having thousands of trees in my level which all will grow, create seedlings and can get cut down with not affecting performance too much. And it’s working at the moment with using a HISMC, but I have only tried a few hundred trees and not thousands. Just the log message is annoying. And the Speedtree color variation seems to have some problems with HISMC, but I think I should just disable it.
Why would you suggest to use regular Static Mesh Components and then grow them all at once from another blueprint? Where is the problem with letting them grow on their own? Using a regular Static mesh Component will decrease performance because of draw cells, and I think performance is better if every tree updates only itself because then the growing is way better destributed over multiple frames. If 1000 trees get scaled every 10 seconds this will probably create a frame spike every 10 seconds, but if they all do it on their own during this 10 seconds then only like 5 or 10 trees grow per frame. There is a delay/timer overhead because these 1000 trees have individual timers/delays for updating itself every 10 seconds, and timers actually have way too much overhead in blueprints for this, but I use a looped delay for this and it works fine.
It would be the same setup, simply in C++. When performing intense operations like this C++ tends to handle the function much more efficiently than blueprints are able to. However, I have another suggestion after discussing this with some of the devs here at Epic. Have you thought about utilizing materials to alter the trees? You can use displacement to give the illusion of growth without it being as performance intensive as actually manually adjusting the trees along the landscape through script.
I know that I may need to convert all my complex logic into c++ at some time in the future, but at the moment I would like to stick with blueprint.
I have not thought about displacement at all because I am really not too familiar with materials, and I can’t image I could scale a tree from 0.2 to 1 just with displacement?
You can do it through materials, though it would be a challenge to put together the exact math you need. However, I did some further digging and found out that Eric Ketchum from our support team has put together an awesome wiki tutorial on doing something very similar to what you are trying. Take a look here and see if you can utilize the information present:
What is good is that he uses instanced meshes in his scaling, which means that the draw calls will be extremely low for what you are trying to do.
Thanks, but I can’t find where he uses a material to scale anything…
He uses a growing particle effect, and growing Instanced Static Mesh Components and only uses the material for changing the ground texture from the tiles to a green grass.
And apart from this I think it does not make any sense how he uses the Instanced Static Mesh Components, he uses one Component per Instance. As far as I know then all the advantage of using an Instanced Static Mesh Component does not exist and it’s basically the same as using a regular Static Mesh Component. For having better performance, only one ISMC with multiple instances inside needs to be used. I might be wrong, but there is no documentation about ISMC so I can’t look this up. But I’m like 99% sure that with his setup he has the same amount of draw cells as if he would use regular static meshes.
Opening the Construction Script of the TerrianMorph Blueprint in my tutorial, you will follow the path and come to a commented section “Create Instanced Static Mesh Components to use as templates, once for each mesh type.” If you look closely at the logic, the construction script allows the user to predefine a series of mesh types (in my tutorial I use it just for grass, but the same logic can be found in Blueprint Office where we spawn grass, weeds and wildflowers). Each predefined Mesh type is then instanced so in my tutorial I have many instances of the grass mesh, but because it is all instances of the same mesh, it is only one draw call. In the blueprint office, you would find 3 draw calls.
You are correct in that I do not use Materials to change the size of the grass it is a change to the relative World Scale of the mesh, but works just as efficiently and probably slightly more performant than trying to manipulate the WPO of the material. The only difficult part is setting up your arrays that are necessary for storing of the mesh scales from generation in the construction script so they can be called again at runtime.