void run() { if(!initialize()) shutdown("Failed to initialize"); if(!loadContent()) shutdown("Failed to load resources"); Mesh cubeMesh = Mesh::genUnitColoredCube(); MeshBuffer cubeBuffer(cubeMesh); Model cube(cubeBuffer); Mesh waterMesh = Mesh::genUnitColoredPlane(Color(0.57f, 0.63f, 0.98f)); MeshBuffer waterBuffer(waterMesh); Model water(waterBuffer); BufferObject quadVbo; float quadVertices[] = { -1.0f, -1.0f, 0.0f, 0.0f, +1.0f, -1.0f, 1.0f, 0.0f, +1.0f, +1.0f, 1.0f, 1.0f, +1.0f, +1.0f, 1.0f, 1.0f, -1.0f, +1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f }; quadVbo.create(GL_ARRAY_BUFFER, GL_STATIC_DRAW, sizeof(quadVertices), quadVertices); Mesh gridMesh; for(int i = 0; i <= 8; ++i) { float f = (i / 8.0) * 2.0f - 1.0f; int j = gridMesh.getPositionCount(); gridMesh.addPosition(f * 3.0f, 0.0f, -3.0f); gridMesh.addPosition(f * 3.0f, 0.0f, +3.0f); gridMesh.addPosition(-3.0f, 0.0f, f * 3.0f); gridMesh.addPosition(+3.0f, 0.0f, f * 3.0f); gridMesh.addColor(Colors::White); gridMesh.addColor(Colors::White); gridMesh.addColor(Colors::White); gridMesh.addColor(Colors::White); gridMesh.addIndex(j + 0); gridMesh.addIndex(j + 1); gridMesh.addIndex(j + 2); gridMesh.addIndex(j + 3); } MeshBuffer gridBuffer(gridMesh); Model grid(gridBuffer); VertexArray vao; vao.create(); vao.bind(); mat4 perspectiveMatrix = glm::perspective(45.0f, windowWidth / float(windowHeight), 0.05f, 50.0f); // The geometry to be refracted and reflected are stored in these // In addition to RGB values, the world-space height is stored in the alpha-channel // of the refraction texture. // Fresnel equations is used to blend between the two textures RenderTexture refractionRT(windowWidth, windowHeight); RenderTexture reflectionRT(windowWidth, windowHeight); renderer.setClearColor(0.55f, 0.45f, 0.45f, 1.0f); renderer.setClearDepth(1.0); Timer timer; timer.start(); double renderTime = 0.0; while(context.isOpen()) { timer.step(); double time = timer.getElapsedTime(); update(time, timer.getDelta()); double renderStart = timer.getElapsedTime(); MatrixStack viewMatrix; viewMatrix.push(); viewMatrix.translate(0.0f, 0.0f, -3.0f); viewMatrix.rotateX(xAxisRotation); viewMatrix.rotateY(yAxisRotation); renderer.setCullState(CullStates::CullNone); renderer.setDepthTestState(DepthTestStates::LessThanOrEqual); colorShader.begin(); colorShader.setUniform("projection", perspectiveMatrix); cube.pushTransform(); cube.translate(0.0f, 0.0f, 0.0f); cube.scale(0.5f); // Render the geometry to be refracted, store result in rt refractionRT.begin(); renderer.clearColorAndDepth(); colorShader.setUniform("view", viewMatrix.top()); cube.draw(GL_TRIANGLES); grid.draw(GL_LINES); refractionRT.end(); // Render the geometry to be reflected, store result in rt reflectionRT.begin(); renderer.clearColorAndDepth(); viewMatrix.push(); viewMatrix.scale(1.0f, -1.0f, 1.0f); // Reflect about xz-plane colorShader.setUniform("view", viewMatrix.top()); cube.draw(GL_TRIANGLES); viewMatrix.pop(); reflectionRT.end(); colorShader.end(); cube.popTransform(); // Render the water with the previous reflection/refraction texture waterShader.begin(); waterShader.setUniform("time", time); glActiveTexture(GL_TEXTURE0 + 0); refractionRT.bindTexture(); glActiveTexture(GL_TEXTURE0 + 1); reflectionRT.bindTexture(); glActiveTexture(GL_TEXTURE0 + 2); waterNormals.bind(); //waterShader.setUniform("view", viewMatrix.top()); waterShader.setUniform("refraction_tex", 0); waterShader.setUniform("reflection_tex", 1); waterShader.setUniform("water_normals_tex", 2); //waterShader.setUniform("light0_pos", vec3(0.0f, 1.0f, 0.0f)); //waterShader.setUniform("light0_col", vec3(1.0f, 0.8f, 0.5f)); //waterShader.setUniform("ambient", vec3(67.0f/255.0f, 66.0f/255.0f, 63.0f/255.0f)); quadVbo.bind(); waterShader.setAttributefv("position", 2, 4, 0); waterShader.setAttributefv("texel", 2, 4, 2); glDrawArrays(GL_TRIANGLES, 0, 6); quadVbo.unbind(); reflectionRT.unbindTexture(); refractionRT.unbindTexture(); waterNormals.unbind(); waterShader.end(); glActiveTexture(GL_TEXTURE0 + 0); // Render unmirrored scene //colorShader.begin(); //renderer.clearColorAndDepth(); //renderer.setCullState(CullStates::CullNone); //renderer.setBlendState(BlendStates::AlphaBlend); //renderer.setDepthTestState(DepthTestStates::LessThanOrEqual); //colorShader.setUniform("projection", perspectiveMatrix); //colorShader.setUniform("view", viewMatrix.top()); //cube.pushTransform(); //cube.translate(0.0f, 0.4f, 0.0f); //cube.scale(0.5f); //cube.draw(GL_TRIANGLES); /*grid.pushTransform(); grid.translate(0.0f, -0.5f, 0.0f); grid.draw(GL_LINES); grid.popTransform();*/ // Draw mirrored scene to a rendertarget /*rt.begin(); renderer.clearColorAndDepth(); viewMatrix.push(); viewMatrix.scale(1.0f, -1.0f, 1.0f); colorShader.setUniform("view", viewMatrix.top()); cube.draw(GL_TRIANGLES); cube.popTransform(); viewMatrix.pop(); rt.end();*/ // Enable stencil testing and mask out a section containing the water mesh //glEnable(GL_STENCIL_TEST); //glStencilFunc(GL_ALWAYS, 1, 0xFF); // Set any stencil to 1 //glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); //glStencilMask(0xFF); // Write to stencil buffer //glDepthMask(GL_FALSE); // Don't write to depth buffer //glClear(GL_STENCIL_BUFFER_BIT); // Clear stencil buffer (0 by default) //// Draw water mesh //water.pushTransform(); //water.scale(3.0f); //water.draw(GL_TRIANGLES); //water.popTransform(); //colorShader.end(); //// Draw previous rendertarget as a quad masked into the water plane //glStencilFunc(GL_EQUAL, 1, 0xFF); // Pass test if stencil value is 1 //glStencilMask(0x00); // Don't write anything to stencil buffer //glDepthMask(GL_TRUE); //glDisable(GL_STENCIL_TEST); viewMatrix.pop(); context.display(); renderTime = timer.getElapsedTime() - renderStart; if(renderTime < 0.013) context.sleep(0.013 - renderTime); if(checkGLErrors(std::cerr)) { std::cin.get(); context.close(); } } waterNormals.dispose(); colorShader.dispose(); waterShader.dispose(); vao.dispose(); context.dispose(); }
std::vector<Grid_t> DiffusionGrid(const unsigned gridDim, const float d, const float dt, std::vector<float> const &_timesToRecord) { std::vector<float> timesToRecord(_timesToRecord); const int nSnapshots = timesToRecord.size(); // Construct cartesian grid int nHorizontal, nVertical; const int nRanks = mpi::size(); nHorizontal = nVertical = std::sqrt(nRanks); while (true) { int nCells = nHorizontal*nVertical; if (nCells == nRanks) { break; } if (nCells < nRanks) { ++nVertical; } else { --nHorizontal; } } mpi::CartesianGrid<2> mpiGrid({{nVertical, nHorizontal}}, false); // Determine local grid const int rowBegin = gridDim * mpiGrid.row() / mpiGrid.rowMax(); const int rowEnd = gridDim * (mpiGrid.row() + 1) / mpiGrid.rowMax(); const int nRows = rowEnd - rowBegin; const int colBegin = gridDim * mpiGrid.col() / mpiGrid.colMax(); const int colEnd = gridDim * (mpiGrid.col() + 1) / mpiGrid.colMax(); const int nCols = colEnd - colBegin; Grid_t grid(nRows + 2, Row_t(nCols + 2)); // Added padding // Initialize local grid values const int fillStart = gridDim / 4; const int fillEnd = gridDim - fillStart; const int minRow = fillStart - rowBegin; const int maxRow = fillEnd - rowBegin; const int minCol = fillStart - colBegin; const int maxCol = fillEnd - colBegin; const int iMax = nRows + 1; const int jMax = nCols + 1; for (int i = -1; i < iMax; ++i) { const bool inRow = i > minRow && i < maxRow; for (int j = -1; j < jMax; ++j) { grid[i + 1][j + 1] = inRow && j > minCol && j < maxCol; } } Grid_t gridBuffer(grid); // Copy into gridBuffer // Run diffusion std::sort(timesToRecord.begin(), timesToRecord.end()); std::vector<Grid_t> localSnapshots(nSnapshots); auto outputItr = localSnapshots.begin(); auto timeItr = timesToRecord.cbegin(); const auto timeItrEnd = timesToRecord.cend(); const float ds = 2. / gridDim; const float factor = d * dt / (ds * ds); const int iMaxInner = iMax - 1; const int jMaxInner = jMax - 1; float t = 0; auto diffuse = [&grid, &factor](const int i, const int j) { return grid[i][j] + factor * (grid[i - 1][j] + grid[i][j - 1] - 4 * grid[i][j] + grid[i][j + 1] + grid[i + 1][j]); }; const std::array<std::pair<int, bool>, 4> neighbors = { {mpiGrid.up(), mpiGrid.down(), mpiGrid.left(), mpiGrid.right()}}; std::vector<float> bufferSendLeft(nRows+2); std::vector<float> bufferSendRight(nRows+2); std::vector<float> bufferReceiveLeft(nRows+2); std::vector<float> bufferReceiveRight(nRows+2); for (;;t += dt) { if (t >= *timeItr) { // Collect snapshot *outputItr++ = grid; if (++timeItr == timeItrEnd) { break; } } // Handle edges std::vector<MPI_Request> colReceive; std::vector<MPI_Request> requests; // Horizontal edges for (int i = 1; i < iMax; ++i) { bufferSendLeft[i] = diffuse(i, 1); bufferSendRight[i] = diffuse(i, nCols); } if (neighbors[2].second) { requests.emplace_back(mpi::SendAsync(bufferSendLeft.begin(), bufferSendLeft.end(), neighbors[2].first)); colReceive.emplace_back(mpi::ReceiveAsync(bufferReceiveLeft.begin(), bufferReceiveLeft.end(), neighbors[2].first)); } if (neighbors[3].second) { requests.emplace_back(mpi::SendAsync(bufferSendRight.begin(), bufferSendRight.end(), neighbors[3].first)); colReceive.emplace_back(mpi::ReceiveAsync(bufferReceiveRight.begin(), bufferReceiveRight.end(), neighbors[3].first)); } // Top edge for (int j = 1; j < jMax; ++j) { gridBuffer[1][j] = diffuse(1, j); } if (neighbors[0].second) { requests.emplace_back(mpi::SendAsync( gridBuffer[1].begin(), gridBuffer[1].end(), neighbors[0].first)); requests.emplace_back(mpi::ReceiveAsync( gridBuffer[0].begin(), gridBuffer[0].end(), neighbors[0].first)); } // Bottom edge for (int j = 1; j < jMax; ++j) { gridBuffer[nRows][j] = diffuse(nRows, j); } if (neighbors[1].second) { requests.emplace_back(mpi::SendAsync(gridBuffer[nRows].begin(), gridBuffer[nRows].end(), neighbors[1].first)); requests.emplace_back(mpi::ReceiveAsync(gridBuffer[nRows + 1].begin(), gridBuffer[nRows + 1].end(), neighbors[1].first)); } // Retrieve the cols so they can be copied to the grid while computing the // bulk mpi::WaitAll(colReceive); // Compute the bulk for (int i = 2; i < iMaxInner; ++i) { gridBuffer[i][0] = bufferReceiveLeft[i]; gridBuffer[i][1] = bufferSendLeft[i]; for (int j = 2; j < jMaxInner; ++j) { gridBuffer[i][j] = diffuse(i, j); } gridBuffer[i][nCols] = bufferSendRight[i]; gridBuffer[i][nCols + 1] = bufferReceiveRight[i]; } // Wait for all remaining sends and receives to finish mpi::WaitAll(requests); gridBuffer.swap(grid); } // End main loop // Gather results const MPI_Comm rowComm = mpiGrid.Partition<0>(); const MPI_Comm colComm = mpiGrid.Partition<1>(); const int rank = mpi::rank(); const int colRank = mpi::rank(colComm); const int rowRank = mpi::rank(rowComm); std::vector<Grid_t> totalSnapshots; if (rank == 0) { totalSnapshots = std::vector<Grid_t>(nSnapshots, Grid_t(gridDim, Row_t(gridDim))); } std::vector<Grid_t> rowSnapshots; if (colRank == 0) { rowSnapshots = std::vector<Grid_t>(nSnapshots, Grid_t(nRows, Row_t(gridDim))); } std::vector<MPI_Request> requests; std::vector<int> colSizes; std::vector<int> colOffsets; // Generate gather parameters if (colRank == 0) { colOffsets.emplace_back(0); for (int i = 0; i < nHorizontal; ++i) { colSizes.emplace_back(gridDim * (i + 1) / mpiGrid.colMax() - gridDim * i / mpiGrid.colMax()); if (i > 0) { colOffsets.emplace_back(colOffsets[i - 1] + colSizes[i] - 1); } } } for (int s = 0; s < nSnapshots; ++s) { // Gather grid rows across columns in each row of MPI ranks for (int i = 0; i < nRows; ++i) { typename Row_t::iterator target; if (colRank == 0) { target = rowSnapshots[s][i].begin(); } mpi::Gather(localSnapshots[s][i + 1].begin() + 1, localSnapshots[s][i + 1].end() - 1, target, colSizes, colOffsets, 0, colComm); } // Gather all rows in root rank if (colRank == 0) { if (rowRank != 0) { for (int i = 0; i < nRows; ++i) { mpi::Send(rowSnapshots[s][i].begin(), rowSnapshots[s][i].end(), 0, 0, rowComm); } } else { int globalRow = 0; for (int i = 0; i < nRows; ++i) { totalSnapshots[s][globalRow] = std::move(rowSnapshots[s][i]); ++globalRow; } for (int r = 1, rMax = mpiGrid.rowMax(); r < rMax; ++r) { const int currRowBegin = gridDim*r/nVertical; const int currRowEnd = gridDim*(r+1)/nVertical; const int currNRows = currRowEnd - currRowBegin; for (int i = 0; i < currNRows; ++i) { requests.emplace_back(mpi::ReceiveAsync( totalSnapshots[s][globalRow].begin(), totalSnapshots[s][globalRow].end(), r, 0, rowComm)); ++globalRow; } } } } } mpi::WaitAll(requests); return totalSnapshots; }