Waterflow
Visualize water in terrain
|
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