The process is simply: 1. Take a plane 2. Cut out a shape 3. Make it a little taller 4. Repeat
- Similar to the spherical landscape algorithm by Hugo Elias.
- I found a combination of Ovals and Triangles to produce the best results.
| Python |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | #!/usr/bin/env python
# -*- coding: utf-8 -*-
import Image, ImageDraw, ImageChops, ImageOps, ImageFilter
import pygame.display, pygame.image
import random
import sys
pygame.init() #Need this to render the output
mapSize = 600 #in pixels
maxSize = 200 #maximum number of pizels for elipses, Smaller makes more "Continents"
minSize = 100 #minimum number of pizels for elipses, Larger make fewer "Islands"
randType = random.uniform #change to alter variability
roughness = 1 #High numbers make a world faster, with more "ridges", but also makes things less "smooth"
def normalize(image):
picture = ImageOps.equalize(image.filter(ImageFilter.BLUR))
return ImageChops.multiply(picture, picture)
def finish(image): #called when window is closed, or iterations stop
picture = normalize(image)
picture.save('heightmap.bmp')
pygame.quit()
sys.exit();
def makeTriangle(orig):
action = random.choice([ImageChops.add,ImageChops.difference])
xrand = lambda : int(randType(0, mapSize*3))
yrand = lambda : int(randType(0-mapSize, mapSize*2))
s1x = xrand()
s1y = yrand()
s2x = xrand()
s2y = yrand()
s3x = xrand()
s3y = yrand()
height = int(randType(1,roughness*2))
img = Image.new('L', (mapSize*2,mapSize))
draw = ImageDraw.Draw(img)
draw.polygon([s1x,s1y,s2x,s2y,s3x,s3y], fill=height)
del draw
if s1x > mapSize*2 or s2x > mapSize*2 or s3x > mapSize*2: #if it crosses our border, we needto wrap
orig = action(orig, img)
r1x = s1x - mapSize*2
r2x = s2x - mapSize*2
r3x = s3x - mapSize*2
img = Image.new('L', (mapSize*2,mapSize))
draw = ImageDraw.Draw(img)
draw.polygon([r1x,s1y,r2x,s2y,r3x,s3y], fill=height)
del draw
return action(orig, img)
def makeOval(orig):
action = random.choice([ImageChops.add,ImageChops.difference])
s1x = int(randType(0, mapSize*2))
s1y = int(randType(0-mapSize, mapSize))
s2x = int(randType(s1x+minSize, s1x+maxSize))
s2y = int(randType(s1y+minSize, s1y+maxSize*2))
height = int(randType(1,roughness))
if s2x > mapSize*2: #if it crosses our border, we needto wrap
img = Image.new('L', (mapSize*2,mapSize))
draw = ImageDraw.Draw(img)
draw.pieslice([s1x,s1y,mapSize*4,s2y], 90, 270, fill=height)
del draw
s2x=s2x-mapSize*2
orig = action(orig, img)
img = Image.new('L', (mapSize*2,mapSize))
draw = ImageDraw.Draw(img)
draw.pieslice([0-s2x,s1y,s2x,s2y], 270, 90, fill=height)
del draw
else:
img = Image.new('L', (mapSize*2,mapSize))
draw = ImageDraw.Draw(img)
draw.ellipse([s1x,s1y,s2x,s2y], fill=height)
del draw
return action(orig, img)
#initialize blank image
image = Image.new('L', (mapSize*2,mapSize))
draw = ImageDraw.Draw(image)
draw.rectangle([0-mapSize,0,mapSize*4,mapSize], fill=128)
del draw
for i in range(10000):
image = makeTriangle(image)
image = makeOval(image)
if i%50 == 1: #conver PIL to pygame display object every 50 iterations
picture = normalize(image)
picture = ImageOps.colorize(picture, 'blue', 'green')
picture = pygame.image.fromstring(picture.tostring(), picture.size, picture.mode)
pygame.display.set_mode(picture.get_size())
main_surface = pygame.display.get_surface()
main_surface.blit(picture, (0, 0))
pygame.display.update()
for event in pygame.event.get(): #When people close the window
if event.type == pygame.QUIT:
finish(image)
finish(image)
|
Discussion
This algorithm can be used with a voxel or 3d modeling application to generate random terrains. Methodological Problems: 1. Mountains don't happen vertically enough 2. No canyons 3. etc...
Implementation Issues: I can't seem to get pygame to stop flickering. Ideally I'd like to update it more frequently, but it flickers even as is.


Sign in to comment