示例#1
0
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();
}
示例#2
0
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;
}