Code archives/3D Graphics - Mesh/Random Tileable Terrain Generator

This code has been declared by its author to be Public Domain code.

Download source code

Random Tileable Terrain Generator by Delerna2005
Uses the diamond square methodology to generate random terrain meshes that are completely tileable in all four directions. You can vary the number of vertices in the terrain as well as the ruggedness and the evenness of the transitions in the ruggedness,if that senetence makes sense!!! Use it/change it however you like, I give it to the Blitz community.
;Changeable Parameters
GridSize%=9; Must be a 2^n+1
Landform#=10;The bigger the number the greater the difference in heights between highspots and lowspots
Smoothness#=6;The bigger the number the more smoothly the transition between highspots and low spots will occur


;Setup the 3D environment
Graphics3D 1024,700,16,2
SetBuffer BackBuffer()
Dim vert(GridSize,GridSize)
WireFrame True
AmbientLight(255,255,255)
cam=CreateCamera()
MoveEntity cam, 0, 50, -140 ; Our camera...
CameraRange cam,1,10000

;Create 4 copies of the same terrain and position them to show that they are tileable
RandomTerrain=TileableRandomDiamondSquareTerrain(GridSize,Landform,Smoothness)
RandomTerrain2=CopyMesh(RandomTerrain,RandomTerrain)
PositionEntity(RandomTerrain2,-45,0,0)
RandomTerrain3=CopyMesh(RandomTerrain,RandomTerrain)
PositionEntity(RandomTerrain3,-45,0,45)
RandomTerrain4=CopyMesh(RandomTerrain,RandomTerrain)
PositionEntity(RandomTerrain4,0,0,45)


While Not KeyDown(1)
	Cls
	TurnEntity RandomTerrain,0,0.5,0
	RenderWorld 
	Flip 
