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 threadsmaster
parent
9605fb14f8
commit
c96e612a9f
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue