float interpolate_tricubic_simple(float* tex, float3 coord, uint3 volumeExtent) { // transform the coordinate from [0,extent] to [-0.5, extent-0.5] const float3 coord_grid = coord - 0.5; float3 indexF = floor(coord_grid); const float3 fraction = coord_grid - indexF; int3 index = make_int3((int)indexF.x, (int)indexF.y, (int)indexF.z); //index = index + 0.5; //move from [-0.5, extent-0.5] to [0, extent] float result = 0.0; for (int z=-1; z <= 2; z++) //range [-1, 2] { float bsplineZ = bspline(z-fraction.z); int w = index.z + z; for (int y=-1; y <= 2; y++) { float bsplineYZ = bspline(y-fraction.y) * bsplineZ; int v = index.y + y; for (int x=-1; x <= 2; x++) { float bsplineXYZ = bspline(x-fraction.x) * bsplineYZ; int u = index.x + x; result += bsplineXYZ * tex3D(tex, u, v, w, volumeExtent); } } } return result; }
int main(void) { srand(time(NULL)); //Create init object Init init = Init(); //Initialize glfw init.glfw(4, 1); //Open a window GLFWwindow *window = init.window(400, 400); //Print window info init.printWindowInfo(window); //Make opened window current context glfwMakeContextCurrent(window); init.glew(); int width, height; glfwGetFramebufferSize(window, &width, &height); glViewport(0, 0, width, height); glEnable(GL_CULL_FACE); // Nvidia cards require a vertex array to cooperate. GLuint VertexArrayID; glGenVertexArrays(1, &VertexArrayID); glBindVertexArray(VertexArrayID); //Set up the initial state. unsigned int w = 32, h = 32, d = 32; State *prevState = new State(w, h, d); VelocityGrid *velocities = new VelocityGrid(w, h, d); prevState->setVelocityGrid(velocities); // init level set LevelSet *ls = factory::levelSet::ball(w, h, d); prevState->setLevelSet(ls); delete ls; // init simulator Simulator sim(*prevState, 0.1f); // BubbleMaxExporter bubbleExporter; // Dark black background glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //Load in shaders static ShaderProgram colorCubeProg("../vertShader.vert", "../colorCube.frag"); static ShaderProgram rayCasterProg("../vertShader.vert", "../rayCaster.frag"); static ShaderProgram bubbleProg("../bubbleVertShader.vert", "../bubbleFragShader.frag"); static const GLfloat vertexBufferData[] = { -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; static const GLuint triangleBufferData[] = { // xy plane (z = -1) 0, 1, 3, 3, 2, 0, // xz plane (y = -1) 0, 5, 1, 0, 4, 5, // yz plane (x = -1) 0, 2, 4, 2, 6, 4, // xy plane (z = 1) 4, 7, 5, 4, 6, 7, // xz plane (y = 1) 2, 7, 6, 2, 3, 7, // yz plane (x = 1) 1, 5, 3, 3, 5, 7 }; std::vector<GLfloat> g_bubble_buffer_data; //Create vertex buffer GLuint vertexbuffer; glGenBuffers(1, &vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vertexBufferData), vertexBufferData, GL_STATIC_DRAW); GLuint triangleBuffer; glGenBuffers(1, &triangleBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangleBuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(triangleBufferData), triangleBufferData, GL_STATIC_DRAW); // Create bubble buffer GLuint bubbleBuffer; glGenBuffers(1, &bubbleBuffer); // Create framebuffer FBO *framebuffer = new FBO(width, height); GLuint volumeTextureId; glGenTextures(1, &volumeTextureId); glBindTexture(GL_TEXTURE_3D, volumeTextureId); //Object which encapsulates a texture + The destruction of a texture. Texture3D tex3D(w, h, d); double lastTime = glfwGetTime(); int nbFrames = 0; float deltaT = 0.1; //First time step glfwSwapInterval(1); int i = 0; do { framebuffer->activate(); // common for both render passes. sim.step(deltaT); // deltaT = sim.getDeltaT(); glm::mat4 matrix = glm::mat4(1.0f); matrix = glm::translate(matrix, glm::vec3(0.0f, 0.0f, 2.0f)); matrix = glm::rotate(matrix, -3.1415926535f / 4.0f, glm::vec3(1.0f, 0.0f, 0.0f)); matrix = glm::rotate(matrix, 0.1415926535f / 4.0f * (float) glfwGetTime(), glm::vec3(0.0f, 1.0f, 0.0f)); // Render back face of the cube. colorCubeProg(); glCullFace(GL_FRONT); { GLuint tLocation = glGetUniformLocation(colorCubeProg, "time"); glUniform1f(tLocation, glfwGetTime()); GLuint mvLocation = glGetUniformLocation(colorCubeProg, "mvMatrix"); glUniformMatrix4fv(mvLocation, 1, false, glm::value_ptr(matrix)); } glClear(GL_COLOR_BUFFER_BIT); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangleBuffer); //Triangle coordinates glVertexAttribPointer( 0, // Location 0 3, // size GL_FLOAT, // type GL_FALSE, // normalized? 0, // stride (void *) 0 // array buffer offset ); glDrawElements(GL_TRIANGLES, 12 * 3, GL_UNSIGNED_INT, 0); glDisableVertexAttribArray(0); // Do the ray casting. glBindFramebuffer(GL_FRAMEBUFFER, 0); // bind the screen glCullFace(GL_BACK); rayCasterProg(); { GLuint tLocation = glGetUniformLocation(rayCasterProg, "time"); glUniform1f(tLocation, glfwGetTime()); GLuint mvLocation = glGetUniformLocation(rayCasterProg, "mvMatrix"); glUniformMatrix4fv(mvLocation, 1, false, glm::value_ptr(matrix)); GLuint windowSizeLocation = glGetUniformLocation(rayCasterProg, "windowSize"); glUniform2f(windowSizeLocation, width, height); } glClear(GL_COLOR_BUFFER_BIT); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, *(framebuffer->getTexture())); GLuint textureLocation = glGetUniformLocation(rayCasterProg, "backfaceTexture"); glUniform1i(textureLocation, 0); State *currentState = sim.getCurrentState(); std::vector<glm::vec3> vertexList; std::vector<std::vector<int> > faceIndices; // copy desired quantities to texture for (unsigned int k = 0; k < d; ++k) { for (unsigned int j = 0; j < h; ++j) { for (unsigned int i = 0; i < w; ++i) { // velocity //tex3D.set(i,j,k,0, 0.5 + 0.5*currentState.getVelocityGrid()->u->get(i,j,k)); //tex3D.set(i,j,1, 0.5 + 0.5*currentState.getVelocityGrid()->v->get(i,j)); //tex3D.set(i,j,2, 0.5 + currentState.getCellTypeGrid()->get(i, j)); //tex3D.set(i,j,2, 0.5); //tex3D.set(i,j,3, 1.0f); // divergence //tex3D.set(i,j,0, fabs(sim.getDivergenceGrid()->get(i,j))); //tex3D.set(i,j,1, fabs(sim.getDivergenceGrid()->get(i,j))); //tex3D.set(i,j,2, fabs(sim.getDivergenceGrid()->get(i,j))); //tex3D.set(i,j,3, 1.0f); // type // tex3D.set(i,j,k, 0, currentState.getCellTypeGrid()->get(i,j, k) == CellType::FLUID ? 1.0 : 0.0); // tex3D.set(i,j,k, 1, currentState.getCellTypeGrid()->get(i,j, k) == CellType::FLUID ? 1.0 : 0.0); // tex3D.set(i,j,k, 2, currentState.getCellTypeGrid()->get(i,j, k) == CellType::SOLID ? 1.0 : 0.0); // tex3D.set(i,j,k, 3, 1.0f); if(currentState->getSignedDistanceGrid()->isValid(i+1,j,k) && currentState->getSignedDistanceGrid()->isValid(i,j+1,k) && currentState->getSignedDistanceGrid()->isValid(i+1,j+1,k) && currentState->getSignedDistanceGrid()->isValid(i,j,k+1) && currentState->getSignedDistanceGrid()->isValid(i+1,j,k+1) && currentState->getSignedDistanceGrid()->isValid(i,j+1,k+1) && currentState->getSignedDistanceGrid()->isValid(i+1,j+1,k+1)){ marchingCubes::GRIDCELL gridcell; gridcell.p[0] = glm::vec3(i,j,k); gridcell.p[1] = glm::vec3(i,j+1,k); gridcell.p[2] = glm::vec3(i+1,j+1,k); gridcell.p[3] = glm::vec3(i+1,j,k); gridcell.p[4] = glm::vec3(i,j,k+1); gridcell.p[5] = glm::vec3(i,j+1,k+1); gridcell.p[6] = glm::vec3(i+1,j+1,k+1); gridcell.p[7] = glm::vec3(i+1,j,k+1); gridcell.val[0] = currentState->getSignedDistanceGrid()->get(i, j, k); gridcell.val[1] = currentState->getSignedDistanceGrid()->get(i, j+1, k); gridcell.val[2] = currentState->getSignedDistanceGrid()->get(i+1, j+1, k); gridcell.val[3] = currentState->getSignedDistanceGrid()->get(i+1, j, k); gridcell.val[4] = currentState->getSignedDistanceGrid()->get(i, j, k+1); gridcell.val[5] = currentState->getSignedDistanceGrid()->get(i, j+1, k+1); gridcell.val[6] = currentState->getSignedDistanceGrid()->get(i+1, j+1, k+1); gridcell.val[7] = currentState->getSignedDistanceGrid()->get(i+1, j, k+1); //std::cout << gridcell.val[0] << std::endl; marchingCubes::TRIANGLE *triangles = new marchingCubes::TRIANGLE[5]; int numTriangles = marchingCubes::PolygoniseCube(gridcell, 0.0, triangles); for(int i = 0; i < numTriangles; i++){ int startIndex = vertexList.size()+1; for(int j = 0; j < 3; j++){ //std::cout << triangles[i].p[j].x << " " << triangles[i].p[j].y << " " << triangles[i].p[j].z << std::endl; } vertexList.push_back(triangles[i].p[0]); vertexList.push_back(triangles[i].p[1]); vertexList.push_back(triangles[i].p[2]); std::vector<int> indices = { startIndex, startIndex+1, startIndex+2 }; faceIndices.push_back(indices); } delete[] triangles; } //signed dist float dist = currentState->getSignedDistanceGrid()->get(i, j, k); float solid = currentState->getCellTypeGrid()->get(i, j, k) == CellType::SOLID ? 1.0f : 0.0f; dist = (glm::clamp(dist + solid, -1.0f, 1.0f) + 1) / 2; tex3D.set(i, j, k, 0, solid); tex3D.set(i, j, k, 1, 0.0f); // not used tex3D.set(i, j, k, 2, dist); tex3D.set(i, j, k, 3, 1.0f); //closest point // tex3D.set(i,j,0, currentState.getClosestPointGrid()->get(i,j).x / 70.0); // tex3D.set(i,j,1, currentState.getClosestPointGrid()->get(i,j).y / 70.0); // tex3D.set(i,j,2, 0.0f); // tex3D.set(i,j,3, 1.0f); } } } printObjToFile("exported_" + std::to_string(i) + ".obj", vertexList, faceIndices); std::ofstream fileStream("exportedState_" + std::to_string(i) + ".pf", std::ios::binary); currentState->write(fileStream); fileStream.close(); // activate and upload texture to gpu tex3D(GL_TEXTURE1); GLuint volumeTextureLocation = glGetUniformLocation(rayCasterProg, "volumeTexture"); glUniform1i(volumeTextureLocation, 1); glEnableVertexAttribArray(0); glDrawElements(GL_TRIANGLES, 12 * 3, GL_UNSIGNED_INT, 0); glDisableVertexAttribArray(0); FBO::deactivate(); ////////////////// Start drawing bubbles ////////////////////// // Draw bubbles const std::vector<Bubble> bubbles = currentState->getBubbles(); g_bubble_buffer_data.clear(); std::cout << "frame=" << i << ", nBubbles=" << bubbles.size() << std::endl; for (int i = 0; i < bubbles.size(); i++) { Bubble b = bubbles.at(i); // std::cout << "bubble pos " << b.position.x << ", " << b.position.y << std::endl << b.radius << std::endl; g_bubble_buffer_data.push_back(b.position.x / (float)w * 2.0 - 1.0); g_bubble_buffer_data.push_back(b.position.y / (float)h * 2.0 - 1.0); g_bubble_buffer_data.push_back(b.position.z / (float)d * 2.0 - 1.0); g_bubble_buffer_data.push_back(b.radius); } glBindBuffer(GL_ARRAY_BUFFER, bubbleBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * g_bubble_buffer_data.size(), &g_bubble_buffer_data[0], GL_DYNAMIC_DRAW); bubbleProg(); glEnable(GL_PROGRAM_POINT_SIZE); { GLuint tLocation = glGetUniformLocation(colorCubeProg, "time"); glUniform1f(tLocation, glfwGetTime()); GLuint mvLocation = glGetUniformLocation(colorCubeProg, "mvMatrix"); glUniformMatrix4fv(mvLocation, 1, false, glm::value_ptr(matrix)); } // glEnable (GL_BLEND); // glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPointSize(4.0); if (g_bubble_buffer_data.size() > 0) { glEnable(GL_PROGRAM_POINT_SIZE); glEnableVertexAttribArray(0); glVertexAttribPointer( 0, //Location 0 4, // size GL_FLOAT, // type GL_FALSE, // normalized? 0, // stride (void*)0 // array buffer offset ); glDrawArrays(GL_POINTS, 0, 4 * g_bubble_buffer_data.size()); // 3 indices starting at 0 -> 1 triangle glDisableVertexAttribArray(0); } ////////////////// End drawing bubbles ////////////////////// glfwPollEvents(); glfwSwapBuffers(window); double currentTime = glfwGetTime(); nbFrames++; if (currentTime - lastTime >= 1.0) { // If last prinf() was more than 1 sec ago // printf and reset timer std::string title = std::to_string(1000.0 / double(nbFrames)) + "ms/frame " + std::to_string(deltaT) + " dt"; glfwSetWindowTitle(window, title.c_str()); nbFrames = 0; lastTime += 1.0; } i++; // bubbleExporter.update(i, sim.getBubbleTracker()); // bubbleExporter.exportSnapshot(i, "bubbles_" + std::to_string(i) + ".mx"); /* if (i > 600) { bubbleExporter.exportBubbles("bubbles.mx"); break; }*/ } // Check if the ESC key was pressed or the window was closed while (!glfwWindowShouldClose(window)); std::cout << "Cleaning up!" << std::endl; // Close OpenGL window and terminate GLFW glfwDestroyWindow(window); glfwTerminate(); glDeleteBuffers(1, &vertexbuffer); glDeleteVertexArrays(1, &VertexArrayID); exit(EXIT_SUCCESS); }