Waterflow
Visualize water in terrain
src/heightField.cpp
Go to the documentation of this file.
00001 
00002 
00003 
00004 #include "heightField.h"
00005 #include "GL_utilities.h"
00006 #include "Utilities.h"
00007 #include <algorithm>
00008 #include <stdio.h>
00009 #include <valarray>
00010 #include <inttypes.h>
00011 
00012 HeightField::HeightField(DataHandler *t, std::vector<Flood_Fill_data*> FFDataIn, std::vector<FlowSource*> FlowsourcesIN) {
00013     terr = t;
00014     texWidth = t->getDataWidth();
00015     texHeight = t->getDataHeight();
00016     totTime = 0.0f; 
00017     flood = FFDataIn;
00018     xmlFlow = FlowsourcesIN;
00019 
00020 }
00021 
00022 void HeightField::floodFill(float* u, int x, int z, float height) {
00023 
00024     std::vector<std::vector<int>> queue;
00025 
00026     if (terr->getData()[x + texWidth*z] < height) {
00027         queue.push_back({ x, z });
00028     }
00029 
00030 
00031     int temp_x, temp_z;
00032 
00033     /* While queue is not empty, keep processing queue from back to front.
00034     */
00035     while (queue.size() > 0) {
00036 
00037         temp_x = queue.back().at(0);
00038         temp_z = queue.back().at(1);
00039 
00040         queue.pop_back();
00041 
00042         // create the four neighbours clamp to ensure we don't check outside the map.   
00043         int temp_x_plus = clip(temp_x + 1, 0, texWidth - 1);
00044         int temp_x_min = clip(temp_x - 1, 0, texWidth - 1);
00045         int temp_z_plus = clip(temp_z + 1, 0, texHeight - 1);
00046         int temp_z_min = clip(temp_z - 1, 0, texHeight - 1);
00047         int offset0 = temp_x + temp_z*texWidth;
00048         if (u[offset0] != height && terr->getData()[offset0] < height) {
00049 
00050             //set height at offset0
00051             u[offset0] = height;
00052             //add the four neighbours
00053             queue.push_back({ temp_x_plus,temp_z_min });
00054             queue.push_back({ temp_x_plus,temp_z_plus });
00055             queue.push_back({ temp_x_min,temp_z_min });
00056             queue.push_back({ temp_x_min,temp_z_plus });
00057         }
00058     }
00059 }
00060 
00061 
00062 
00063 void HeightField::initTest() {
00064     for (int i = 0; i < width; i++) {
00065         for (int j = 0; j < height; j++) {
00066             u[i][j] = terr->giveHeight((GLfloat)i*samp, (GLfloat)j*samp) - 2.0f;
00067             v[i][j] = 0;
00068         }
00069     }
00070     for (int j = 20; j < 30; j++) {
00071         for (int i = 20; i < 30; i++) {
00072             u[i][j] = u[i][j] + 5;
00073         }
00074     }
00075 }
00076 
00077 int HeightField::clip(int n, int lower, int upper) {
00078     return std::max(lower, std::min(n, upper));
00079 }
00080 
00081 GLfloat HeightField::clipf(GLfloat n, GLfloat lower, GLfloat upper) {
00082     return std::max(lower, std::min(n, upper));
00083 }
00084 
00085 GLfloat HeightField::getHeight(int i, int j, GLfloat ourHeight) {
00086     i = clip(i, 0, width - 1);
00087     j = clip(j, 0, height - 1);
00088     if (u[i][j] - terr->giveHeight((GLfloat)i*samp, (GLfloat)j*samp) < 0.0f) {
00089         return ourHeight;
00090     }
00091     return u[i][j];
00092 
00093 }
00094 
00095 void HeightField::updateSim(GLfloat dt) {
00096 
00097     GLfloat c2 = 1;
00098     GLfloat max_c = (1.0f / dt);
00099     if (c2 > max_c) {
00100         printf("C2 too large/ dt too large.");
00101     }
00102 
00103     GLfloat h2 = 4;
00104     dt = dt*4.9f;
00105     for (int i = 0; i < width; i++) {
00106         for (int j = 0; j < height; j++) {
00107 
00108             GLfloat height_east = getHeight((i + 1), j, u[i][j]);
00109             GLfloat height_west = getHeight((i - 1), j, u[i][j]);
00110             GLfloat height_south = getHeight(i, (j - 1), u[i][j]);
00111             GLfloat height_north = getHeight(i, (j + 1), u[i][j]);
00112 
00113             GLfloat f = c2*(height_west + height_east + height_south + height_north - 4 * u[i][j]) / h2;
00114 
00115             f = clipf(f, -0.1f, 0.1f);
00116             v[i][j] = v[i][j] + f*dt;
00117             unew[i][j] = u[i][j] + v[i][j] * dt;
00118             v[i][j] *= 0.995f;
00119 
00120         }
00121     }
00122 
00123 
00124     memcpy(u, unew, sizeof(unew));
00125 }
00126 
00127 void HeightField::render() {
00128     updateVoxelrender();
00129 }
00130 
00131 std::vector<GLuint> *HeightField::getVoxelPositions() {
00132     std::vector<GLuint> *positions = new std::vector<GLuint>;
00133 
00134     for (int i = 0; i < width; i++) {
00135         for (int j = 0; j < height; j++) {
00136             if (u[i][j] - 1 > terr->giveHeight((GLfloat)i, (GLfloat)j)) {
00137                 positions->push_back(i*samp);
00138                 positions->push_back((GLuint)round(u[i][j] - 1.0f));
00139                 positions->push_back(j*samp);
00140             }
00141         }
00142     }
00143     return positions;
00144 }
00145 
00146 void HeightField::initDraw() {
00147     voxelPositions = getVoxelPositions();
00148     numVoxels = (GLuint)voxelPositions->size() / 3;
00149     voxelShader = loadShadersG("src/shaders/simplevoxels.vert", "src/shaders/simplevoxels.frag", "src/shaders/simplevoxels.geom");
00150 
00151     glGenBuffers(1, &voxelBuffer);
00152     glBindBuffer(GL_ARRAY_BUFFER, voxelBuffer);
00153     glBufferData(GL_ARRAY_BUFFER, numVoxels * 3 * sizeof(GLuint), voxelPositions->data(), GL_STATIC_COPY);
00154     glBindBuffer(GL_ARRAY_BUFFER, 0);
00155 
00156     glBindBuffer(GL_ARRAY_BUFFER, voxelBuffer);
00157     glGenVertexArrays(1, &voxelVAO);
00158     glBindVertexArray(voxelVAO);
00159 
00160     GLuint posAttrib = glGetAttribLocation(voxelShader, "posValue");
00161     glEnableVertexAttribArray(posAttrib);
00162     glVertexAttribPointer(posAttrib, 3, GL_UNSIGNED_INT, GL_FALSE, 0, 0);
00163 
00164     glBindVertexArray(0);
00165     glBindBuffer(GL_ARRAY_BUFFER, 0);
00166 }
00167 
00168 void HeightField::updateVoxelrender() {
00169     voxelPositions->clear();
00170     delete voxelPositions;
00171     voxelPositions = getVoxelPositions();
00172     numVoxels = (GLuint)voxelPositions->size() / 3;
00173 
00174     glBindBuffer(GL_ARRAY_BUFFER, voxelBuffer);
00175     glBufferData(GL_ARRAY_BUFFER, numVoxels * 3 * sizeof(GLuint), voxelPositions->data(), GL_STATIC_COPY);
00176     glBindBuffer(GL_ARRAY_BUFFER, 0);
00177 }
00178 
00179 void HeightField::drawVoxels(glm::mat4 projectionMatrix, glm::mat4 viewMatrix) {
00180     glUseProgram(voxelShader);
00181     glBindBuffer(GL_ARRAY_BUFFER, voxelBuffer);
00182     glBindVertexArray(voxelVAO);
00183     glUniformMatrix4fv(glGetUniformLocation(voxelShader, "VTPMatrix"), 1, GL_FALSE, glm::value_ptr(projectionMatrix));
00184     glUniformMatrix4fv(glGetUniformLocation(voxelShader, "WTVMatrix"), 1, GL_FALSE, glm::value_ptr(viewMatrix));
00185 
00186     if (numVoxels > 0) {
00187         glDrawArrays(GL_POINTS, 0, numVoxels);
00188     }
00189 
00190     glBindVertexArray(0);
00191     glBindBuffer(GL_ARRAY_BUFFER, 0);
00192 
00193     printError("Voxel Draw Billboards");
00194 }
00195 
00196 
00197 void HeightField::initGPU(float** heightArray, float** velocityArray) {
00198 
00199     
00200     float* u = (*heightArray != nullptr) ? *heightArray : new float[texWidth*texHeight];
00201     float* v = (*velocityArray != nullptr) ? *velocityArray : new float[texWidth*texHeight];
00202     float* f = new float[texWidth*texHeight];
00203     
00204     if(*heightArray == nullptr)
00205         std::fill_n(u, texWidth*texHeight, 0.0f);
00206     
00207     if(*velocityArray == nullptr)
00208         std::fill_n(v, texWidth*texHeight, 0.0f);
00209     
00210     
00211     std::fill_n(f, texWidth*texHeight, 0.0f);
00212 
00213     initFloodFill(u);
00214 
00215     std::valarray<float> fvalarray(terr->getData(), texWidth*texHeight);
00216     fvalarray = fvalarray - 0.0001f;
00217     
00218     fieldProgram = compileComputeShader("src/shaders/fieldShader.comp"); 
00219     addProgram = compileComputeShader("src/shaders/addFlowShader.comp");
00220 
00221     //create buffers
00222     glGenBuffers(5, fieldBuffers);
00223     GLint numData = terr->getDataWidth()*terr->getDataHeight();
00224 
00225     glBindBuffer(GL_SHADER_STORAGE_BUFFER, fieldBuffers[0]);
00226     glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat) * 1 * numData, u, GL_STATIC_DRAW);
00227     glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
00228 
00229     glBindBuffer(GL_SHADER_STORAGE_BUFFER, fieldBuffers[1]);
00230     glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat) * 1 * numData, u, GL_STATIC_DRAW);
00231     glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
00232 
00233     glBindBuffer(GL_SHADER_STORAGE_BUFFER, fieldBuffers[2]);
00234     glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat) * 1 * numData, v, GL_STATIC_DRAW);
00235     glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
00236 
00237     glBindBuffer(GL_SHADER_STORAGE_BUFFER, fieldBuffers[3]);
00238     glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat) * 1 * numData, &fvalarray[0], GL_STATIC_DRAW);
00239     glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
00240 
00241     glBindBuffer(GL_SHADER_STORAGE_BUFFER, fieldBuffers[4]);
00242     glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat) * 1 * numData, f, GL_STATIC_DRAW);
00243     glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
00244 
00245     printError("init Compute Error");
00246     printProgramInfoLog(fieldProgram, "field Init", NULL, NULL, NULL, NULL);
00247 
00248     glBindBuffer(GL_SHADER_STORAGE_BUFFER, fieldBuffers[0]);
00249     glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLfloat)*texWidth*texHeight, u);
00250     glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
00251 
00252     if(*heightArray == nullptr)
00253         delete u;
00254     if(*velocityArray == nullptr)
00255         delete v;
00256     
00257     delete f;
00258 
00259 }
00260 
00261 void HeightField::initFloodFill(float* u) {
00262     for (unsigned int i = 0; i < flood.size(); i++) {
00263         floodFill(u, flood.at(i)->x, flood.at(i)->z, flood.at(i)->height);
00264     }
00265 }
00266 
00267 void HeightField::runSimGPU(GLfloat dt) {
00268     totTime += dt;
00269     int numPing = 20;
00270     GLint numData = terr->getDataWidth()*terr->getDataHeight();
00271 
00272     if (flowChange(xmlFlow, dt)) {
00273         GLfloat* f = new float[texWidth*texHeight];
00274         std::fill_n(f, texWidth*texHeight, 0.0f);
00275         for (unsigned int i = 0; i < xmlFlow.size(); i++) {
00276             std::vector<int> flowPos = xmlFlow.at(i)->getPosition();
00277             f[flowPos[0] + flowPos[2] * texWidth] = xmlFlow.at(i)->currPres;
00278             printf("Pressure %f \n", xmlFlow.at(i)->currPres);
00279         }
00280         glBindBuffer(GL_SHADER_STORAGE_BUFFER, fieldBuffers[4]);
00281         glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat) * 1 * numData, f, GL_STATIC_DRAW);
00282         glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
00283 
00284         delete f;
00285     }
00286 
00287 
00288     glUseProgram(fieldProgram);
00289     glUniform2i(glGetUniformLocation(fieldProgram, "size"), terr->getDataWidth(), terr->getDataHeight());
00290     glUniform1f(glGetUniformLocation(fieldProgram, "dt"), dt);
00291 
00292     glUseProgram(addProgram);
00293     glUniform2i(glGetUniformLocation(addProgram, "size"), terr->getDataWidth(), terr->getDataHeight());
00294 
00295     glBindBuffersBase(GL_SHADER_STORAGE_BUFFER, 4, 5, fieldBuffers);
00296 
00297     glUseProgram(addProgram);
00298     glDispatchCompute((GLuint)ceil((GLfloat)terr->getDataWidth() / 16.0f), (GLuint)ceil((GLfloat)terr->getDataHeight() / 16.0f), 1);
00299 
00300 
00301     for (int i = 0; i < numPing; i++) {
00302 
00303         glBindBuffersBase(GL_SHADER_STORAGE_BUFFER, 4, 5, fieldBuffers);
00304 
00305 
00306         glUseProgram(fieldProgram);
00307         glDispatchCompute((GLuint)ceil((GLfloat)terr->getDataWidth() / 16.0f), (GLuint)ceil((GLfloat)terr->getDataHeight() / 16.0f), 1);
00308         std::swap(fieldBuffers[0], fieldBuffers[1]);
00309     }
00310 
00311     printError("run Sim GPU");
00312 }
00313 
00314 
00315 void HeightField::measureVolume() {
00316 
00317     float* u = new float[texWidth*texHeight];
00318 
00319     glBindBuffer(GL_SHADER_STORAGE_BUFFER, fieldBuffers[0]);
00320     glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, texWidth*texHeight*sizeof(float), u);
00321     glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
00322 
00323     std::valarray<float> myvalarray(u, texWidth*texHeight);
00324     float vol1 = myvalarray.sum();
00325 
00326 
00327     std::cout << "Volume difference is: " << vol1 - vol0 << std::endl;
00328     myvalarray.resize(0);
00329     delete u;
00330 
00331 }
00332 
00333 
00334 void HeightField::saveData(float** u, float** v){
00335     *u = (*u != nullptr) ? *u : (float*)malloc(texWidth*texHeight*sizeof(float));       
00336     *v = (*v != nullptr) ? *v : (float*)malloc(texWidth*texHeight*sizeof(float));
00337 
00338     
00339     glBindBuffer(GL_SHADER_STORAGE_BUFFER, fieldBuffers[0]);
00340     glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, texWidth*texHeight*sizeof(float), *u);
00341     glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
00342     
00343     
00344     glBindBuffer(GL_SHADER_STORAGE_BUFFER, fieldBuffers[2]);
00345     glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, texWidth*texHeight*sizeof(float), *v);
00346     glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
00347     
00348 }
00349 
00350 
00351 
00352 
00353 
00354 
00355 
00356 
00357 
00358 
00359 
 All Classes Files Functions Variables Enumerations