地形イメージの自動生成を行うプログラムを作りました。こういったイメージを作成する目的には、Processingが楽でいいです。
結果は以下のようになりました。


地形の凸凹はパーリンノイズで決定して、上下左右の端に近い部分は無理やり高度を下げて海にしています。
クリックするたびに新しい地形がバンバン生成されるのですが、ぼんやり眺めていると、なんかこういろんな妄想が浮かんできますな。
プログラムソースは以下です。
int IMG_WIDTH = 2048; int IMG_HEIGHT = 1024; int imageViewX = 0; int imageViewY = 0; int imageViewWidth = IMG_WIDTH; int imageViewHeight = IMG_HEIGHT; // 数字が大きいほど、地形がのっぺりする float SCALE = 100f; void setup() { fullScreen(); colorMode(RGB, 256, 256, 256); noLoop(); // イメージ描画位置を決定 if (width / IMG_WIDTH < height / IMG_HEIGHT) { imageViewWidth = width; imageViewHeight = IMG_HEIGHT * width / IMG_WIDTH; imageViewY = (height - imageViewHeight) / 2; } else { imageViewWidth = IMG_WIDTH * width / IMG_HEIGHT; imageViewHeight = height; imageViewX = (width - imageViewWidth) / 2; } } void draw() { long millis = millis(); noiseSeed((int)millis); background(0, 0, 0); PImage img = createImage(IMG_WIDTH, IMG_HEIGHT, ARGB); img.loadPixels(); for (float y = 0; y < img.height; y++) { for (float x = 0; x < img.width; x++) { float tmp = lerp(-200, 500, noise(x / SCALE, y / SCALE )); // 海抜に近いところはなだらかに。高度が高くなるほど急峻にする。 if (tmp > 0) { float ratio = lerp(0f, 1f, pow(tmp, 0.1 ) / pow(500, 0.1)); tmp *= ratio; } // 端に近いところは海にする float offsetW = pow(lerp(0, 100, abs(x - IMG_WIDTH / 2) / IMG_WIDTH), 1.5); tmp -= offsetW; float offsetH = pow(lerp(0, 100, abs(y - IMG_HEIGHT / 2) / IMG_HEIGHT), 1.5); tmp -= offsetH; tmp = constrain(tmp, -500, 500); img.pixels[(int)(x + (y * img.width))] = createColor(tmp); } } // 枠線描画 for (float y = 32; y < img.height; y += 32) { for (float x = 0; x < img.width; x += 4) { img.pixels[(int)(x + (y * img.width))] = color(30, 30, 30); } } for (float y = 0; y < img.height; y+= 4) { for (float x = 32; x < img.width; x += 32) { img.pixels[(int)(x + (y * img.width))] = color(30, 30, 30) ; } } for (float x = 0; x < img.width; x++) { int y = 0; img.pixels[(int)(x + (y * img.width))] = color(200, 200, 200); y = img.height - 1; img.pixels[(int)(x + (y * img.width))] = color(200, 200, 200); } for (float y = 0; y < img.height; y++) { int x = 0; img.pixels[(int)(x + (y * img.width))] = color(200, 200, 200); x = img.width - 1; img.pixels[(int)(x + (y * img.width))] = color(200, 200, 200); } img.updatePixels(); // 画像を表示 image(img, imageViewX, imageViewY, imageViewWidth, imageViewHeight); img.save("island-" + millis + ".png"); } color createColor(float val) { color col; if (val < -50) { col = lerpColor(color(0, 0, 50), color(0, 0, 205), (val + 300) / 250f); } else if (val < 0) { col = lerpColor(color(0, 0, 205), color(65, 105, 237), (val + 50) / 50f); // ここまで海 } else if (val < 250) { col = lerpColor(color(0, 101, 68), color(158, 154, 46), (val - 0) / 249f); } else { col = lerpColor(color(158, 154, 46), color(154, 108, 0), (val - 250) / 249f); } return col; } void mousePressed() { redraw(); }