MultiThread chunk mesh generation.

Removed BlockChunk property from MeshChunk
MeshChunk::build() now takes vectors for the indices and vertices instead of doing it itself
World class now MultiThreads generation of MeshChunks using the BiQueueThreadPool spec developed by Aurailus (not conforming)
World::ThreadData object for simplifying communication between threads
master
aurailus 2018-12-16 21:42:21 -08:00
parent 9605fb14f8
commit c96e612a9f
6 changed files with 105 additions and 35 deletions

View File

@ -107,11 +107,11 @@ BlockAtlas* createAtlas() {
void genChunks(World* world) {
PerlinNoise p(0);
int VIEW_RANGE = 1;
int VIEW_RANGE = 32;
for (int i = -VIEW_RANGE; i < VIEW_RANGE; i++) {
for (int j = -VIEW_RANGE; j < VIEW_RANGE; j++) {
for (int k = -2; k < 2; k++) {
for (int k = -1; k < 1; k++) {
auto* blocks = new std::vector<int>();
blocks->reserve(4096);

View File

@ -11,6 +11,7 @@ MeshGenerator::MeshGenerator() {
bool outOfRange(glm::vec3 pos) {
return (pos.x < 0 || pos.x > 15 || pos.y < 0 || pos.y > 15 || pos.z < 0 || pos.z > 15);
// return false;
}
void MeshGenerator::build(BlockChunk* chunk, BlockAtlas* atlas,
@ -59,15 +60,15 @@ void MeshGenerator::build(BlockChunk* chunk, BlockAtlas* atlas,
vertices.shrink_to_fit();
indices.shrink_to_fit();
t.elapsedMs();
// t.elapsedMs();
}
void MeshGenerator::addFaces(glm::vec3 &offset, vector<float>* vertices, vector<unsigned int>* indices, vector<MeshPart*>* meshParts) {
for (MeshPart *mp : *meshParts) {
MeshVertexIter *mvIterator = mp->getVertexIterator();
while (mvIterator->hasNext()) {
Vertex *vertex = mvIterator->next();
MeshVertexIter *vertexIter = mp->getVertexIterator();
while (vertexIter->hasNext()) {
Vertex *vertex = vertexIter->next();
vertices->push_back(vertex->pos->x + offset.x);
vertices->push_back(vertex->pos->y + offset.y);
@ -81,9 +82,9 @@ void MeshGenerator::addFaces(glm::vec3 &offset, vector<float>* vertices, vector<
vertices->push_back(vertex->nml->z);
}
MeshIndexIter *miIterator = mp->getIndexIterator();
while (miIterator->hasNext()) {
unsigned int index = miIterator->next();
MeshIndexIter *indexIter = mp->getIndexIterator();
while (indexIter->hasNext()) {
unsigned int index = indexIter->next();
indices->push_back(indOffset + index);
}
indOffset += mp->getVertexCount();

View File

@ -8,24 +8,13 @@ MeshChunk::MeshChunk() {
ready = false;
}
MeshChunk::MeshChunk(BlockChunk *blockChunk) {
this->blockChunk = blockChunk;
ready = false;
}
bool MeshChunk::isReady() {
return ready;
}
void MeshChunk::build(BlockAtlas* atlas) {
std::vector<float> vertices;
std::vector<unsigned int> indices;
MeshGenerator mg;
mg.build(blockChunk, atlas, vertices, indices);
void MeshChunk::build(std::vector<float> *vertices, std::vector<unsigned int> *indices) {
auto *mesh = new Mesh();
mesh->create(&vertices, &indices);
mesh->create(vertices, indices);
this->create(mesh);
ready = true;
}

View File

@ -13,14 +13,12 @@
class MeshChunk : public Entity {
public:
MeshChunk();
explicit MeshChunk(BlockChunk* blockChunk);
void build(BlockAtlas* atlas);
void build(std::vector<float> *vertices, std::vector<unsigned int> *indices);
bool isReady();
private:
bool ready;
BlockChunk* blockChunk;
};

View File

@ -4,6 +4,10 @@
#include "World.h"
World::World() {
blockAtlas = nullptr;
}
World::World(BlockAtlas *atlas) {
blockAtlas = atlas;
}
@ -13,18 +17,56 @@ void World::newChunk(glm::vec3* pos, BlockChunk *c) {
meshGenQueue.insert(pos);
}
void genThread(World::ThreadData* t) {
MeshGenerator().build(t->chunk, t->atlas, *(t->vertices), *(t->indices));
t->done = true;
}
void World::update() {
int done = 0;
while (!meshGenQueue.empty() && done < 8) {
//Run through all of the active generation threads, and finish and remove the ones that are ready to be finished.
//Then, spin up new threads when there is space in the genThreads array and there are chunks waiting to be meshed.
//Create MeshChunks for the finished threads.
Timer applyGlobal("Applying Meshes");
for (auto iter = genThreads.begin(); iter != genThreads.end(); ) {
ThreadData* threadData = (*iter);
//If the threadData is done, create a MeshChunk and delete the threadData.
if (threadData->done) {
Timer apply("Applying Mesh");
auto meshChunk = new MeshChunk();
meshChunk->build(threadData->vertices, threadData->indices);
meshChunk->setPosition(*(threadData->pos) * glm::vec3(CHUNK_SIZE));
meshChunks.insert(std::pair<glm::vec3*, MeshChunk*>(threadData->pos, meshChunk));
// apply.elapsedMs();
delete threadData;
iter = genThreads.erase(iter);
}
//Otherwise ignore it and move to the next MeshChunk
else {
iter++;
}
}
// applyGlobal.elapsedMs();
//Begin processing queued chunks if there are chunks to be processed and there's room for more threads.
while (!meshGenQueue.empty() && genThreads.size() < MAX_CONCURRENT_THREADS) {
//Get and remove the first position from the vector.
auto it = meshGenQueue.begin();
meshGenQueue.erase(meshGenQueue.begin());
glm::vec3* pos = (*it);
auto meshChunk = new MeshChunk(blockChunks.at(pos));
meshChunk->build(blockAtlas);
meshChunk->setPosition(glm::vec3(pos->x * CHUNK_SIZE, pos->y * CHUNK_SIZE, pos->z * CHUNK_SIZE));
meshChunks.insert(std::pair<glm::vec3*, MeshChunk*>(pos, meshChunk));
//Create a thread for it and add the threadData to the genThreads vector
auto t = new ThreadData(pos, blockChunks.at(pos), blockAtlas);
auto thread = new std::thread(genThread, t);
thread->detach();
t->thread = thread;
genThreads.push_back(t);
}
}
@ -33,4 +75,22 @@ void World::draw(GLint modelUni) {
glUniformMatrix4fv(modelUni, 1, GL_FALSE, glm::value_ptr(meshChunk.second->getModelMatrix()));
meshChunk.second->draw();
}
}
World::ThreadData::ThreadData(glm::vec3 *pos, BlockChunk *chunk, BlockAtlas *atlas) {
this->pos = pos;
this->chunk = chunk;
this->atlas = atlas;
this->done = false;
this->vertices = new std::vector<float>();
this->indices = new std::vector<unsigned int>();
}
World::ThreadData::~ThreadData() {
//Not delete this->pos because it is used in the MeshChunk and BlockChunk vectors.
//delete pos
delete vertices;
delete indices;
//Delete the thread, when the deconstructor is called, the thread is done.
delete thread;
}

View File

@ -6,10 +6,11 @@
#define GLPROJECT_WORLD_H
#include <map>
#include <vec3.hpp>
#include <unordered_set>
#include <iostream>
#include <gtc/type_ptr.hpp>
#include <vec3.hpp>
#include <thread>
#include "BlockChunk.h"
#include "MeshChunk.h"
@ -17,7 +18,7 @@
class World {
public:
World() = default;
World();
explicit World(BlockAtlas* atlas);
void newChunk(glm::vec3* pos, BlockChunk* c);
@ -26,6 +27,23 @@ public:
void draw(GLint modelUni);
~World() = default;
struct ThreadData {
ThreadData(glm::vec3* pos, BlockChunk* chunk, BlockAtlas* atlas);
std::thread* thread;
glm::vec3* pos;
BlockChunk* chunk;
BlockAtlas* atlas;
bool done;
std::vector<float>* vertices;
std::vector<unsigned int>* indices;
~ThreadData();
};
private:
//Note to self:
//The same glm::vec3 pointer is used for the blockChunk and meshChunk maps. If discarding a block/meshChunk, keep
@ -35,6 +53,10 @@ private:
std::unordered_set<glm::vec3*> meshGenQueue;
const int MAX_CONCURRENT_THREADS = 32;
std::vector<ThreadData*> genThreads;
BlockAtlas* blockAtlas;
};