예제 #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++;
  }
}
예제 #2
0
/// \brief Two dimensional midpoint displacement fractal.
///
/// For a tile where edges are to be filled by 1d fractals.
/// Size must be a power of 2, array is (size + 1) * (size + 1) with the
/// corners the control points.
void Segment::fill2d(const BasePoint& p1, const BasePoint& p2, 
                     const BasePoint& p3, const BasePoint& p4)
{
    assert(m_points!=0);
    
    // int line = m_res+1;
    
    // calculate the edges first. This is necessary so that segments tile
    // seamlessly note the order in which the edges are calculated and the
    // direction. opposite edges are calculated the same way (eg left->right)
    // so that the top of one tile matches the bottom of another, likewise
    // with sides.
    
    // temporary array used to hold each edge
    float * edge = new float[m_size];
    
    // calc top edge and copy into m_points
    fill1d(p1,p2,edge);
    for (int i=0;i<=m_res;i++) {
        m_points[0*m_size + i] = edge[i];
        checkMaxMin(edge[i]);
    }

    // calc left edge and copy into m_points
    fill1d(p1,p4,edge);
    for (int i=0;i<=m_res;i++) {
        m_points[i*m_size + 0] = edge[i];
        checkMaxMin(edge[i]);
    }
   
    // calc right edge and copy into m_points
    fill1d(p2,p3,edge);
    for (int i=0;i<=m_res;i++) {
        m_points[i*m_size + m_res] = edge[i];
        checkMaxMin(edge[i]);
    }

    // calc bottom edge and copy into m_points
    fill1d(p4,p3,edge);
    for (int i=0;i<=m_res;i++) {
        m_points[m_res*m_size + i] = edge[i];
        checkMaxMin(edge[i]);
    }
    
    // seed the RNG - this is the 5th and last seeding for the tile.
    // it was seeded once for each edge, now once for the tile.
    //srand(p1.seed()*20 + p2.seed()*15 + p3.seed()*10 + p4.seed()*5);
    WFMath::MTRand::uint32 seed[4]={ p1.seed(), p2.seed(), p3.seed(), p4.seed() };
    WFMath::MTRand rng(seed, 4);

    QuadInterp qi(m_res, p1.roughness(), p2.roughness(), p3.roughness(), p4.roughness());

    float f = BasePoint::FALLOFF;
    float depth=0;
    
    // center of m_points is done separately
    int stride = m_res/2;

    //float roughness = (p1.roughness+p2.roughness+p3.roughness+p4.roughness)/(4.0f);
    float roughness = qi.calc(stride, stride);
    m_points[stride*m_size + stride] = qRMD(rng, m_points[0 * m_size + stride],
                                        m_points[stride*m_size + 0],
                                        m_points[stride*m_size + m_res],
                                        m_points[m_res*m_size + stride],
                                        roughness,
                                        f, depth);
                    

    checkMaxMin(m_points[stride*m_size + stride]);

    stride >>= 1;

    // skip across the m_points and fill in the points
    // alternate cross and plus shapes.
    // this is a diamond-square algorithm.
    while (stride) {
      //Cross shape - + contributes to value at X
      //+ . +
      //. X .
      //+ . +
      for (int i=stride;i<m_res;i+=stride*2) {
          for (int j=stride;j<m_res;j+=stride*2) {
              roughness=qi.calc(i,j);
              m_points[j*m_size + i] = qRMD(rng, m_points[(i-stride) + (j+stride) * (m_size)],
                                       m_points[(i+stride) + (j-stride) * (m_size)],
                                       m_points[(i+stride) + (j+stride) * (m_size)],
                                       m_points[(i-stride) + (j-stride) * (m_size)],
                                       roughness, f, depth);
              checkMaxMin(m_points[j*m_size + i]);
          }
      }
 
      depth++;
      //Plus shape - + contributes to value at X
      //. + .
      //+ X +
      //. + .
      for (int i=stride*2;i<m_res;i+=stride*2) {
          for (int j=stride;j<m_res;j+=stride*2) {
              roughness=qi.calc(i,j);
              m_points[j*m_size + i] = qRMD(rng, m_points[(i-stride) + (j) * (m_size)],
                                       m_points[(i+stride) + (j) * (m_size)],
                                       m_points[(i) + (j+stride) * (m_size)],
                                       m_points[(i) + (j-stride) * (m_size)], 
                                       roughness, f , depth);
              checkMaxMin(m_points[j*m_size + i]);
          }
      }
               
      for (int i=stride;i<m_res;i+=stride*2) {
          for (int j=stride*2;j<m_res;j+=stride*2) {
              roughness=qi.calc(i,j);
              m_points[j*m_size + i] = qRMD(rng, m_points[(i-stride) + (j) * (m_size)],
                                       m_points[(i+stride) + (j) * (m_size)],
                                       m_points[(i) + (j+stride) * (m_size)],
                                       m_points[(i) + (j-stride) * (m_size)],
                                       roughness, f, depth);
              checkMaxMin(m_points[j*m_size + i]);
          }
      }

      stride>>=1;
      depth++;
    }
    delete [] edge;
}