2
\$\begingroup\$

I'm designing a voxel-based game (aren't we all?), and just yesterday implemented infinite terrain generation. I'd already had the terrain generation working off of simplex noise, so this wasn't a problem, and I've worked a lot with terrain generation before.. Anyway, I found myself hitting performance issues with the huge increase in "stuff to draw", so I started optimizing and disposing of vertex buffers for chunks that were out of frustum, then created a "SurroundingChunks(Vec3 position, int range)" function that as you may assume returns the chunks surrounding a position within a range. I used this to cull the chunks being even considered for drawing before the frustum check.

Performance is pretty good when it isn't generating new chunks (haven't multithreaded yet), but after I had already worked out the performance issue I came across an alternate solution, and I was wondering how it would compare.

In a normal chunk-based terrain, the player moves around in the chunks and chunks are loaded and unloaded depending on some algorithm/methodology. In this alternate method, there are a fixed number of chunks in existance. For the sake of simplicity, let's pretend we have a chunk-view-distance of 1, i.e., 8 chunks around the player and the one he's standing on for a total of 9. Instead of allowing the player to roam around infinite chunks, the chunks are replaced with others as the player proceeds in a direction. This could mean the player never moves, and some movement buffer dictates chunk changing, or it triggers when the player moves over a chunk boundary and then resets the player to the center (like many FPS mouse schemes, but with a player in 3D).

I drew a crappy little diagram in mspaint (don't have better tools on hand) to help illustrate this concept:

chunk swapping diagram

I'm curious whether this would perform better than doing all of the detection work for chunks in range and frustum culling followed by unloading any unneeded chunks, since it wouldn't require as much detection work. However, I am concerned that it would complicate things in the future, for example when there are enemy entities - they would have to constantly be position shifted with the land, etc..

I was hoping perhaps you guys would chime in with thoughts, pros, cons, opinions, etc.. :3

\$\endgroup\$
0
\$\begingroup\$

Thinking about how we render our virtual worlds you do several things ...

  1. setup a vertex buffer
  2. setup a shader stack
  3. set some constants (world, view, projection) for the frame and object

So logically thinking about that, to move the entire world 1 chunk in any direction what do I actually change on my normal render cycle ...

...

Nothing ... I do the same in my draw calls, but in my update loop I update my root object transform and all children inherit that change and the render loop continues as normal.

So,

With moving a chunk effectively being "free" I can't see an issue moving the whole world when a player steps over a chunk boundary.

However ...

I took a more liberal approach by setting "areas" in which the player could be to prevent a constant recalculation of the transform information.

For example:

lets say im moving --->>>>

c1, c2, c3, c4

when i move from c1 to c2 I do nothing, when I move from c2 to c3 I move the world back by 2 chunks.

How does this help ... Lets say a player is having a rather large fight and every frame counts but they are doing this right on a chunk intersection or worse on the corner of a chunk so this applies in 3 dimensions. Having that 1 chunk buffer means I make the change once until the player moves a reasonable distance so the "expensive but still cheap" math only happens once for that area.

I apply the same logic to loading and unloading chunks on my world edges too to sort of apply a "temporary cache" around the currently being rendered terrain.

\$\endgroup\$
0
\$\begingroup\$

A combination of both methods is what I've used in the past. Essentially your character is still moving around in the world with a set number of chunks following them. Each axis of the chunk array is like a conveyor belt of chunks, shifted when new chunks are loaded and old chunks unloaded. Make sure you're not reloading chunk data when shifting it, just changing the references. Only the leading edge of the grid of chunks should be loading new.

However, if you wanted to move everything around the player, it's not so bad. If you have the entire world all children of one object transform, and the player outside that world, all you have to do is move the world transform to move everything in the world.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.