Wend
End
Function TileableRandomDiamondSquareTerrain(GridSize,Range#,Smoothness#)
	NumSquares=1; We start with 1 square that is the size of the mesh
	XS=1
	Iterations#=Log2(GridSize-1) ;In the loops we work with progressively smaller and smaller squares
											  ;This is the number of times to execute the loops to get to the smallest
											  ;possible square defined by the vertices.
	Terrain=CreateGrid(GridSize,GridSize)
	surf=GetSurface(Terrain,1)
	SeedRnd (MilliSecs()) 
	For i= 1 To iterations
		s=((GridSize-1)/XS)
		For z=1 To NumSquares/XS
		For x=1 To NumSquares/XS
			;Get the corner vertices of the square defined by z,x
			v1=0+(s*(x-1))+s*(z-1)*GridSize  :  v2=v1+s  :  v3=v1+s*GridSize  :  v4=v3+s
			;Now get the centre vertice of the z,x square and raise or lower it by a random amount
			vc=v1+s/2+(s/2)* GridSize
			AvgHeight=(VertexY(surf,v1)+VertexY(surf,v2)+VertexY(surf,v3)+VertexY(surf,v4))/4
			VertexCoords surf,vc,VertexX(surf,vc),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,vc)
			
			;next we get the centre vertice of the left edge of the z.x square and raise or lower it by a random amount
			v5=vc-s/2  :  v15=v5-(s/2)*GridSize  :  v25=v15+(s/2)  :  v35=v5+(s/2)
			AvgHeight=(VertexY(surf,v15)+VertexY(surf,v25)+VertexY(surf,v35))/3
			VertexCoords surf,v5,VertexX(surf,v5),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,v5)
			;if the vertex is on the left edge of the mesh then set the vertex on the right edge to the same height to ensure tileability
			If v5*1.0/gridsize*1.0=Int(v5/gridsize) Then
				ve=v5+gridsize-1:VertexCoords surf,ve,VertexX(surf,ve),VertexY(surf,v5),VertexZ(surf,ve)
			End If
			
			;next we get the centre vertice of the top edge of the z.x square and raise or lower it by a random amount
			v6=vc-(s/2)*GridSize  :  v16=v6+(s/2)   :  v26=v16+(s/2)*GridSize  :  v36=v26-(s/2)			
			AvgHeight=(VertexY(surf,v16)+VertexY(surf,v26)+VertexY(surf,v36))/3
			VertexCoords surf,v6,VertexX(surf,v6),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,v6)
			;if the vertex is on the top edge of the mesh then set the vertex on the bottom edge to the same height to ensure tileability
			If v6<GridSize Then
				ve=v6+gridsize*(gridsize-1):VertexCoords surf,ve,VertexX(surf,ve),VertexY(surf,v6),VertexZ(surf,ve)
			End If

			;next we get the centre vertice of the right edge of the z.x square and raise or lower it by a random amount
			v7=vc+s/2  :  v17=v7-(s/2)   :  v27=v17+(s/2)*GridSize  :  v37=v27+(s/2)
			AvgHeight=(VertexY(surf,v17)+VertexY(surf,v27)+VertexY(surf,v37))/3
			VertexCoords surf,v7,VertexX(surf,v7),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,v7)
			;if the vertex is on the right edge of the mesh then set the vertex on the left edge to the same height to ensure tileability
			If ((v7-gridsize+1)*1.0)/(gridsize*1.0)=Int((v7-gridsize+1)/(gridsize-1))  Then
				ve=v7-gridsize+1:VertexCoords surf,ve,VertexX(surf,ve),VertexY(surf,v7),VertexZ(surf,ve)
			End If
			
			;next we get the centre vertice of the bottom edge of the z.x square and raise or lower it by a random amount
			v8=vc+(s/2)*GridSize  :  v18=v8-(s/2)*GridSize  :  v28=v18+(s/2)  :  v38=v8+(s/2)
			AvgHeight=(VertexY(surf,v17)+VertexY(surf,v27)+VertexY(surf,v37))/3
			VertexCoords surf,v8,VertexX(surf,v8),Rand(AvgHeight-Range,AvgHeight+Range),VertexZ(surf,v8)
			;if the vertex is on the top edge of the mesh then set the vertex on the bottom edge to the same height to ensure tileability
			If v8>GridSize*(gridsize-1) Then
				ve=v8-gridsize*(gridsize-1):VertexCoords surf,ve,VertexX(surf,ve),VertexY(surf,v8),VertexZ(surf,ve)
			End If
			Next
		Next
		NumSquares=NumSquares*4
		xs=xs*2
		Print numsquares
		range=range/smoothness
	Next
	Return terrain
End Function
Function CreateGrid(x=9,z=9,w=5,h=5)
	mesh=CreateMesh()
	surf=CreateSurface(mesh)
	
	For xl=0 To x-1
		v=AddVertex(surf,xl*w,0,0)
		vert(xl,0)=v
	Next
	
	For zl=1 To z-1
		For xl=0 To x-1
			v=AddVertex(surf,xl*w,0,zl*-h)
			vert(xl,zl)=v
			If xl>0 Then
				AddTriangle surf,vert(xl,zl),vert(xl-1,zl),vert(xl,zl-1)
				AddTriangle surf,vert(xl,zl-1),vert(xl-1,zl),vert(xl-1,zl-1)					
			End If
			
		Next
	Next
	Return mesh
End Function
Function Log2# ( x# )
	Return Log( x ) / Log( 2 ) 
End Function

Comments

Delerna2006
IMPROVED
1) Previous version didn't really work as intended. This has been corrected
2) The grid of 2X2 meshes now automatically position themselves automatically to suit the size of the idividual meshes
3) Previous version could produce jagged terrains. A smothing function has been added to even out the transitions from high spots to low spots
4) The vertices are now colored in relation to their height. Black for lowest vertices through shades of green then yellow and on to white for the highest vertices


The terrains are random so you may need to run the program a few times to get a good one. Also a mesh save function might be a good addition, i'll get around to writing one someday, just experimenting at the moment.

If you like this, or it is usefull, or you have suggestions then make a comment and I will continue to post improvements




Ryudin2008
Great code! I'm going to try to add a heightmap saving function to it to export the good maps and use them in my games.


plash2008
blitzmax, non-superstrict (minib3d):



Code Archives Forum