示例#1
0
/// \brief One dimensional midpoint displacement fractal.
///
/// Size must be a power of 2.
/// Falloff is the decay of displacement as the fractal is refined.
/// Array is size + 1 long. array[0] and array[size] are filled
/// with the control points for the fractal.
void Segment::fill1d(BasePoint const & l, BasePoint const &h,
                     float *array) const
{
  array[0] = l.height();
  array[m_res] = h.height();
  LinInterp li(m_res, l.roughness(), h.roughness());

  // seed the RNG.
  // The RNG is seeded only once for the line and the seed is based on the
  // two endpoints -because they are the common parameters for two adjoining
  // tiles
  //srand((l.seed() * 1000 + h.seed()));
  WFMath::MTRand::uint32 seed[2] = { l.seed(), h.seed() };
  WFMath::MTRand rng(seed, 2);

  // stride is used to step across the array in a deterministic fashion
  // effectively we do the 1/2  point, then the 1/4 points, then the 1/8th
  // points etc. this has to be the same order every time because we call
  // on the RNG at every point
  decltype(getResolution()) stride = m_res / 2;

  // depth is used to indicate what level we are on. the displacement is
  // reduced each time we traverse the array.
  float depth = 1;

  while (stride)
  {
    for (decltype(getResolution()) i = stride; i < m_res; i += stride * 2)
    {
      auto hh = array[i - stride];
      auto lh = array[i + stride];
      auto hd = std::fabs(hh - lh);
      auto roughness = li.calc(i);

      //eliminate the problem where hd is nearly zero, leaving a flat section.
      if ((hd * 100.f) < roughness)
      {
        hd += 0.05f * roughness;
      }

      array[i] = ((hh + lh) / 2.f) + randHalf(rng) * roughness  * hd / (1.f + std::pow(depth, BasePoint::FALLOFF));
    }
    stride >>= 1;
    depth++;
  }
}