Terrain generator - Initial groundwork


(BluePrintRandom) #1

I remade my terrain editor from scratch, and commented it out a bit, here it is so far.


import bge
from mathutils import Vector
import mathutils




def main():


    cont = bge.logic.getCurrentController()
    own = cont.owner
    
    # create empty entry for each grid pos
     
    if 'TerrainDict' not in own:
        TerrainDict = {}
        
        for x in range(10):
            for y in range(10):
                pos = [x,y]
                
                key = str(pos)
                
                TerrainDict.update( { key:[pos] } )
                
        own['TerrainDict']=TerrainDict
    
    
    # create a tile for each entry and libnew the mesh
    
    elif 'World' not in own:
        world = []
        for key in own['TerrainDict']:
            added = own.scene.addObject('Tile',own,0)
            Pos = own['TerrainDict'][key][0]
            added.worldPosition =[ Pos[0]-5,Pos[1]-5,0]
            meshName = "Tile_"+str(own['Tiles'])
            own['Tiles']+=1
            added['NewMeshName']=meshName
            mesh = bge.logic.LibNew(meshName,"Mesh",[added.meshes[0].name])
            print(mesh)
            
            added.replaceMesh(mesh[0],1,0)
        
            world.append([key,added])
            
        own['World'] = world
        print('Created world')    
   
              
            
    # build kd tree used to get all overlapping vertex
               
    elif 'KdTree' not in own:
        print('Building vertex set')
        Master = []
        for object in own['World']:
            mesh = object[1].meshes[0]
            for index in range(mesh.getVertexArrayLength(0)):
                vertex = mesh.getVertex(0, index)
                Master.append([vertex,object[1]])
                
        


        
        print('intialize tree')
        kd = mathutils.kdtree.KDTree(len(Master))
        


        for index in range(len(Master)):
            owner = Master[index][1]
            vertexLocal = Master[index][0].XYZ 
            worldVector = owner.worldPosition+owner.worldOrientation*vertexLocal
            
            kd.insert( worldVector , index)


        kd.balance()
        own['KdTree']=kd
        own['Master']=Master
        print('created tree')
        
    
    
    #generate a list of vertex for each point in space 
        
    elif 'Overlap' not in own:
        overlap = {}
        #get overlapping vertex list
        # Find points within a radius of the 3d cursor
        for data in own['Master']:
            
            pos = data[0].XYZ
            owner = data[1]
            pos = owner.worldTransform*Vector(pos) 
            
            
            #min must be smaller than dist between vertex
            
            min = .005
            
            for (co, index, dist) in own['KdTree'].find_range(pos, min):
                key = str([pos[0],pos[1]])
                owner = own['Master'][index][1]
                vertex = own['Master'][index][0]
                
                #if you don't have a entry make one
                if key not in overlap:
                    
                    overlap.update({ key:[[vertex,owner]] } )
                    
                #if you do have a entry just add to it    
                else:
                    
                    dat = overlap[key]
                    dat.append([vertex,owner])
                    overlap[key]=dat
                    
                    
                    
        own['Overlap']= overlap    
        print('Created overlap list')
        
        
    #Apply Noise    
    elif 'Noise' not in own:
        own['Noise']=True
        print('Creating noise')
        for key in own['Overlap']:
            data = own['Overlap'][key]
            pos = eval(key)
            pos = Vector([pos[0],pos[1],0])
            
            print(pos)
            
            
            Noise = mathutils.noise.fractal(pos, .25, .1 , 4, mathutils.noise.types.STDPERLIN)
            for vertexDat in data:
                print(vertexDat)
                host = vertexDat[1]
                vertex = vertexDat[0]
                pos1 = vertex.XYZ
                pos1.z = Noise
                vertex.XYZ = pos1       
                    
                   




           
                    
                     
            
                
                    
main()



I use a kdtree to calculate the overlapping vertex,

Attachments

Kd_terrain_Gen.blend (535 KB)


(BluePrintRandom) #2

just noticed I forgot to erase many prints.

much faster now

Attachments

Kd_terrain_Gen_2.blend (535 KB)


(BluePrintRandom) #3

Here is a ‘over time’ version that

  1. generates world
  2. builds trees and overlap dictionary
  3. applies noise over time, occasionally repairing border normals
  4. applies erosion
  5. fixes normals 1 last time

Attachments

Kd_terrain_Gen_over_time.blend (606 KB)


(BluePrintRandom) #4

played with vertex color,

next up is editing the vertex in a radius of a agent,

and finally stream to / from disk once BP_Player - bidirectional communication protocol is in.

Attachments

Kd_terrain_Gen_over_time_2.blend (769 KB)


(BluePrintRandom) #5

ok this is actually super useful now :smiley:

enjoy!

Attachments

Kd_terrain_Gen_over_time_islands.blend (903 KB)


(Lostscience) #6

what about dynamic terrain loading?


(BluePrintRandom) #7

once BP_Player bi-directional streaming lands :smiley:


(Lostscience) #8

okay I will wait


(BluePrintRandom) #9

for now when the terrain loads in all the way, you should be able to batch it all to 1 render in upbge

this should allow a considerable terrain size.

found a second noise method.

D = vertex xy distance from center of under monkey.

subtracting D from vertex.z makes a slope away from the center(aka mountain)

applying a cos to this value as it slopes + the terrain perlin noise makes really nice islands.


(BluePrintRandom) #10

now terrain object push themselves in a unused state
obj.state = 2

also just before turning off logic meshes are batched.

also added mouse orbit

edit: forgot to mention it also sets up reinstancePhysicsMesh() unique for each tile

Attachments

Kd_terrain_Gen_over_time_islands_2.blend (844 KB)


(Lostscience) #11

what is your framerate?i get a framerate of 8 on our hewletpackard desktop.


(BluePrintRandom) #12

60 - Nvidia 850_ish

however I need to do some testing, batching does not appear to be helping the framerate.

any errors or anything in the console?



(Lostscience) #13

let us know when you have done that.


(BluePrintRandom) #14

your video card may not support batching, or your system may just not be able to handle this many unique meshes in the memory.

it’s hit and miss with integrated gpu unless its nvidia (from my experience)
intel and amd may be catching up soon though from what I hear.

is your console printing any errors ?

grab suzzane ?
terrainMonkey

the property length determine how many meshes are used.

12x12 and bigger work without adjusting the equations


(Lostscience) #15

what do you mean by by grab suzzane or terrain monkey?

Read prefs: C:\Users\barbara\AppData\Roaming\Blender Foundation\Blender\2.78\config\userpref.blend
found bundled python: C:\Users\barbara\Desktop\Release\2.78\python
addon not found: 'import_runtime_mhx2'
Read blend: C:\Users\barbara\Desktop\Kd_terrain_Gen_over_time_islands_2.blend
Blender Game Engine Started
Created world
Building vertex set
intialize tree
created tree
Created overlap list
Merged
Blender Game Engine Finished