Waterflow
Visualize water in terrain
|
00001 00002 00003 #include <chrono> 00004 #include "readData.h" 00005 00006 #include "Utilities.h" 00007 #include "GL_utilities.h" 00008 00009 #include "glm.hpp" 00010 00011 #include <iostream> 00012 00013 // ===== Constructors and destructors 00014 00015 DataHandler::DataHandler(const char* inputfile) { 00016 readdata = new mapdata(); 00017 00018 std::cout << "Reading DEM data from: " << inputfile << "..."; 00019 readDEM(inputfile); 00020 std::cout << " done!" << std::endl; 00021 00022 std::cout << "Performing normalized convolution..."; 00023 normConvCompute(); 00024 std::cout << " done!" << std::endl; 00025 } 00026 00027 DataHandler::~DataHandler() { 00028 delete readdata; 00029 } 00030 00031 // ===== Getters ===== 00032 00033 float DataHandler::getCoord(int col, int row) { 00034 int index; 00035 float retdata = 0; 00036 00037 if (readdata != NULL) { 00038 00039 if (col < readdata->ncols && row < readdata->nrows) { 00040 index = col + row * readdata->ncols; 00041 } else { 00042 std::cerr << "Input does not exist in data. Col: " << col << " Row: " << row << std::endl; 00043 index = 0; 00044 } 00045 retdata = readdata->data[index]; 00046 } else { 00047 std::cerr << "No mapdata exists." << std::endl; 00048 } 00049 00050 return retdata; 00051 } 00052 00053 GLfloat DataHandler::giveHeight(GLfloat x, GLfloat z) // Returns the height of a height map. 00054 { 00055 int width = getDataWidth(); 00056 int height = getDataHeight(); 00057 00058 int vertX1 = (int)floor(x); 00059 int vertZ1 = (int)floor(z); 00060 00061 int vertX2 = (int)floor(x) + 1; 00062 int vertZ2 = (int)floor(z) + 1; 00063 00064 int vertX3 = 0; 00065 int vertZ3 = 0; 00066 00067 GLfloat yheight = 0; 00068 00069 if ((vertX1 >= 0) && (vertZ1 >= 0) && (vertX2 < width) && (vertZ2 < height)) { 00070 00071 GLfloat dist1 = vertX1 - x; 00072 GLfloat dist2 = vertZ1 - z; 00073 00074 if (dist1 > dist2) { 00075 vertX3 = vertX1; 00076 vertZ3 = vertZ1 + 1; 00077 } else { 00078 vertX3 = vertX1 + 1; 00079 vertZ3 = vertZ1; 00080 } 00081 GLfloat vertY1 = getData()[(vertX1 + vertZ1 * width)]; 00082 GLfloat vertY2 = getData()[(vertX2 + vertZ2 * width)]; 00083 GLfloat vertY3 = getData()[(vertX3 + vertZ3 * width)]; 00084 00085 glm::vec3 p1 = { (float)vertX1 / (float)width, vertY1, (float)vertZ1 / (float)height }; 00086 glm::vec3 p2 = { (float)vertX2 / (float)width, vertY2, (float)vertZ2 / (float)height }; 00087 glm::vec3 p3 = { (float)vertX3 / (float)width, vertY3, (float)vertZ3 / (float)height }; 00088 00089 glm::vec3 planeNormal = { 0, 0, 0 }; 00090 00091 // This if/else might not be making any difference whatsoever. 00092 if (dist1 > dist2) { 00093 planeNormal = glm::normalize(glm::cross(p2 - p1, p3 - p1)); 00094 } else { 00095 planeNormal = glm::normalize(glm::cross(p3 - p1, p2 - p1)); 00096 } 00097 00098 GLfloat D; 00099 D = glm::dot(planeNormal, p1); 00100 00101 yheight = (D - planeNormal.x*x / width - planeNormal.z*z / height) / planeNormal.y; 00102 } 00103 return yheight; 00104 } 00105 00106 // ===== Actual functions ===== 00107 00108 void DataHandler::readDEM(const char* inputfile) { 00109 char* buffer = readFile(inputfile); 00110 char* currentStr = buffer; 00111 int readChars = 0; 00112 00113 if (buffer != NULL) { 00114 if (sscanf(currentStr, "%*s %i %n", &readdata->ncols, &readChars) != 1) std::cout << "Reading DEM error!" << std::endl; 00115 currentStr += readChars; 00116 if (sscanf(currentStr, "%*s %i %n", &readdata->nrows, &readChars) != 1) std::cout << "Reading DEM error!" << std::endl; 00117 currentStr += readChars; 00118 if (sscanf(currentStr, "%*s %f %n", &readdata->xllcorner, &readChars) != 1) std::cout << "Reading DEM error!" << std::endl; 00119 currentStr += readChars; 00120 if (sscanf(currentStr, "%*s %f %n", &readdata->yllcorner, &readChars) != 1) std::cout << "Reading DEM error!" << std::endl; 00121 currentStr += readChars; 00122 if (sscanf(currentStr, "%*s %f %n", &readdata->cellsize, &readChars) != 1) std::cout << "Reading DEM error!" << std::endl; 00123 currentStr += readChars; 00124 if (sscanf(currentStr, "%*s %f %n", &readdata->NODATA_value, &readChars) != 1) std::cout << "Reading DEM error!" << std::endl; 00125 currentStr += readChars; 00126 00127 readdata->max_value = readdata->NODATA_value; 00128 readdata->min_value = FLT_MAX; 00129 00130 readdata->nelem = readdata->ncols * readdata->nrows; 00131 readdata->data.resize(getElem()); 00132 00133 float incoord = 0; 00134 00135 for (int i = 0; i < getElem(); i++) { 00136 incoord = myStrtof(currentStr, ¤tStr); 00137 00138 if (incoord > readdata->max_value) { 00139 readdata->max_value = incoord; 00140 } 00141 if (incoord > readdata->NODATA_value + 1.0f && incoord < readdata->min_value) { 00142 readdata->min_value = incoord; 00143 } 00144 if (incoord == readdata->NODATA_value) { 00145 incoord = -1.0f; 00146 } 00147 00148 readdata->data[i] = incoord; 00149 } 00150 terrainScale = readdata->max_value - readdata->min_value; 00151 00152 free(buffer); 00153 } else { 00154 std::cerr << "Could not read file: " << inputfile << std::endl; 00155 } 00156 00157 for (int i = 0; i < getElem(); i++) { 00158 if (readdata->data[i] > 0.0f) { 00159 readdata->data[i] -= readdata->min_value; 00160 } 00161 } 00162 00163 } 00164 00165 void DataHandler::normConvCompute() { 00166 00167 GLuint normConvProgram = compileComputeShader("src/shaders/normConv.comp"); 00168 00169 glGenBuffers(1, &terrainBufferID); 00170 00171 GLuint normBuffers[3]; 00172 glGenBuffers(3, normBuffers); 00173 00174 GLint numData = getElem(); 00175 GLuint reset = 0; 00176 // read buffer height 00177 glBindBuffer(GL_SHADER_STORAGE_BUFFER, normBuffers[0]); //What data? getData() 00178 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat)*numData, getData(), GL_STATIC_DRAW); 00179 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); 00180 00181 // write buffer height 00182 glBindBuffer(GL_SHADER_STORAGE_BUFFER, normBuffers[1]); 00183 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat)*numData, NULL, GL_STATIC_DRAW); 00184 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); 00185 00186 // Atomic counter for isNODATA 00187 glBindBuffer(GL_SHADER_STORAGE_BUFFER, normBuffers[2]); 00188 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint), &reset, GL_STATIC_DRAW); 00189 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); 00190 00191 printError("init NormConvCompute"); 00192 00193 glUseProgram(normConvProgram); 00194 glUniform2i(glGetUniformLocation(normConvProgram, "size"), getDataWidth(), getDataHeight()); 00195 00196 GLuint isNODATA = 1; 00197 while (isNODATA) { // Ping pong the normalized convolution until there are no more NODATA 00198 isNODATA = 0; 00199 00200 glBindBuffersBase(GL_SHADER_STORAGE_BUFFER, 0, 3, normBuffers); 00201 glDispatchCompute((GLuint)ceil((GLfloat)getDataWidth() / 16.0f), (GLuint)ceil((GLfloat)getDataHeight() / 16.0f), 1); 00202 00203 glBindBuffer(GL_SHADER_STORAGE_BUFFER, normBuffers[2]); 00204 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint), &isNODATA); 00205 glClearBufferData(GL_SHADER_STORAGE_BUFFER, GL_R32UI, GL_RED, GL_UNSIGNED_INT, &reset); 00206 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); 00207 00208 std::swap(normBuffers[0], normBuffers[1]); 00209 } 00210 00211 terrainBufferID = normBuffers[0]; 00212 00213 // Replace the data in readdata with data from GPU 00214 glBindBuffer(GL_SHADER_STORAGE_BUFFER, terrainBufferID); 00215 glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLfloat)*numData, getData()); 00216 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); 00217 00218 glDeleteBuffers(2, &normBuffers[1]); 00219 00220 printError("End NormConvCompute"); 00221 } 00222 00223 00224 00225 00226 00227 00228 00229 00230 00231 00232 00233 00234 00235 00236 00237 00238