Attaching nodes on the fly without loosing FPS

Hi all,

I’m working on an open world almost end-less. It’s divided in chunks. I’ve designed a simple manager so that the player can walk in any direction for a long period of time. It’s the classic “scroller”, here is a diagram to help you understand

-------------------------
|       |       |       |
|       |       |       |
|-------+-------+-------|
|       |       |       |
|       |   x   |       |
|-------+-------+-------|
|       |       |       |
|       |       |       |
|-----------------------|

Internally I manage a grid of 3*3 chunks. The player is always in the same chunk : the one at 1,1. If he enters the chunk on the left, the grid shifts to the right and 3 new chunks are created, and attached to the scene ; the other 3 are cleaned up.

This systems works quite well but some chunks have more “content”. And when the engine adds too much stuff at once, we experience an FPS drop.

My question is : with JME, what would be the best strategy to handle this ?

The chunks are composed exclusively of com.jme3.scene.shape.Box ; some have a lot ! Also there’s a directional light. LOD is not possible.

Maybe I could design a system that adds x number of Boxes, wait for next tick, then add another x number of Boxes until all is added ? Also, every time the grid shifts, it’s 3 chunks : maybe this could be parallelized, but I read somewhere that doing that is a big no-no in JME…

Also, what causes this FPS drop ? Is it the fact that Nodes are added, or the render of the Nodes ? Thus, would a fog fixes this ?

All feedback appreciated :smiley:

Updates :

  • I was talking about Minecraft chunks, not the voxels per se :

A chunk in Minecraft is a procedurally generated 16 x 16 segment of the world that extends all the way down to the bedrock up to a height of 256 blocks . In other words, a chunk is simply a small portion of your game world that consists of a maximum of 65,536 blocks.

  • I’m already using GeometryBatchFactory.optimize

So first off… minecraft world’s aren’t made up of boxes which is probably why you are losing a lot of your fps. It makes more sense to use a custom mesh and only add the visible faces. This drastically reduces the item count and makes it much less costly to attach to the scene graph. There is a block plugin on the asset store which I would recommend taking a look at to get a better idea of how it is handled.

The lag from attaching something to the scene graph could be any number of things. Often it is from uploading mesh / texture data to the GPU. In your case it’s probably from the sheer number of items you are trying to attach.

1 Like

but why… why not voxel then? with possible LOD too…

Also, what causes this FPS drop ? Is it the fact that Nodes are added, or the render of the Nodes ? Thus, would a fog fixes this ?

  1. Object amount - batch geoms to have less geoms there (voxel is one of strategy - chunks(chunk geom). 1 chunk = 1 geom usually in Minecraft like games. You can have much more, but anyway best to stick like 100 objects(geoms) up to 1000 max i assume. If someone who have 1000000+ geoms in scene wonder why its slow… then he have answer. But well its more about FPS instead of load freeze.

  2. Like said above, by glh, minecraft is not made of boxes, its just illusion, its voxel world. There are ready2use existing libraries in JME for it.

  3. Preload Textures / Mesh in another thread.
    Attach in main thread(update loop) only already loaded things

  4. If this still make any small freeze, split generation into smaller parts into multiple frames

  5. fog will not fix it (but if you mix with render distance, it might help a little… a little… not much like points above)

here is example voxel lib:

JME game example voxel with LOD:

1 Like

I’ve updated OP : Minecraft was just an example for understanding chunks. In term of looks, it has nothing to do with Minecraft

Sorry I’m kind of a newb for 3D stuff, but basicaly you are saying to only call something like rootNode.attach in the main thread. And all the other things like new Box(), new Geometry(), new Material() in a separated thread. Is that correct ?

Ok that I understand :smiley:

basically yes. Remember that frame is both GPU and CPU. if CPU bottleneck main thread, it will affect FPS.

But here, for a CPU we have more cores, so you can use another thread/core to not affect game thread/core. (app.enqueue is what you need for sync threads basically)

There is one thing that you can’t avoid. It is “passing” data(textures/mesh) from CPU to GPU like textures, but it should be really fast, until you use plenty of 4k textures. (then it is good to split loading them into multiple frames) And second thing like i said earlier. DrawCalls(geometry) try to have lowest amount as possible to just have better fps.

Just to add, i also use GRID system for non-voxel world(just not infinite). And here is tip for you “use separate physics spaces for each grid” if you gonna use physics on large areas(if area is small, it can be one). And suggest Minie here.

1 Like

Also, even if you generate/load your geometry on a separate thread, only attach a few things per frame to the scene or you will also see noticeable frame drops.

3 Likes

To add a bit of my own view on this (my One Million Worlds is a blockworld). To give some idea of whats plausibly possible; with my fairly decent gaming laptop I’m able to get a render distance of 300 meters without framerate drop (and 500 meters if im prepared to accept some drop or turn off things like fancy water).

Each chunk (16 by 16 by 256) is 1sh* geometry built from a custom mesh. That means that i never use a Box, I build up a mesh from the voxels. As already said there are libraries for that (although i dont use those for probably poor reasons). An important point here is that if a face isnt visible no face is created for it (by not visibly i mean has annother block attached to it). Ive also developed some tricks to in fact have less than one mesh face per voxel face but i wouldn’t suggest you worry about that yet (or at all if you use a library).

As others have said, i build up the mesh and geometry on a separate thread then swap it in on the main thread when it’s ready.

( *I say “ish” because ive done stuff like having the caves as a separate geomtry so i can have a much smaller render distance than the surface world)

1 Like