Ok, I pushed some heightmap saving code to the github repo. In a nutshell it simply saves the heightmap data in a “./world/” folder whenever a tile is generated, and loads it from there if it exists instead of re-generating it. This reduces the time it takes to load pre-generated tiles quite significantly, and is persistent every time the game loads up. Just don’t forget to clear the saved data if you want to change any noise generation settings. It also does this for ImageBasedWorld too, it stands to reason that loading a float array is going to be quicker than reading the image.
OK good news is it’s really quite fast now. Bad news is, I got a full on crash:
[java]
SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:658)
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:306)
at com.jme3.util.BufferUtils.createFloatBuffer(BufferUtils.java:831)
at com.jme3.terrain.geomipmap.LODGeomap.writeNormalArray(LODGeomap.java:790)
at com.jme3.terrain.geomipmap.TerrainPatch.updateNormals(TerrainPatch.java:332)
at com.jme3.terrain.geomipmap.TerrainQuad.fixNormals(TerrainQuad.java:1610)
at com.jme3.terrain.geomipmap.TerrainQuad.updateNormals(TerrainQuad.java:268)
at com.jme3.terrain.geomipmap.NormalRecalcControl.controlUpdate(NormalRecalcControl.java:62)
at com.jme3.scene.control.AbstractControl.update(AbstractControl.java:112)
at com.jme3.scene.Spatial.runControlUpdate(Spatial.java:570)
at com.jme3.scene.Spatial.updateLogicalState(Spatial.java:688)
at com.jme3.scene.Node.updateLogicalState(Node.java:145)
at com.jme3.scene.Node.updateLogicalState(Node.java:152)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:244)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:185)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:228)
at java.lang.Thread.run(Thread.java:722)
[/java]
Any chance you could commit the trees bit to the repo as well? I am tinkering with textures and toneg0d’s skydome to make a nice demo video for this component but I am lacking the trees
@monkeychops You know that’s quite a wierd crash. Can you possibly disable the cache system by remarking out lines 227 and 228 of World.java:
If you still get that crash, we can rule out the cache system causing it.
I’ve already added the preliminary stages to add static rigids (trees, boulders) and non-rigids (grass, flowers, etc) to each chunk, but I didn’t want to get too far ahead of myself and continue to add things when we aren’t certain the things that are already there are exactly as we want them. I think we still need a couple days to solidify our foundation.
I ramped up the cache time to 9000 seconds and flew around for a few minutes and eventually it threw the same error you guys were getting. I repeated it with the cache off and i still got the error. The report is pointing at the Lod control for some reason. @Sploreg do you know what would cause your control to throw that error? Last time i saw a report like that was when I was trying to write too much data to the buffer…
@jayfella said: I ramped up the cache time to 9000 seconds and flew around for a few minutes and eventually it threw the same error you guys were getting. I repeated it with the cache off and i still got the error. The report is pointing at the Lod control for some reason. @Sploreg do you know what would cause your control to throw that error? Last time i saw a report like that was when I was trying to write too much data to the buffer..@jayfella I think I've found the error, as I was looking at debugger info I noticed a big amount of threads being spawned with the name "jME Terrain Thread". This is the name of the deamon Thread created in TerrainLodControl.
Because each terrain chunk will get it’s own LodControl, those threads are eventually a killer, as they’re not being destroyed, and contain references to the terrain, which means the gc won’t clean that. So effectively every chunk is still in memory even when deleted from cache :\
This error: “java.lang.OutOfMemoryError: Direct buffer memory”
Means you are running out of memory.
Most likely cause is low direct heap max but high regular heap max… so GC never runs and thus direct memory is never freed. It has little to do with where the exception is being thrown in this case.
@reveance and @pspeed you are both correct, the LOD controls are spawning tons of threads that aren’t closing:
Yikes. Sounds like another case for a shared thread pool executor.
As Paul said, you are just running out of memory. It just happened to occur in the LOD control.
The LOD control spawns a thread to run the LOD calculations. If you load 50 terrain tiles, you have 50 LOD controls since each one runs on its own terrain quad.
However, those threads do not disappear and they should be removed just to be clean. They don’t store much info, but if the terrain quad is gone, they should be gone too.
I am committing a fix for that now. You will have to detach the control when you detach the terrain by calling lodControl.detachAndCleanUpControl()
TerrainTestAdvanced.java has an example of this now.
It does use a shared thread pool executor but on each control. There is one control per-terrain and they don’t really know about each other.
Thanks @Sploreg for the super quick fix.
I won’t bother testing this now since it seems the cause was found before I checked back
I have to say - this is really an exciting thread… I can already picture all the cool open world games we’ll be able to make with this
We got the updated control today for Lod so I’ll push the changes as soon as netbeans stops telling me there are no files available for commit But I can confirm that the Lod Control works as expected now, so thanks @Sploreg - I wanted to also bring an inherited problem to your attention, the MultiTerrainLodControl may also need ammending as a result of your update.
Having said that, I think I might create a branch of the LodControl and pass the world ThreadPool to it to use rather than have it spawn one thread for each Lodcontrol, If anything it will give us control of how many threads we spawn. Currently with a 5x5 (view distance of 2) it will spawn 25 threads in addition to our own threadpool. I think lower-clocked CPU’s (2.0 GHz and below) are most likely to notice significant gains from this, but also, as far as I am aware, each thread takes 320k in a 32bit environment and 1024k in a 64bit env, so we can also take a nice little bite of memory consumption out of the game too.
@jayfella I will give it a try when you’re done.
Do you think there’s anything that can be done to increase the view distance? It works nicely with a view distance of 2 or 3 with 129 blocks but doesn’t really take us up to the horizon and give us distant mountains and such. Since increasing the tile size seems to hurt, can we do something with scaling maybe?
@monkeychops last time I checked (netbeans seems to take forever preparing the commit right now so I can’t check) a viewdistance of 5 was the limit before the camera viewFrustrum kicked in anyway and started culling them from view, so we have a potential maximum of somewhere between 516 and 645 anyway. I’ll write the code for the Lod control to share the world threadpool and we can see what gains we reap from that.
@jayfella said: @monkeychops last time I checked (netbeans seems to take forever preparing the commit right now so I can't check) a viewdistance of 5 was the limit before the camera viewFrustrum kicked in anyway and started culling them from view, so we have a potential maximum of somewhere between 516 and 645 anyway. I'll write the code for the Lod control to share the world threadpool and we can see what gains we reap from that.When the lod is working good, i think you should be able use cam.setFrustumFar(10000); without it getting too laggy. However When looking that far I think the chunk's should be bigger aswell, because it'd be way too many chunks to handle if theyre not bigger I guess
@monkeychops and @reveance - I’ve pushed a new ModifiedTerrainLodControl to use the world ScheduledThreadPoolExecutor instead of the default behaviour of creating a thread for each Lod Control. This has the added benefit of not needing to manually shut down each individual thread as we found yesterday, and also allows us to directly control the number of threads created, and also improves on the fact that we are not continually creating and destroying threads.
May I be so bold as to ask @Sploreg to consider the change as a permanent footing? Basically all I have added is two overloads (one for a single camera, one for multiple cameras) that have a ScheduledThreadPoolExecutor as an extra argument, and uses that instead if given, else it reverts to your default behaviour if not.
@jayfella said: @monkeychops and @reveance - I've pushed a new ModifiedTerrainLodControl to use the world ScheduledThreadPoolExecutor instead of the default behaviour of creating a thread for each Lod Control. This has the added benefit of not needing to manually shut down each individual thread as we found yesterday, and also allows us to directly control the number of threads created, and also improves on the fact that we are not continually creating and destroying threads.May I be so bold as to ask @Sploreg to consider the change as a permanent footing? Basically all I have added is two overloads (one for a single camera, one for multiple cameras) that have a ScheduledThreadPoolExecutor as an extra argument, and uses that instead if given, else it reverts to your default behaviour if not.
Well done, looks to be working nicely

I have been trying to debug the framedrops for a while now, and I can’t seem to figure out what the cause is… It seems to be happening at the moment new items are just added to the worldTilesQue / threadpool
The MultiTerrainLodControl subclasses and gets the same fix as the TerrainLodControl. However I just remembered that the multi one should be used for your use-case here, and just add/remove the terrains from it. Each terrain won’t need its own.
As for your changes, why not just supply an executor and the terrain will use that instead of making its own? Instead of keeping the two around, and just using the Executor interface. Unless I missed something you are doing in particular with the ScheduledThreadPoolExecutor
I pass the ScheduledThreadPoolExecutor to the LodControl in the new constructors I added and it uses that instead of your behaviour. So:
[java]
// uses your default behaviour
TerrainLodControl lodControl = new TerrainLodControl(terrain, camera);
// uses the supplied threadpool instead
TerrainLodControl lodControl = new TerrainLodControl(terrain, camera, threadpool);
[/java]
Both constructors exist in the modified version I made, but you just get the choice to use either your default behaviour (and maintain backwards compatibility) or use a threadpool that your game already has instead.
If a threadpool is given to the lodControl, your default behaviour is never initialized, it doesnt create both.