Jump to content
  • Advertisement
Sign in to follow this  
  • entries
  • comments
  • views

Jumping into the voxel world

Sign in to follow this  
CC Ricers


I'm decided to go back XNA for my shooter game on Windows 7. Two reason why: Using custom effects is unwieldy with Monogame in Windows 7, and I'm wasting my time trying to figure out why they are not being built correctly, and making my game multi-platform is more of a long term goal. MonoGame is more geared to porting or writing code on platforms that don't natively support XNA, and because there are many tutorials on it for those platforms, building custom effects may be more straightforward. That is really the only issue I'm having with the content pipeline.

So for now I will go back to focus my efforts on making a prototype using XNA only and then when it's in a playable state, start porting for the other platforms.

Voxel World - First Attempt

Meanwhile, I decided I want to try my hand making a voxel-based world because I realized that, for a while, I have been interested in the idea in creating a huge world that would be at least interesting to look at and walk around on. Also, I want to find out the challenges that come in rendering such a world.

Eventually, I will want to make some sort of action/adventure type of game with the voxel/cube world engine once it is fleshed out well enough. So far it has been a mostly smooth experience to see what it goes into the code. To get a head start I picked out some pre-existing code to make 2D and 3D simplex noise. I quickly learned how the noise functions readily make a continuous texture without being repetitive, as it's of huge importance when making a procedurally generated world.

I started working on this on Saturday, and made some decent progress by Sunday night, making a cube world with 3D Simplex noise and some mesh optimization to avoid rendering hidden cubes. The custom shader is very simple and low bandwidth, taking only a Vector3 for local position and a Byte4 for color. The mesh-building code also adds a shade of green to cubes that are visible from above, and the rest are brownish in color. This creates a somewhat convincing grass-and-dirt look. Finally I implemented some basic brute-force culling to avoid rendering invisible chunks. Quick and dirty procedural world!



Some problems I found with this voxel-cube generator were, I frequently ran into out-of-memory exceptions when I decided to go any higher than 192^3 cubes. I was splitting the world into 32^3 sized chunks but it didn't really help out the memory problem. My guess is that the triple-nested loops used to calculate the noise values are wounded too tight, and it might benefit from single-dimensional arrays. Also, I was storing the chunks in a resizable list, but it makes more sense to have a fixed sized array to be able to keep track of them. Also, while interesting to look at, the shapes produced by 3D noise weren't very desirable so I switched to 2D to make a more believable height map. From there, I will then experiment with some 3D noise to get some interesting rock formations and caves going on.

Streaming the Voxel World

The next steps are to stream new chunks of the world into view as you move the camera around. I've already made some progress with this, only for now by showing a 2D noise texture that "scrolls" when the camera moves past a certain distance from the center chunk. Currently, when the world requests new chunks to be added, the cube meshes for all chunks are re-built. This of course is not efficient enough, but I have come across bugs in how chunks are ordered when I try to just re-build some of the chunks.

The world is drawn with a grid of n x n chunks, where n is an odd number so there is an actual "center" chunk for the camera to sit in. Each chunk has a 2D coordinate called the offset, which tells its world position, as offset by its local position. For a chunk that is 32 units long and wide, its local coordinates are 0 to 32, and the offset vector is added to give the chunk's cubes their world positions.

To update chunks I have planned the following series of steps to do on every frame.

For each chunk in the grid:

  • Get the X and Z distances between its offset position and the camera's position
  • If X or Z are too far away from the camera:

    • Set a new offset for the chunk according to its distance from the camera
    • Chunk automatically tagged as 'dirty' in updating its offset

    • [size=1](this bullet item needed to indent the above two items, there is a bug preventing me to do otherwise)

      Set a "chunks rebuilt" variable to 0

      (2nd loop) for each chunk in the grid:

      • If chunk is 'dirty':

        • Re-build the chunk's mesh with the new offset location
        • Increment "chunks rebuilt" by 1

        • If n chunks have been re-built, exit the loop

          Hopefully this plan will make it possible to update only part of the world, and with the proper offset coordinates being fed to them. I split the chunk updates into two separate loops so there it is clear which ones need to re-build their mesh and avoid discontinuities in updating. I actually think that recalculating the correct offset coordinates for "faraway" chunks would actually be the trickiest to get right, since it depends on the X and Z values of the camera.

          As far as the the "exit the loop" business goes in the second loop, that is meant to minimize any CPU stalling when re-building chunks. Calculating the noise values and determining what cubes need to be added to the mesh is going to be tasking for the CPU, so I decided it is better to just update a few chunks every frame. I'd rather have some chunks be visibly "in progress" rather than try to re-build all dirty chunks and abruptly stall or lag the game when the player enters another section of the world.

          So far I haven't seen any visible dips in framerate when 81 32x32 chunks are updated in one frame, but it's still good to have the feature of splitting updates across several frames when needed. Then I will go back and optimize the mesh building so that only the faces facing the outside are drawn, rather than the entire cube.
Sign in to follow this  


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!