一个极其隐秘只有...吧 关注:2,375贴子:11,089
  • 4回复贴,共1

diamond-square算法生成高度图(地形)

只看楼主收藏回复

从左到右是原始图、简单平滑处理过的、上色的
参考文章http://www.cnblogs.com/lookof/archive/2009/03/18/1415259.html
这是禁止事项。——朝比奈实玖瑠


通过百度相册上传1楼2014-06-21 21:52回复
    在对话框类声明里添加:
    protected:
        CImage img;
        CImage img_smooth;
        CImage img_colored;
        const static int SIZE = 257; //最好是2^n+1
        int HeightMap[SIZE][SIZE];
    protected:
        void DiamondSquare(int x1, int y1, int x2, int y2, int randomRange = 100, double roughness = 0.7f);
        //返回[min, max]均匀的随机整数
        int RandBetween(int min, int max);
    //超过数组范围或高度未计算返回-1
        inline int GetHeight(int x, int y)
        {
            return (x >= 0 && x < SIZE && y >= 0 && y < SIZE) ? HeightMap[x][y] : -1;
        }
    //已计算不重复写,height限制在[0, 255]
        inline void SetHeight(int x, int y, int height)
        {
            if(HeightMap[x][y] == -1)
                HeightMap[x][y] = height < 0 ? 0 : (height > 255 ? 255 : height);
        }
    只要是活着的东西,即使是神也杀给你看!——两仪 式


    2楼2014-06-21 21:54
    回复
      在对话框注册函数里添加:
      srand(GetTickCount());
      img.Create(SIZE, SIZE, 32);
      img_smooth.Create(SIZE, SIZE, 32);
      img_colored.Create(SIZE, SIZE, 32);
      OnBnClickedButton1();
      在对话框绘制函数里添加:
      CClientDC dc(this);
      img.Draw(dc, 0, 0, SIZE - 1, SIZE - 1);
      img_smooth.Draw(dc, SIZE + 2, 0, SIZE - 1, SIZE - 1);
      img_colored.Draw(dc, SIZE + SIZE + 4, 0, SIZE - 1, SIZE - 1);
      加在对话框cpp文件末尾:
      void CHeightMapDlg::OnBnClickedButton1()
      {
          // TODO: 在此添加控件通知处理程序代码
          //初始化高度值为-1
          memset(HeightMap, -1, sizeof(HeightMap));
          SetHeight(0, 0, RandBetween(0, 255));
          SetHeight(SIZE - 1, 0, RandBetween(0, 255));
          SetHeight(0, SIZE - 1, RandBetween(0, 255));
          SetHeight(SIZE - 1, SIZE - 1, RandBetween(0, 255));
          DiamondSquare(0, 0, SIZE - 1, SIZE - 1);
      //原始
          COLORREF *data = (COLORREF*)img.GetBits();
          int bitCount = img.GetBPP() / 8;
          int pitch = img.GetPitch() / bitCount;
          for(int y = 0; y < SIZE; y++)
              for(int x = 0; x < SIZE; x++)
                  data[pitch * y + x] = RGB(HeightMap[x][y], HeightMap[x][y], HeightMap[x][y]);
      //平滑,取4点平均值作为左上点高度值
          for(int y = 0; y < SIZE - 1; y++)
              for(int x = 0; x < SIZE - 1; x++)
                  HeightMap[x][y] = (HeightMap[x][y] + HeightMap[x + 1][y] + HeightMap[x][y + 1] + HeightMap[x + 1][y + 1]) / 4;
      data = (COLORREF*)img_smooth.GetBits();
          bitCount = img_smooth.GetBPP() / 8;
          pitch = img_smooth.GetPitch() / bitCount;
          for(int y = 0; y < SIZE; y++)
              for(int x = 0; x < SIZE; x++)
                  data[pitch * y + x] = RGB(HeightMap[x][y], HeightMap[x][y], HeightMap[x][y]);
      //上色
          data = (COLORREF*)img_colored.GetBits();
          bitCount = img_colored.GetBPP() / 8;
          pitch = img_colored.GetPitch() / bitCount;
          for(int y = 0; y < SIZE; y++)
              for(int x = 0; x < SIZE; x++)
              {
                  double scale;
                  COLORREF color;
                  if(HeightMap[x][y] > 170)
                  {
                      scale = ((double)HeightMap[x][y] - 171.0f) / (255.0f - 170.0f);
                      color = RGB((int)(0xCC + (0xFF - 0xCC) * scale), (int)(0xCC + (0xFF - 0xCC) * scale), (int)(0xCC + (0xFF - 0xCC) * scale));
                  }
                  else if(HeightMap[x][y] > 85)
                  {
                      scale = ((double)HeightMap[x][y] - 86.0f) / (170.0f - 85.0f);
                      color = RGB((int)(0x52 + (0x5C - 0x52) * scale), (int)(0x97 + (0xB9 - 0x97) * scale), (int)(0xB7 + (0xE5 - 0xB7) * scale));
                  }
                  else
                  {
                      scale = (double)HeightMap[x][y] / 85.0f;
                      color = RGB((int)(0x39 + (0x4C - 0x39) * scale), (int)(0xC4 + (0xF1 - 0xC4) * scale), (int)(0x19 + (0x26 - 0x19) * scale));
                  }
                  data[pitch * y + x] = color;
              }
      RedrawWindow();
      }
      void CHeightMapDlg::DiamondSquare(int x1, int y1, int x2, int y2, int randomRange, double roughness)
      {
          //中心
          int mx = (x1 + x2) / 2, my = (y1 + y2) / 2;
          //TRACE("(%d, %d) (%d, %d) (%d, %d) %d %lf\n", x1, y1, x2, y2, mx, my, randomRange, roughness);
          int m = (HeightMap[x1][y1] + HeightMap[x2][y1] + HeightMap[x1][y2] + HeightMap[x2][y2]) / 4 + RandBetween(-randomRange, randomRange);
          SetHeight(mx, my, m);
      int height, height2;
          //上中点
          height2 = GetHeight(mx, y1 + y1 - my);
          //如果缺少1点数据则取3点平均值,可以改为BFS(迭代)保证要用的点已经计算
          height = (HeightMap[x1][y1] + HeightMap[x2][y1] + m + (height2 != -1 ? height2 : 0)) / (height2 != -1 ? 4 : 3) + RandBetween(-randomRange, randomRange);
          SetHeight(mx, y1, height);
      //左中点
          height2 = GetHeight(x1 + x1 - mx, my);
          height = (HeightMap[x1][y1] + HeightMap[x1][y2] + m + (height2 != -1 ? height2 : 0)) / (height2 != -1 ? 4 : 3) + RandBetween(-randomRange, randomRange);
          SetHeight(x1, my, height);
      //下中点
          height2 = GetHeight(mx, y2 + y2 - my);
          height = (HeightMap[x1][y2] + HeightMap[x2][y2] + m + (height2 != -1 ? height2 : 0)) / (height2 != -1 ? 4 : 3) + RandBetween(-randomRange, randomRange);
          SetHeight(mx, y2, height);
      //右中点
          height2 = GetHeight(x2 + x2 - mx, my);
          height = (HeightMap[x2][y1] + HeightMap[x2][y2] + m + (height2 != -1 ? height2 : 0)) / (height2 != -1 ? 4 : 3) + RandBetween(-randomRange, randomRange);
          SetHeight(x2, my, height);
      //左上正方形
          if(mx - x1 > 1 || my - y1 > 1)
              DiamondSquare(x1, y1, mx, my, (int)(randomRange * roughness), roughness);
          //右上正方形
          if(x2 - mx > 1 || my - y1 > 1)
              DiamondSquare(mx, y1, x2, my, (int)(randomRange * roughness), roughness);
          //左下正方形
          if(mx - x1 > 1 || y2 - my > 1)
              DiamondSquare(x1, my, mx, y2, (int)(randomRange * roughness), roughness);
          //右下正方形
          if(x2 - mx > 1 || y2 - my > 1)
              DiamondSquare(mx, my, x2, y2, (int)(randomRange * roughness), roughness);
      }
      //返回[min, max]均匀的随机整数
      int CHeightMapDlg::RandBetween(int min, int max)
      {
          return (int)((double)rand()/(RAND_MAX + 1) * (max - min + 1)) + min;
      }
      魔装少女就是本大爷!——相川步


      3楼2014-06-21 21:59
      回复
        降低了粗糙度转成3D地形,感觉还是不够平滑...以后加上各种滤波吧




        都是时臣的错!——间桐雁夜


        4楼2014-06-22 00:27
        收起回复