2014-07-19 4 views
0

Je suis en train de re-mettre en œuvre quelque chose que je l'ai fait avec succès il y a un certain temps, mais je suis tout simplement pas l'obtenir tout à fait raison ..terrain Fractal/génération heightmap

L'algorithme de génération de fractale heightmap J'utilise est essentiellement l'algorithme récursif de diamant-carré. Il semble fonctionner correctement, mais la carte produite n'est pas tout à fait correcte ... Il ne semble pas que chaque point de la grille soit visité avec succès pour déterminer la couleur, et il y a une 'structure' résiduelle sur la carte cela semble être lié à la façon dont le réseau est récursif. Je ne sais pas exactement où/comment le problème pourrait être de produire ce que je vois.

Le code que j'ai jusqu'à présent est,

import matplotlib.pyplot as plt 
import matplotlib.cm as cm 
from math import sqrt 
from collections import namedtuple 
import random 

Coord=namedtuple('Coord','x y') 

class Grid(object): 
    '''grid handedness, 0,0=topleft max,max=bottomr right'''  

    def __init__(self,x,y): 
     self.size_x=x 
     self.size_y=y 
     self.data=[ [0 for _ in xrange(x)] for _ in xrange(y) ] 

    def _render_to_text(self): 
     print '\n\n' 
     for row in self.data: 
      print [ int(n) for n in row ] 

    def _render_to_colormap(self): 
     plt.imshow(self.data, interpolation='nearest',cmap=cm.gist_rainbow) 
     plt.show() 

    def render(self): 
     self._render_to_colormap() 
     #self._render_to_text() 

    def make(self,coordinate,value): 
     self.data[coordinate.x][coordinate.y]=value 

    def make_new(self,coordinate,value): 
     if self.data[coordinate.x][coordinate.y]==0: 
      self.make(coordinate,value) 

    def get(self,coordinate): 
     return self.data[coordinate.x][coordinate.y] 

class FractalHeightmap(object): 
    '''populates a 'grid' with a fractal heightmap''' 
    def __init__(self,grid,rng_seed,roughness, 
       corner_seeds=[(0,100),(0,100),(0,100),(0,100)], 
       max_depth=3): 
     self.grid=grid 
     self.max_depth=max_depth 
     self._set_initial_corners(corner_seeds) 
     self.roughness=roughness 
     self.generate_heightmap([Coord(0,0), 
           Coord(self.grid.size_x-1,0), 
           Coord(0,self.grid.size_y-1), 
           Coord(self.grid.size_x-1,self.grid.size_y-1)],1 
           ) 

    def _set_initial_corners(self,corner_seeds): 
     tl,tr,bl,br=corner_seeds 
     seeds=[[tl,tr],[bl,br]] 
     for x_idx,x in enumerate([0,self.grid.size_x-1]): 
      for y_idx,y in enumerate([0,self.grid.size_y-1]): 
       try: 
        minval,maxval=seeds[x_idx][y_idx] 
        val=minval+(random.random()*(maxval-minval)) 
       except ValueError: 
        val=seeds[x_idx][y_idx] 
       self.grid.make_new(Coord(x,y),val) 

    def generate_heightmap(self,corners,depth): 
     '''corners = (Coord(),Coord(),Coord(),Coord()/tl/tr/bl/br''' 
     if depth>self.max_depth: return 

     # 
     tl,tr,bl,br=corners 
     center=Coord((tr.x-tl.x)/2,(br.y-tr.y)/2) 

     #define edge center coordinates 
     top_c=Coord(tl.x+((tr.x-tl.x)/2),tl.y) 
     left_c=Coord(tl.x,tl.y+((bl.y-tl.y)/2)) 
     right_c=Coord(tr.x,tr.y+((br.y-tr.y)/2)) 
     bot_c=Coord(bl.x+((br.x-bl.x)/2),bl.y) 

     #calc the center and edge_center heights 
     avg=sum([self.grid.get(tl), 
       self.grid.get(tr), 
       self.grid.get(bl), 
       self.grid.get(br)] 
       )/4.0 ###NOTE, we can choose to use the current corners, the new edge-centers, or all 
       #currenty we use the current corners 
       #then do the edge centers 
     offset=((random.random())-.5)*self.roughness 
     self.grid.make_new(center,avg+offset) 

     #top_c 
     avg=sum([self.grid.get(tl), 
       self.grid.get(tr)] 
       )/2.0 
     offset=((random.random())-.5)*self.roughness 
     self.grid.make_new(top_c,avg+offset) 

     #left_c 
     avg=sum([self.grid.get(tl), 
       self.grid.get(bl)] 
       )/2.0 
     offset=((random.random())-.5)*self.roughness 
     self.grid.make_new(left_c,avg+offset) 

     #right_c   
     avg=sum([self.grid.get(tr), 
       self.grid.get(br)] 
       )/2.0 
     offset=((random.random())-.5)*self.roughness 
     self.grid.make_new(right_c,avg+offset) 

     #bot_c 
     avg=sum([self.grid.get(bl), 
       self.grid.get(br)] 
       )/2.0 
     offset=((random.random())-.5)*self.roughness 
     self.grid.make_new(bot_c,avg+offset) 

     self.generate_heightmap((tl,top_c,left_c,center),depth+1) 
     self.generate_heightmap((top_c,tr,center,right_c),depth+1) 
     self.generate_heightmap((left_c,center,bl,bot_c),depth+1) 
     self.generate_heightmap((center,right_c,bot_c,br),depth+1) 



