Waterflow
Visualize water in terrain
|
00001 #include "voxel.h" 00002 #include "GL_utilities.h" 00003 00004 #include <iostream> 00005 #include "gtc/type_ptr.hpp" 00006 #include "GL_utilities.h" 00007 #include "glm.hpp" 00008 00009 00010 void Voxelgrid::rehash(){ 00011 hashSize = hashSize*2; 00012 std::vector<voxel*>* tempTable = new std::vector<voxel*>((int)hashSize,nullptr); 00013 numCollisions = 0; 00014 numInTable = 0; 00015 00016 std::cout << "Rehash Triggered: " << hashSize << std::endl; 00017 00018 for (std::vector<voxel*>::iterator it = hashTable->begin(); it!=hashTable->end(); ++it){ 00019 if(*it != nullptr){ 00020 00021 voxel* temp = *it; 00022 int64_t hashPos = hashFunc(temp->x,temp->y,temp->z,hashSize); 00023 if(tempTable->at(hashPos) == nullptr){ 00024 tempTable->at(hashPos) = *it; 00025 numInTable++; 00026 }else{ 00027 numCollisions++; 00028 hashPos++; 00029 int numLinearRepeat = 0; 00030 hashPos = hashPos % hashSize; 00031 while (tempTable->at(hashPos) != nullptr) { 00032 hashPos++; 00033 hashPos = hashPos % hashSize; 00034 numLinearRepeat++; 00035 } 00036 numInTable++; 00037 tempTable->at(hashPos) = *it; 00038 } 00039 } 00040 } 00041 00042 delete hashTable; 00043 hashTable = tempTable; 00044 00045 std::cout << "rehash finished" << std::endl; 00046 } 00047 00048 int64_t Voxelgrid::hashFunc(int64_t x, int64_t y, int64_t z,int64_t inHashSize){ 00049 return std::abs((((73856093 * x) + (19349663 * y) + (83492791 * z)) % inHashSize)); 00050 } 00051 00052 void Voxelgrid::hashAdd(int16_t x, int16_t y, int16_t z,bool filled, float a, float b){ 00053 voxel* temp = new voxel; 00054 temp->filled = filled; 00055 temp->x = x; 00056 temp->y = y; 00057 temp->z = z; 00058 temp->a = a; 00059 temp->b = b; 00060 int64_t hashPos = hashFunc(x,y,z,hashSize); 00061 00062 if(hashTable->at(hashPos) == nullptr){ 00063 hashTable->at(hashPos) = temp; 00064 numInTable++; 00065 }else{ 00066 numCollisions++; 00067 hashPos++; 00068 int numLinearRepeat = 0; 00069 hashPos = hashPos % hashSize; 00070 while(hashTable->at(hashPos) != nullptr && numLinearRepeat < 100000){ 00071 hashPos++; 00072 hashPos = hashPos % hashSize; 00073 numLinearRepeat++; 00074 } 00075 if (numLinearRepeat > 90000) { 00076 rehash(); 00077 hashAdd(x, y, z, filled, a, b); 00078 return; 00079 } 00080 numInTable++; 00081 hashTable->at(hashPos) = temp; 00082 } 00083 if((float)numCollisions/(float)numInTable > rehashTresh){ 00084 rehash(); 00085 } 00086 } 00087 00088 voxel* Voxelgrid::hashGet(int16_t x, int16_t y, int16_t z){ 00089 int64_t hashPos = hashFunc(x,y,z,hashSize); 00090 if(hashTable->at(hashPos) != nullptr){ 00091 while(hashTable->at(hashPos) != nullptr && !isEqualPoint(hashTable->at(hashPos),x,y,z)){ 00092 hashPos++; 00093 hashPos = hashPos % hashSize; 00094 } 00095 return hashTable->at(hashPos); 00096 }else{ 00097 return nullptr; 00098 } 00099 00100 } 00101 00102 00103 bool Voxelgrid::isEqualPoint(voxel* vox,short int x, short int y,short int z){ 00104 return (vox->x == x && vox->y == y && vox->z == z); 00105 } 00106 00107 00108 void Voxelgrid::hashInit() { 00109 this->hashTable = new std::vector<voxel*>((int)hashSize, nullptr); 00110 } 00111 00112 00113 neighs* Voxelgrid::getNeighbourhoodHash(int16_t x, int16_t y, int16_t z) { 00114 00115 neighs* neigh = new neighs(); 00116 for (size_t i = 0; i < 27; i++) 00117 { 00118 neigh->voxs[i] = hashGet(x + xoff[i],y+yoff[i],z+zoff[i]); 00119 } 00120 00121 return neigh; 00122 00123 } 00124 00125 00126 neighs* Voxelgrid::getNeighbourhood(int16_t x, int16_t y, int16_t z) { 00127 00128 neighs* neigh = new neighs(); 00129 for (size_t i = 0; i < 27; i++) 00130 { 00131 neigh->voxs[i] = getVoxel(x + xoff[i], y + yoff[i], z + zoff[i]); 00132 } 00133 00134 return neigh; 00135 00136 } 00137 00138 00139 00140 /* ----------------------------------------------------------------- 00141 Voxelgrid - Create the initial vector strutcture. 00142 */ 00143 00144 Voxelgrid::Voxelgrid(DataHandler* dataHandler,int64_t hashSize){ 00145 this->hashSize = hashSize; 00146 this->rehashTresh = 0.75; 00147 this->numInTable = 0; 00148 this->numCollisions = 0; 00149 this->voxels = new std::vector<std::vector<std::vector<voxel*>*>*>; 00150 this->datahandler = dataHandler; 00151 this->width = dataHandler->getDataWidth(); 00152 this->height = dataHandler->getDataHeight(); 00153 this->waterHeight = new std::vector<GLint>(width*height, -1); 00154 00155 int i = 0; 00156 for (int x = -1; x < 2; x++) 00157 { 00158 for (int y = -1; y < 2; y++) 00159 { 00160 for (int z = -1; z < 2; z++) 00161 { 00162 xoff[i] = x; 00163 yoff[i] = y; 00164 zoff[i] = z; 00165 i++; 00166 } 00167 } 00168 } 00169 } 00170 00171 00172 /* ----------------------------------------------------------------- 00173 Voxelgrid - Destructor, ensure destruction of all pointer structures 00174 */ 00175 00176 Voxelgrid::~Voxelgrid(){ 00177 for (GLuint x = 0; x < voxels->size(); x++) { 00178 if(voxels->at(x) != nullptr){ 00179 for (GLuint y = 0; y < voxels->at(x)->size(); y++) 00180 { 00181 if(voxels->at(x)->at(y) != nullptr){ 00182 for (GLuint z = 0; z < voxels->at(x)->at(y)->size(); z++) 00183 { 00184 if( voxels->at(x)->at(y)->at(z) != nullptr){ 00185 delete voxels->at(x)->at(y)->at(z); 00186 } 00187 } 00188 delete voxels->at(x)->at(y); 00189 } 00190 } 00191 delete voxels->at(x); 00192 } 00193 } 00194 delete voxels; 00195 delete voxelPositions; 00196 } 00197 00198 00199 00200 /* ----------------------------------------------------------------- 00201 setVoxel take a x,y,z coordinate where the voxel will be created (or modified) 00202 with the values ax, bx. 00203 */ 00204 00205 void Voxelgrid::setVoxel(int16_t x, int16_t y, int16_t z, bool filledx, float ax, float bx) 00206 { 00207 GLuint xorig = x; 00208 GLuint yorig = y; 00209 GLuint zorig = z; 00210 00211 setHeight(xorig, yorig, zorig); 00212 00213 x += 10; 00214 y += 10; 00215 z += 10; 00216 00217 00218 00219 //if x is not in table. Create y and z tables, resize x, and 00220 //point to children (y,z); 00221 if(voxels->size() < (unsigned int)x+1){ 00222 std::vector<voxel*>* tempZ = new std::vector<voxel*>(z+1); 00223 std::vector<std::vector<voxel*>*>* tempY = new std::vector<std::vector<voxel*>*>(y+1); 00224 voxels->resize(x+1,nullptr); 00225 (*voxels)[x] = tempY; 00226 (*(*voxels)[x])[y] = tempZ; 00227 00228 } 00229 //if y is not in table. Create z table, resize y, and 00230 //point to childtable z; Note that existence of y table is 00231 //managed by the first part of the if-statement 00232 else if((*voxels)[x] != nullptr && (*voxels)[x]->size() < (unsigned int)y+1){ 00233 00234 std::vector<voxel*>* tempZ = new std::vector<voxel*>(z+1); 00235 (*voxels)[x]->resize(y+1,nullptr); 00236 (*(*voxels)[x])[y] = tempZ; 00237 00238 } 00239 //if z is not large enough resize. Note that existence of z table is 00240 //managed by the first two parts of the if-statement 00241 else if((*voxels)[x] != nullptr && (*(*voxels)[x])[y] != nullptr && (*(*voxels)[x])[y]->size() < (unsigned int)z+1){ 00242 (*(*voxels)[x])[y]->resize(z+1,nullptr); 00243 00244 } 00245 00246 //If x is large enough but does not contain a table at position x 00247 //create and insert relevant tables. 00248 if((*voxels)[x] == nullptr){ 00249 std::vector<voxel*>* tempZ = new std::vector<voxel*>(z+1); 00250 std::vector<std::vector<voxel*>*>* tempY = new std::vector<std::vector<voxel*>*>(y+1); 00251 (*voxels)[x] = tempY; 00252 (*(*voxels)[x])[y] = tempZ; 00253 } 00254 //If y is large enough but does not contain a table at position y 00255 //create and insert relevant tables. 00256 else if((*(*voxels)[x])[y] == nullptr){ 00257 std::vector<voxel*>* tempZ = new std::vector<voxel*>(z+1); 00258 (*(*voxels)[x])[y] = tempZ; 00259 } 00260 //If there is already a voxel at position x,y,z, delete this in 00261 //preperation for new insertion. 00262 else if((*(*(*voxels)[x])[y])[z] != nullptr){ 00263 delete (*(*(*voxels)[x])[y])[z]; 00264 } 00265 00266 //create and insert the new voxel. 00267 voxel* temp = new voxel; 00268 temp->filled = filledx; 00269 temp->a = ax; 00270 temp->b = bx; 00271 temp->x = xorig; 00272 temp->y = yorig; 00273 temp->z = zorig; 00274 (*(*(*voxels)[x])[y])[z] = temp; 00275 00276 } 00277 00278 /* ----------------------------------------------------------------- 00279 Get voxel at x,y,z. This function returns a pointer to the struct. 00280 If no voxel is present it returns a nullptr. 00281 */ 00282 00283 voxel* Voxelgrid::getVoxel(int16_t x, int16_t y, int16_t z) 00284 { 00285 00286 x += 10; 00287 y += 10; 00288 z += 10; 00289 00290 00291 //std::cout << "In getVoxel, size of vector voxels is: " << voxels->size() << std::endl; 00292 00293 //std::cout << "Voxels at x is empty" << std::endl; 00294 00295 //ensure table existance and table size, if either fails return nullptr. 00296 if (voxels->size() < (unsigned int)x + 1 || (*voxels)[x] == nullptr) { 00297 //std::cout << "In first if in get_Voxel" << std::endl; 00298 return nullptr; 00299 } 00300 //ensure table existance and table size, if either fails return nullptr. 00301 else if ((*voxels)[x]->size() < (unsigned int)y + 1 || (*(*voxels)[x])[y] == nullptr) { 00302 //std::cout << "In second if in get_Voxel" << std::endl; 00303 return nullptr; 00304 } 00305 //ensure table existance and table size, if either fails return nullptr. 00306 else if ((*(*voxels)[x])[y]->size() < (unsigned int)z + 1 || (*(*(*voxels)[x])[y])[z] == nullptr) { 00307 return nullptr; 00308 } 00309 00310 //Existance is ensured, return pointer at location x,y,z 00311 //std::cout << "Just before returning voxel in get_Voxel" << std::endl; 00312 return (voxel*)(*(*(*voxels)[x])[y])[z]; 00313 } 00314 00315 00316 /* FloodFill function creates a vector queue. Tests if the first voxel coordinates are above land, if so its coordinates are added to the queue 00317 vector and the struct for the voxel is creatd using setVoxel. While there are still coordinates in the queue, the neighboring voxels' 00318 coordinates relative to the current coordinates (last position in queue) are added to the queue and a corresponding struct is created with setVoxel. 00319 As each element in the queue is processed the voxels beneath the current voxel are filled. 00320 */ 00321 00322 void Voxelgrid::FloodFill(int x, int z, int height, bool fillDown){ 00323 00324 std::vector<std::vector<int>> queue; 00325 std::cout << x << std::endl; 00326 00327 if (datahandler->giveHeight((GLfloat)x, (GLfloat)z) < (GLfloat)height) { 00328 queue.push_back({x, z}); 00329 setVoxel(x, height, z, true, 0, 0); 00330 } 00331 00332 int temp_x, temp_z; 00333 int height_test; 00334 int terrain_height; 00335 00336 /* While queue is not empty, keep processing queue from back to front. 00337 */ 00338 while(queue.size() > 0){ 00339 00340 temp_x = queue.back().at(0); 00341 temp_z = queue.back().at(1); 00342 00343 queue.pop_back(); 00344 00345 /* Fill voxels beneath current voxel 00346 */ 00347 height_test = height; 00348 terrain_height = (int)datahandler->giveHeight((GLfloat)temp_x, (GLfloat)temp_z); 00349 00350 if(fillDown){ 00351 while(height_test > terrain_height && height_test >= 0){ 00352 00353 setVoxel(temp_x, height_test, temp_z, true, 0, 0); 00354 height_test--; 00355 } 00356 } 00357 00358 00359 00360 /* Checking voxels adjacent to current voxel and adding their coordinates to the queue if they are inside the terrain, 00361 above land and have not yet been added to the queue. Before coordinates are added the struct is created. Struct existance 00362 (!= nullptr) thus equivalent to voxel added to cue as used in if-statement. 00363 */ 00364 // temp_x + 1 < datahandler->getDataWidth() -1 dye to giveHeight not able to give height and edge!!! 00365 if (temp_x + 1 < datahandler->getDataWidth() - 1 && datahandler->giveHeight((GLfloat)(temp_x + 1), (GLfloat)temp_z) < height && getVoxel(temp_x + 1, height, temp_z) == nullptr) { 00366 setVoxel(temp_x + 1, height, temp_z, true, 0, 0); 00367 queue.push_back({ temp_x + 1,temp_z }); 00368 } 00369 00370 00371 if (temp_x - 1 > 0 && datahandler->giveHeight((GLfloat)(temp_x - 1), (GLfloat)temp_z) < height && getVoxel(temp_x - 1, height, temp_z) == nullptr) { 00372 setVoxel(temp_x - 1, height, temp_z, true, 0, 0); 00373 queue.push_back({ temp_x - 1, temp_z }); 00374 } 00375 if (temp_z + 1 < datahandler->getDataHeight() - 1 && datahandler->giveHeight((GLfloat)temp_x, (GLfloat)(temp_z + 1)) < height && getVoxel(temp_x, height, temp_z + 1) == nullptr) { 00376 setVoxel(temp_x, height, temp_z + 1, true, 0, 0); 00377 queue.push_back({ temp_x,temp_z + 1 }); 00378 } 00379 00380 if (temp_z - 1 > 0 && datahandler->giveHeight((GLfloat)temp_x, (GLfloat)(temp_z - 1)) < height && getVoxel(temp_x, height, temp_z - 1) == nullptr) { 00381 setVoxel(temp_x, height, temp_z - 1, true, 0, 0); 00382 queue.push_back({ temp_x, temp_z - 1 }); 00383 } 00384 } 00385 00386 } 00387 00388 std::vector<GLuint> *Voxelgrid::getVoxelPositions() { 00389 std::vector<GLuint> *positions = new std::vector<GLuint>; 00390 GLint tempH = 0; 00391 for (GLuint x = 0; x < width; x++) 00392 { 00393 for (GLuint z = 0; z < height; z++) 00394 { 00395 tempH = getHeight(x, z); 00396 if (tempH != -1) { 00397 positions->push_back(x); 00398 positions->push_back((GLuint)tempH); 00399 positions->push_back(z); 00400 } 00401 00402 } 00403 } 00404 00405 return positions; 00406 } 00407 00408 void Voxelgrid::initDraw() { 00409 voxelPositions = getVoxelPositions(); 00410 numVoxels = (GLuint)voxelPositions->size() / 3; 00411 voxelShader = loadShadersG("src/shaders/simplevoxels.vert", "src/shaders/simplevoxels.frag", "src/shaders/simplevoxels.geom"); 00412 00413 glGenBuffers(1, &voxelBuffer); 00414 glBindBuffer(GL_ARRAY_BUFFER, voxelBuffer); 00415 glBufferData(GL_ARRAY_BUFFER, numVoxels * 3 * sizeof(GLuint), voxelPositions->data(), GL_STATIC_COPY); 00416 glBindBuffer(GL_ARRAY_BUFFER, 0); 00417 00418 glBindBuffer(GL_ARRAY_BUFFER, voxelBuffer); 00419 glGenVertexArrays(1, &voxelVAO); 00420 glBindVertexArray(voxelVAO); 00421 00422 GLuint posAttrib = glGetAttribLocation(voxelShader, "posValue"); 00423 glEnableVertexAttribArray(posAttrib); 00424 glVertexAttribPointer(posAttrib, 3, GL_UNSIGNED_INT, GL_FALSE, 0, 0); 00425 00426 glBindVertexArray(0); 00427 glBindBuffer(GL_ARRAY_BUFFER, 0); 00428 } 00429 00430 void Voxelgrid::updateVoxelrender() { 00431 delete voxelPositions; 00432 voxelPositions = getVoxelPositions(); 00433 numVoxels = (GLuint)voxelPositions->size() / 3; 00434 00435 glBindBuffer(GL_ARRAY_BUFFER, voxelBuffer); 00436 glBufferData(GL_ARRAY_BUFFER, numVoxels * 3 * sizeof(GLuint), voxelPositions->data(), GL_STATIC_COPY); 00437 glBindBuffer(GL_ARRAY_BUFFER, 0); 00438 } 00439 00440 void Voxelgrid::drawVoxels(glm::mat4 projectionMatrix, glm::mat4 viewMatrix) { 00441 glUseProgram(voxelShader); 00442 glBindBuffer(GL_ARRAY_BUFFER, voxelBuffer); 00443 glBindVertexArray(voxelVAO); 00444 glUniformMatrix4fv(glGetUniformLocation(voxelShader, "VTPMatrix"), 1, GL_FALSE, glm::value_ptr(projectionMatrix)); 00445 glUniformMatrix4fv(glGetUniformLocation(voxelShader, "WTVMatrix"), 1, GL_FALSE, glm::value_ptr(viewMatrix)); 00446 00447 if (numVoxels > 0) { 00448 glDrawArrays(GL_POINTS, 0, numVoxels); 00449 } 00450 00451 glBindVertexArray(0); 00452 glBindBuffer(GL_ARRAY_BUFFER, 0); 00453 00454 printError("Voxel Draw Billboards"); 00455 } 00456 00457 void Voxelgrid::setHeight(int16_t x, int16_t y, int16_t z) { 00458 GLint curHeight = getHeight(x, z); 00459 if( y > curHeight ){ 00460 waterHeight->at(x + z*width) = y; 00461 } 00462 } 00463 00464 GLint Voxelgrid::getHeight(int16_t x, int16_t z) { 00465 00466 return waterHeight->at(x + z*width); 00467 00468 } 00469 00470 std::vector<GLint>* Voxelgrid::getHeightMap() { 00471 return waterHeight; 00472 }