Dynamically Generate Terrian

Is it possible using the terrian class to randomally generate terrian dynamically.

Any help or ideas greatly appreciated

If this is about how to make the terrain from functions:

This is - as far as i know - only possible by generating the images (PNMImage) and then loading them into the terrain or by making all the terrain model yourself vertex by vertex.
For the second option maybe “NURBS” could be useful for making it smooth. (for that see wikipedia and [SheetNode substitute))

If the question is about which function to use:

I’d suggest having a look at PerlinNoise (and its friends) in the reference and “Fractal landscape” as well as “perlin noise” in wikipedia.

edit:
Also in SciPy/NumPy there are tools for interpolation and such stuff eg vectorizing functions which could be useful.

I found this thread [url]Python n-dimensional simplex noise] which shows how to create perlin noise in panda3D. This would allow me to make the terrian random however the bigger and more complex question is how would I generate more terrian as reached the edge of the generated terrian.

Thanks for your help so far.

by creating a new terrain , enable the borderstiching option, create a new perlin-noise with the correct seed,and start values for x and y. and then move the new piece of terrain in its new place.

Thanks for your help so far,

I am having trouble generating perlin noise for my height-field map.

img = PNMImage(256,256)

noise1 = PerlinNoise2() 
noise1.setScale( 2.0 ) 
noise2 = PerlinNoise2() 
noise2.setScale( 5.0 ) 
noise3 = PerlinNoise2() 
noise3.setScale( 0.25 ) 
noise4 = PerlinNoise2() 
noise4.setScale( 0.125 ) 

img.write('perlinnoise.png')

When I run this code a black image is produced. What more do I need to add to get the perlin noise to work.

Once again any help is greatly appreciated,
Thanks

the problem is you dont put the values on the image…

from pandac.PandaModules import PNMImage,PerlinNoise2

img = PNMImage(256,256,1,(2<<16)-1)

noise1 = PerlinNoise2()
noise1.setScale( 2.0 )
noise2 = PerlinNoise2()
noise2.setScale( 5.0 )
noise3 = PerlinNoise2()
noise3.setScale( 0.25 )
noise4 = PerlinNoise2()
noise4.setScale( 0.125 )

def noise(x,y):
    #just an example: you could also use * instead of + or something totally different
    return noise1.noise(x,y)+noise2.noise(x,y)+noise3.noise(x,y)+noise4.noise(x,y)

for x in xrange(256):
    for y in xrange(256):
        img.setGray(x,y,noise(x/256.0,y/256.0))

img.write('perlinnoise.png') 

Thanks Praios I can now randomly generate terrain however now I need help working out how to endlessly generate terrain. This I believe will involve border stitching which ThomasEgi suggested. My main goal is to randomly generate towns as well.

For generating terrain-tiles to load from disk later you could use something like this. (its too high-frequency at the moment to be usefull)

from pandac.PandaModules import PNMImage, PerlinNoise2, StackedPerlinNoise2


noise = StackedPerlinNoise2()
noise1 = PerlinNoise2()
noise1.setScale(2.0)
noise.addLevel(noise1,1)
noise2 = PerlinNoise2()
noise2.setScale(5.0)
noise.addLevel(noise2)
noise3 = PerlinNoise2()
noise3.setScale(0.25)
noise.addLevel(noise3)
noise4 = PerlinNoise2()
noise4.setScale(0.125)
noise.addLevel(noise4)

def gen(x,y):
    a=x*1024
    b=y*1024
    #im not sure if you need an offset of 1024 or 1025 - you'll have to find out yourself
    img = PNMImage(1025, 1025, 1, (2 << 16) - 1)
    for xo in xrange(1025):
        for yo in xrange(1025):
            img.setGray(xo, yo, noise(a+xo , b+yo))
    img.write('%ix%i.png' % (x,y))

for x in xrange(10):
    for y in xrange(10):
        gen(x,y)
#as you see this takes a while this way.

To me - perlin alone looks kind of uniform. for generating good-looking terrain you will either need programs/libraries for that or you will have to take e dive into fractals which could be usefull for your city-generator too.

procedurally generating terrain on the fly seems to be to slow at the moment (at least if you use this many python-calls)

for rendering “endless” terrains borderstitching is just a detail - you have to switch it on if you use geomipterrain-tiles to fit them together.
the big thing is when and how you load new terrain-tiles and which area you set to which detail-level (or show at all).

also for towns i think generating at all is not too hard but making good-looking, believeable ones which render with usable framerates is quite a task.

I have found a number of examples of the Diamond-Square Algorithm which can be used to create fractal terrain. http://www.gameprogrammer.com/fractal.html#diamond. This is in C so it will take me a while to try and understand it. Another issue I am having is terrain.update(). When I move the camera close to the terrain my frame rate jerks because it has to update it. Would putting it in a different thread mean that the main thread would continue to render.

Thanks for your help so far.

if updating lags your terrain-parameters are not well chosen. such as blocksize or the LOD settings.

terrain.setBlockSize(32)
terrain.setFactor(40)