if __name__ == '__main__': 
    g_size=32 #//must be power of 2 
    g=Grid(g_size+1,g_size+1) 
    f=FractalHeightmap(g,1,10,max_depth=sqrt(g_size)) 
    g.render() 

si vous exécutez tel quel, vous devriez voir la palette de couleurs et de voir pourquoi il nest pas-tout à fait raison, profondeur l'évolution des pouvoirs differnt de 2 montrent en différentes façons - les valeurs 256 et plus prennent un certain temps à générer

toute aide très appréciée.

Répondre

2

désolé pour le hors-sujet, mais je veux partager un autre bon algorithme pour générer un terrain, j'ai commencé à utiliser après avoir réalisé que je n'aimais pas le diamant et le carré. Here une descrption et ici une mise en œuvre:

#/usr/bin/python 
#coding=UTF-8 

import random,math 

class HillGrid: 

    def __init__(self,KRADIUS =(1.0/5.0),ITER=200,SIZE=40): 
     self.KRADIUS = KRADIUS 
     self.ITER = ITER 
     self.SIZE = SIZE 

     self.grid = [[0 for x in range(self.SIZE)] for y in range(self.SIZE)] 

     self.MAX = self.SIZE * self.KRADIUS 
     for i in range(self.ITER): 
      self.step() 

    def dump(self): 
     for ele in self.grid: 
      s = '' 
      for alo in ele: 
       s += '%s ' % str(alo) 
      print s 

    def __getitem__(self,n): 
     return self.grid[n] 

    def step(self): 
     point = [random.randint(0,self.SIZE-1),random.randint(0,self.SIZE-1)] 
     radius = random.uniform(0,self.MAX) 

     x2 = point[0] 
     y2 = point[1]  

     for x in range(self.SIZE): 
      for y in range(self.SIZE): 

       z = (radius**2) - (math.pow(x2-x,2) + math.pow(y2-y,2)) 
       if z >= 0: 
        self.grid[x][y] += int(z) 


if __name__ == '__main__': 
    h = HillGrid(ITER=50,SIZE = 20) 
    h.dump() 
+0

En rapport avec le sujet au moins! Je vais y jeter un coup d'œil. En tant que tel, je ne cherche pas à générer un terrain réaliste, juste un ensemble de données qui a les propriétés d'une carte de hauteur générée de manière fractale. –

+0

Je pense que cela devrait faire l'affaire, j'ai utilisé celui-ci à la place du diamant et du carré car il est facile de le modifier et avec le diamant et le carré je devenais des bordures moche ^^ – lelloman

0

J'ai répondu à ma propre question, après avoir beaucoup progressé à travers la grille au fur et à mesure de sa construction.

le calcul du point central était incorrect,

centre = Coord ((tr.x-tl.x)/2, (br.y-tr.y)/2)

devrait ont été

centre = Coord (tl.x + ((tr.x-tl.x)/2), tr.y + ((br.y-tr.y)/2))

Le premier La version oublie d'ajouter la position x/y de l'origine de la sous-grille au résultat du calcul des coordonnées du point milieu.