diamond-square算法生成高度图(地形)
一个极其隐秘只有xfgryujk知道的地方吧
全部回复
仅看楼主
level 13
图片来自:盗我原号的没J8的百度相册从左到右是原始图、简单平滑处理过的、上色的
参考文章http://www.cnblogs.com/lookof/archive/2009/03/18/1415259.html
这是禁止事项。——朝比奈实玖瑠

2014年06月21日 13点06分 1
level 13
在对话框类声明里添加:
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);
    }
只要是活着的东西,即使是神也杀给你看!——两仪 式

2014年06月21日 13点06分 2
level 13
在对话框注册函数里添加:
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;
}
魔装少女就是本大爷!——相川步
2014年06月21日 13点06分 3
level 13
降低了粗糙度转成3D地形,感觉还是不够平滑...以后加上各种滤波吧
都是时臣的错!——间桐雁夜

2014年06月21日 16点06分 4
洛奇玩家~~
2017年10月13日 05点10分
1