I’ve been working on generating a forest and at this stage I’m trying to optimize the framerate. The forest contains about 10K trees, each of them having around 1k triangles. I’m projecting shadows. The whole thing looks like this
First thing I did was generating LODs on the meshes (so far only tried with 2 lods), I did see a significant impact on the framerate
Then I tried using batch geometries. Here, reading: My experiences with batching objects and the resulting frame rate
I made sure I split the whole forest into smaller nodes (100 nodes of about 100 trees, all trees use the same material) and this is what I see, at medium range, I feel the bulk geometry is actually a bit worse:
in comparison to the non-bulked
I don’t understand how come I still render 64 out of 100 nodes. With the layout of my forest, I would expect a much smaller fraction to show up from this camera angle (in the non-bulked, the fraction of objects showed is much smaller in comparison to the total)
At close range, I can see an improvement (like x2) from the bulking. Still I see that I’m rendering 44 nodes out of 100
vs the non-bulked
At long range, I see the bulk geometry doesn’t use LODs (even though I’m calling it through this
I don’t really care that much since I won’t be displaying the whole forest very often, but let me know if you see I am missing something)
Do you think there is a way to improve either the bulking, the z-culling or frustrum culling? Is there any other rendering optimization technique that would benefit the framerate?
Yes, there are billboards/impostors. That is a 2d quad with a texture of a tree. You can generate eg. 4-8 different textures from different angles and swap between these. You normally apply these for the furthest trees. They are very fast since 1 quad = 4 vertexes. To render them efficiently you can use instancing. The rotation and selection of texture can be done in a shader also. The generation of the textures can be done by code too.
Group them into a larger grid. Then as they get further away you could lower the lod until a certain point, then replace them with billboards, instanced billboards, or batched billboards, though you might have to have some shader knowledge first. The point is, when those trees are only a few pixels on screen, it is much better to just have a quad (two triangles) rendered per tree instead of a mesh. The trick is if you want to combine those quads into groups so the renderer can cull out large sections of the scene without having to check each tree individually. Most AAA games do this is some way or another, from skyrim to battlefield etc. You could combine all your tree billboard textures into one big texture atlas and render them all from that with a shader.
I tried creating an instancednode for the whole forest but then framerate dropped considerably since all trees have to be rendered all the time
Then I tried to instance each of the 100 sub nodes but then something very strange happened onscreen (like the forest turned into a big black shape with pieces of tree everywhere and framerate dropped to around 1 frame per 10 s) maybe because the 100 nodes share the same instanced material ?
I don’t know why that happens, but make sure you are putting the trees under a node based on location, not just random location, so that the renderer can check the nodes and cull areas that are offscreen.
You can do offscreen rendering at runtime or prebuilt that will render your tree into a 2d texture, just like taking a screenshot of it. Then you can arrange whatever you want into a texture atlas.
No, I believe the bounding box for a node is only based on the geometry max extents. You might want to try davidb’s viewer for debugging:
So you should:
Have close range trees be Instanced in location grid groups, or close range trees be in a Batch node/geometry batch factory, or close range trees be regular spatials if it is necessary.
Transition lods as the grids get further away
Eventually switch to a 2d billboard of the tree. The billboards should still be Instanced / batched per grid group, so they can be culled out optimally.
The hard part (that many games still haven’t solved perfectly) is transitioning between these without too much popping or noticeable change to the player. There are many techniques such as fading the object out/ fading in billboard that you can try out. There’s also dithering and rendering different rotations of the trees to fade between based on what direction the player is looking at the tree.
Just putting these here in case you want to dig around in other solutions.
SimArboreal will generate trees that have LOD, etc. built in, including simpler trees as well as full atlases. It supports wind, etc. even for instanced trees. It also supports an in-between LOD where each branch is rendered as a single camera-aligned quad (hard to describe in words).
it looks pretty neat! I downloaded the zip file but when importing it says I’m missing a bunch of com.simsilica.lemur.* which i can’t find on the simsilica home page, by any chance do you know where to get these?
Really sorry about that but I’m still seeing missing references such as below, even from simarboreal itself, for example the package (and I double checked the content from github to make sure it wasn’t just on my side) doesn’t contain the following references:
references the following (dead?) links like
Then in fileActionState I got an unknown class on TreeParameters at line 251 and 259
then ForestGridState references elements from the lemur node
which doesn’t exist
Continuing on the idea of the billboarding, I’ve played a bit with the concept and created a control to which you provide a node containing the regular mesh and a simple quad. There is a control attached to each node (each node represents a tree) and that control will swap the two geometries (removing one and adding the other) depending on the distance and rotate the quad accordingly to the camera (based on the demo from the jme3 library)
I am very surprised to see that my map with billboarding is slower than the one that only has meshes. You can see below that the object count is about the same, and as expected the triangle count of the billboard scene is 4M triangles vs 11M for all meshes
I will investigate more why the fps is dropping, but happy to hear if you can think of anything
Well, if you are checking the distance for every tree once per frame, that’ll do it. I was thinking more along the lines of only checking the distance per small chunk of trees, and maybe do some kind of time slicing so you’re only checking one chunk of trees a frame or so. Maybe check every chunk of trees once a second, though not all at once. In addition, computing the billboard rotation for every billboard every frame may be having an impact. Might be better to do it in a vertex shader.
I downloaded the IsoSurfaceDemo for Windows and tried to run it, but I got an error dialog: “The registry refers to a nonexistent Java Runtime Environment installation of the runtime is corrupted. The system cannot find the file specified.”