Creating a voxel world with 3D arrays using threads
- by Sean M.
I am making a voxel game (a bit like Minecraft) in C++(11), and I've come across an issue with creating a world efficiently.
In my program, I have a World class, which holds a 3D array of Region class pointers. When I initialize the world, I give it a width, height, and depth so it knows how large of a world to create. Each Region is split up into a 32x32x32 area of blocks, so as you may guess, it takes a while to initialize the world once the world gets to be above 8x4x8 Regions. In order to alleviate this issue, I thought that using threads to generate different levels of the world concurrently would make it go faster.
Having not used threads much before this, and being still relatively new to C++, I'm not entirely sure how to go about implementing one thread per level (level being a xz plane with a height of 1), when there is a variable number of levels.
I tried this:
for(int i = 0; i < height; i++)
{
std::thread th(std::bind(&World::load, this, width, height, depth));
th.join();
}
Where load() just loads all Regions at height "height". But that executes the threads one at a time (which makes sense, looking back), and that of course takes as long as generating all Regions in one loop.
I then tried:
std::thread t1(std::bind(&World::load, this, w, h1, h2 - 1, d));
std::thread t2(std::bind(&World::load, this, w, h2, h3 - 1, d));
std::thread t3(std::bind(&World::load, this, w, h3, h4 - 1, d));
std::thread t4(std::bind(&World::load, this, w, h4, h - 1, d));
t1.join();
t2.join();
t3.join();
t4.join();
This works in that the world loads about 3-3.5 times faster, but this forces the height to be a multiple of 4, and it also gives the same exact VAO object to every single Region, which need individual VAOs in order to render properly. The VAO of each Region is set in the constructor, so I'm assuming that somehow the VAO number is not thread safe or something (again, unfamiliar with threads).
So basically, my question is two one-part:
How to I implement a variable number of threads that all execute at the same time, and force the main thread to wait for them using join() without stopping the other threads?
How do I make the VAO objects thread safe, so when a bunch of Regions are being created at the same time across multiple threads, they don't all get the exact same VAO? Turns out it has to do with GL contexts not working across multiple threads. I moved the VAO/VBO creation back to the main thread. Fixed!
Here is the code for block.h/.cpp, region.h/.cpp, and CVBObject.h/.cpp which controls VBOs and VAOs, in case you need it.
If you need to see anything else just ask.
EDIT: Also, I'd prefer not to have answers that are like "you should have used boost". I'm trying to do this without boost to get used to threads before moving onto other libraries.