I am running update every second, what are the optimum parameters for updating the terrain.

parameters variate depending on your terrain. update as few as possible. every frame is ways to much. if your camera only moves slowly updating every second or even every 5 seconds would be totaly fine.

Even if I update it every 5 seconds it just lags every 5 seconds I would rather that the it would continue to render while it recalculates the terrains. Is this possible through using panda’s threads and ultimately using pythons multi-process package.

Any help on this would be greatly appreciated,
Thanks

it vastly depends on your parameters and your terrain.
enabling wire-frame render on the terrain is a good way to see what’s going on.
try to pick your terrain parameters that the terrain close to the camera (focalpoint) is highly detailed. chose a block size which allows “small” updates in the mesh. only few blocks should change while you move the camera.

it’s pretty much trial and error to get the best parameters. you could also write an auto-tune script which simulates your typical camera movement and messures the overall-performance aswell as the lag when updating.

I have tuned my terrain and I am interested to see how it runs on other computers as I have a P4 3.2ghz and a old nvidia quadro.

import direct.directbase.DirectStart
from pandac.PandaModules import Vec2, Vec3 
from pandac.PandaModules import PerlinNoise, PerlinNoise2, PerlinNoise3 
from pandac.PandaModules import PNMImage
from pandac.PandaModules import *
from direct.interval.IntervalGlobal import *
import math

Wireframe=0

def generateTask():
	print "Generating Terrian"

	img = PNMImage(257,257,1,(2<<16)-1) 

	noise1 = PerlinNoise2() 
	noise1.setScale( 2.0 ) 
	noise2 = PerlinNoise2() 
	noise2.setScale( 5.0 ) 
	noise3 = PerlinNoise2() 
	noise3.setScale( 0.25 ) 
	noise4 = PerlinNoise2() 
	noise4.setScale( 0.125 ) 

	def noise(x,y): 
		return noise1.noise(x,y)+noise2.noise(x,y)-noise3.noise(x,y)+noise4.noise(x,y) 

	for x in xrange(257): 
		for y in xrange(257):
			img.setGray(x,y,noise(x/257.0,y/257.0)) 

	img.write('perlinnoise.png')
	terrain.setHeightfield('perlinnoise.png')
	terrain.generate()

	print "Terrain Generated"

def wireframe():
	root.setRenderModeWireframe()


base.accept("r",generateTask)

terrain = GeoMipTerrain("myDynamicTerrain")

terrain.setBlockSize(8)
terrain.setNear(40)
terrain.setFar(100)
terrain.setMinLevel(1.5)
terrain.setFocalPoint(base.camera)

root = terrain.getRoot()
root.reparentTo(render)
root.setSz(32)
root.setPos(-128,-64,0)
ts = TextureStage('ts')
terrainTex= loader.loadTexture("map1.jpg")
root.setTexture(ts,terrainTex)


generateTask()

def updateTask(task):
  terrain.update()
  return task.again

taskMgr.doMethodLater(1, updateTask, "update")

dlight = DirectionalLight('dlight')
dlight.setColor(VBase4(0.8, 0.8, 0.5, 1))
dlnp = render.attachNewNode(dlight)
dlnp.setHpr(-32, -64, 0)
render.setLight(dlnp)

base.accept("w",wireframe)

run()

Press r to randomly generate the terrain and w to change to wire-frame mode.

I would like to know how fast it is running ie FPS and if you experience any lag.

Thanks

there is something miising it seems:

oops, just comment or remove these three lines

ts = TextureStage('ts') 
terrainTex= loader.loadTexture("map1.jpg") 
root.setTexture(ts,terrainTex)

Thanks for the heads up.

I have Win7, Core2Quad 2,6 GHz, Geforce9400gt.
When seeing the whole terrain i get 30-40fps but when seeing a third of the landscape at a time i get about 80fps.
I experience a small lag when the terrain changes but to me that seems ok for non-action games if its not often.

Thanks Praios,

I believe that most of my lag is related to my old hardware not the actual structure or code.

I have now (well I think, I could be completely wrong) come up with a structure or method to which I can randomly generate terrain to infinity or as powerful a your computer is.

First I will create a terrain and give it a unique name like T2. When the terrain detects a collision with the player it will then check if there are any terrains surrounding it ie T3,T4,T1,T0 if there is it will do nothing however if there isn’t it will generate new terrain and give it a number based on whether it is above, below, left or right of it. It easier to understand what I mean in this image.

The problem I am having trouble wrapping my head around is how I go about implementing the unique id or name.

I hope that you can understand what I am trying to do.
If you have any ideas on how I might achieve this I have a better more efficient way, please let me know.
Thanks

Some time ago I played with the idea of infinite terrains, too.

For the unique id I used an absolute coordinate system where each tile (located at (x,y)) was called “%ix%i” % (x, y).

What I wrote is not so well documented and Im almost sure it doesnt actually run but maybe it helps you.
I made 2 versions one generating on the fly and one paging from disc.
You got a PM.