Картинка, конечно, интересная, но абсолютно не в тему. Это уже моя третья попытка реализации этого алгоритма, до этого получались шумные картинки с черными полосами вокруг квадратов, замучился уже. Вот код:
Синтаксис:
Используется csharp
public class Heighmap_class
{
public static int size = 2048;
public static float[,] heighmap = new float[size, size];
public static float roughness = 1.5f;
public static void Square(int lx, int ly, int rx, int ry)
{
int l = (rx - lx) / 2;
float a = heighmap[lx, ly]; // B--------C
float b = heighmap[lx, ry]; // | |
float c = heighmap[rx, ry]; // | ce |
float d = heighmap[rx, ly]; // | |
// A--------D
int cex = lx + l;
int cey = ly + l;
heighmap[cex, cey] = (a + b + c + d) / 4 + Random.Range(-l * 2 * roughness / size, l * 2 * roughness / size);
}
public static void Diamond(int tgx, int tgy, int l)
{
float a, b, c, d;
if (tgy - l > 0)
a = heighmap[tgx, tgy - l]; // C--------
else // | |
a = heighmap[tgx, size - l]; // B---t g----D |
// | |
// A--------
if (tgx - l > 0)
b = heighmap[tgx - l, tgy];
else
b = heighmap[size - l, tgy];
if (tgy + l < size - 1)
c = heighmap[tgx, tgy + l];
else
c = heighmap[tgx, l];
if (tgx + l < size - 1)
d = heighmap[tgx + l, tgy];
else
d = heighmap[l, tgy];
heighmap[tgx, tgy] = (a + b + c + d) / 4 + Random.Range(-l * 2 * roughness / size, l * 2 * roughness / size);
}
public static void DiamondSquare(int lx, int ly, int rx, int ry)
{
int l = (rx - lx) / 2;
if (l > 0)
{
Square(lx, ly, rx, ry);
Diamond(lx, ly + l, l);
Diamond(rx, ry - l, l);
Diamond(rx - l, ry, l);
Diamond(lx + l, ly, l);
int cex = lx + l;
int cey = ly + l;
DiamondSquare(lx, ly, cex, cey);
DiamondSquare(lx, ly + l, lx + l, ry);
DiamondSquare(cex, cey, rx, ry);
DiamondSquare(lx + l, ly, cex, cey);
}
}
public static void Generate()
{
heighmap[0, 0] = Random.Range(0.2f, 1.0f);
heighmap[size - 1, 0] = Random.Range(0.2f, 1.0f);
heighmap[size - 1, size - 1] = Random.Range(0.2f, 1.0f);
heighmap[0, size - 1] = Random.Range(0.2f, 1.0f);
DiamondSquare(0, 0, size - 1, size - 1);
}
}
{
public static int size = 2048;
public static float[,] heighmap = new float[size, size];
public static float roughness = 1.5f;
public static void Square(int lx, int ly, int rx, int ry)
{
int l = (rx - lx) / 2;
float a = heighmap[lx, ly]; // B--------C
float b = heighmap[lx, ry]; // | |
float c = heighmap[rx, ry]; // | ce |
float d = heighmap[rx, ly]; // | |
// A--------D
int cex = lx + l;
int cey = ly + l;
heighmap[cex, cey] = (a + b + c + d) / 4 + Random.Range(-l * 2 * roughness / size, l * 2 * roughness / size);
}
public static void Diamond(int tgx, int tgy, int l)
{
float a, b, c, d;
if (tgy - l > 0)
a = heighmap[tgx, tgy - l]; // C--------
else // | |
a = heighmap[tgx, size - l]; // B---t g----D |
// | |
// A--------
if (tgx - l > 0)
b = heighmap[tgx - l, tgy];
else
b = heighmap[size - l, tgy];
if (tgy + l < size - 1)
c = heighmap[tgx, tgy + l];
else
c = heighmap[tgx, l];
if (tgx + l < size - 1)
d = heighmap[tgx + l, tgy];
else
d = heighmap[l, tgy];
heighmap[tgx, tgy] = (a + b + c + d) / 4 + Random.Range(-l * 2 * roughness / size, l * 2 * roughness / size);
}
public static void DiamondSquare(int lx, int ly, int rx, int ry)
{
int l = (rx - lx) / 2;
if (l > 0)
{
Square(lx, ly, rx, ry);
Diamond(lx, ly + l, l);
Diamond(rx, ry - l, l);
Diamond(rx - l, ry, l);
Diamond(lx + l, ly, l);
int cex = lx + l;
int cey = ly + l;
DiamondSquare(lx, ly, cex, cey);
DiamondSquare(lx, ly + l, lx + l, ry);
DiamondSquare(cex, cey, rx, ry);
DiamondSquare(lx + l, ly, cex, cey);
}
}
public static void Generate()
{
heighmap[0, 0] = Random.Range(0.2f, 1.0f);
heighmap[size - 1, 0] = Random.Range(0.2f, 1.0f);
heighmap[size - 1, size - 1] = Random.Range(0.2f, 1.0f);
heighmap[0, size - 1] = Random.Range(0.2f, 1.0f);
DiamondSquare(0, 0, size - 1, size - 1);
}
}
Попытаюсь объяснить.
Метод Square на вход получает два угла, левый нижний и правый верхний и считает центральную точку заданного таким образом квадрата.
Diamond принимает на вход только координаты точки, которую надо посчитать (т.е. середины квадрата из предыдущего шага) и половинную сторону этого квадрата, считает координаты четырех точек справа, слева, сверху и снизу от принятой точки и также, как и в Square, усредняет их и прибавляет случайное число, пропорциональное стороне. Если любая из координат этих четырех точек выходит за границы карты, то он берет значение точки, лежащей с другой стороны, т.е. как бы сворачивает плоскость.
Метод DiamondSquare комбинирует эти два метода, принимая те же параметры, что и Square. Сначала он вызывает Square для входного квадрата, потом Diamond для всех четырех середин своих сторон, а потом рекурсивно вызывает сам себя для четырех под-квадратов до тех пор, пока не посчитает все пиксели.
Проверял перепроверял, ошибок в координатах сторон не нашел. Теперь уж и не знаю, что может быть не так. Подозрение падало на неправильные координаты смещения при выходе их за ноль в Diamond, но сколько я их не менял, ничего не поменялось. Может в генераторе случайных чисел проблема? Подозрительно, что так много точек просто ноль. Или все - таки надо точки в другом порядке считать?