Free Terrain Mesh system

Blitz3D Forums/Blitz3D Programming/Free Terrain Mesh system

Hi all !


I decide ti give my terrain system without occulusion system in a speciale License Agreement version. This Height Performance Terrain Mesh System is base on Tile mesh system who are child of a primary mesh.

If you want more informations ask me ...

The heightmap must be in n^2+1 pixel width (129,257,513,1025 ... )


Look at the code to use it

; ------------------------------------------------------------------------------------
; Project Title	: QTS : Quadtree Terrain System
;
; Author		: Poursin Nicolas
; Email			: Nicolas.poursin@...
;
; Version		: 1.0.0          
; Date			: 05.04.2004
; ------------------------------------------------------------------------------------


; ------------------------------------------------------------------------------------
; Terms of Use License
;
; This is a legal agreement ("License Agreement") between you And Poursin Nicolas.

;	You are permitted To:

;   - Create For free or commercial games 
;   - Free Tool
;	 
;	You are Not permitted To: 
;
;	1) Sell, resell it
;	2) Use it, in commercial tool 
;	3) Modify the products And sell it                   
; ------------------------------------------------------------------------------------


; The global who contain the terrain mesh
Global QTS_Terrain 


; Set collission state for the terrain
Const QTS_TerrainCollision = 800	


; Type that contain the patch of the terrain
Type QTS_TPatch

	Field mesh
	Field x#
	Field y#
	Field z#
	Field inView
	
End Type



; Bank used to create the terrain
Global QTS_QuadTree
Global QTS_HeightMap
Global QTS_Vertex
Global QTS_Tile

; Global information  on the terrain
Global QTS_BlockSize		; Size of Terrain Patch = 16 * QTS_BlockSize
Global QTS_HeightMapSize	; Size of the heightmap must = 2^n+1 ( 129,257,513,1025 etc ...)


;********************************************** PUBLIC FONCTION **************************************************************



;------------------------------------------------------------------------------------
; Name: 				QTS_CreateTerrain
;
; Description: Create the terrain m
;
; Arguments:	- filename$ : path to the heightmap
;				- Blocksize	: Size of the terrain patch = 16 * QTS_BlockSize
;				- EdgeError	: The Error lenght to set the number of polygons
; -----------------------------------------------------------------------------------
Function QTS_CreateTerrain( filename$ , BlockSize , EdgeError   )

	QTS_Terrain = CreateMesh()
	QTS_LoadHeightMap( filename$  )

	QTS_BlockSize = BlockSize
	QTS_NbPatch = QTS_HeightMapSize/( QTS_BlockSize*16)
	QTS_Tile = CreateBank( 64*64*4 )
	
	QTS_Roughness(EdgeError)
	QTS_CreatePatch( QTS_BlockSize )

	QTS_Texture()
	
	FreeBank QTS_QuadTree
	FreeBank QTS_HeightMap
	FreeBank QTS_Vertex

End Function

;------------------------------------------------------------------------------------
; Name: 				QTS_FreeTerrain
;
; Description: Free the terrain and all attach object
; -----------------------------------------------------------------------------------
Function QTS_FreeTerrain()

	FreeEntity QTS_Terrain
	For tt.QTS_TPatch = Each QTS_TPatch
		Delete tt
	Next
	
End Function

;------------------------------------------------------------------------------------
; Name: 				QTS_UpdateTerrain
;
; Description: Free the terrain and all attach object
;
; Arguments:	- Cam : Camera handle
;				- ViewDistance# : Distance in front of camera that terrain pathc is still visible 
; -----------------------------------------------------------------------------------
Function QTS_UpdateTerrain( cam , ViewDistance# )


	For tile.QTS_TPatch = Each QTS_TPatch

			If EntityDistance( cam, tile\mesh ) < ViewDistance# Then

				If  EntityInView( tile\mesh ,cam) Then

					ShowEntity 	tile\mesh
		
				Else
					HideEntity tile\mesh

				EndIf
			Else
				HideEntity tile\mesh
		EndIf
		
	Next
	
End Function

; This fonction return the patch mesh at one position
Function QTS_GetMesh( x,z , scalevalue# )

	patchsize# = (QTS_BlockSize * 16/2 ) * scalevalue#
 	
	For tile.QTS_TPatch = Each QTS_TPatch
		xx = EntityX( tile\mesh,True)
		zz= EntityZ( tile\mesh,True)
	
		If x>= xx - patchsize# And x < xx+ patchsize# And z>= zz - patchsize# And z < zz+ patchsize# Then
			Return tile\mesh
		EndIf
		
	Next

	Return False
	
	
End Function


; REturn the height of the terrain
Function QTS_TerrainY#(x#,z#)

	pick=LinePick(x#,200000,z#,0,-2000000,0)

	Return (PickedY())

End Function

; TExture the terrain
Function QTS_TextureTerrain( hTexture,scale#=1,level=0,BlendMode=2)

	TextureBlend hTexture,BlendMode
	ScaleTexture hTexture,scale#,scale#
	
	For tile.QTS_TPatch = Each QTS_TPatch
		EntityTexture tile\mesh,hTexture,0,level
	Next
	
End Function






;********************************************** PRIVATE FONCTION **************************************************************

Function QTS_Roughness( Error )

	
	EdgeLength = 3
	
	While EdgeLength <=17

		EdgeOffset = (EdgeLength-1)/2
		ChildOffset = (Edgelength-1)/4

		z= EdgeOffset
		While z < QTS_HeightMapSize 

			x= EdgeOffset
			While x < QTS_HeightMapSize 

				node = 0
				kill=0


				If EdgeLength>3 Then
					; top edge
					Node = QTS_GetMatrixValue( x-ChildOffset , z-ChildOffset)
					Node = QTS_MAX( Node , QTS_GetMatrixValue( x+ChildOffset , z-ChildOffset))
					Node = QTS_MAX( Node , QTS_GetMatrixValue( x+ChildOffset , z+ChildOffset))
					Node = QTS_MAX( Node , QTS_GetMatrixValue( x-ChildOffset , z+ChildOffset))
				EndIf
				

				
				If EdgeLength = 3 Or node=0 Then

					QTS_SetMatrixValue( x-EdgeOffset , z-EdgeOffset , 1)
					QTS_SetMatrixValue( x+EdgeOffset , z-EdgeOffset , 1)
					QTS_SetMatrixValue( x+EdgeOffset , z+EdgeOffset , 1)
					QTS_SetMatrixValue( x-EdgeOffset , z+EdgeOffset , 1)
				
					; top edge
					morph# = Abs(QTS_TrueHeightAtPoint#(x,z-EdgeOffset) - ((QTS_TrueHeightAtPoint#(x-EdgeOffset,z-EdgeOffset) + QTS_TrueHeightAtPoint#( x+EdgeOffset,z-EdgeOffset) ) /2))
					If morph#> Error Then
						QTS_SetMatrixValue(  x,z-EdgeOffset, 1 )
					Else
						
						If EdgeLength>3 Then


								QTS_SetMatrixValue( x,z-EdgeOffset ,  0)

						EndIf

						
						kill = kill +1
					EndIf


					; right edge
					morph# = Abs(QTS_TrueHeightAtPoint#(x+EdgeOffset,z) - ((QTS_TrueHeightAtPoint#(x+EdgeOffset,z-EdgeOffset) + QTS_TrueHeightAtPoint#( x+EdgeOffset,z+EdgeOffset) ) /2))
					If morph#> Error Then
						QTS_SetMatrixValue( x+EdgeOffset,z , 1 )
					Else
						If EdgeLength>3 Then	
							QTS_SetMatrixValue( x+EdgeOffset,z , 0 )
						EndIf
						
						
						kill = kill +1
					EndIf

	
					; bottom edge
					morph# = Abs(QTS_TrueHeightAtPoint#(x,z+EdgeOffset) - ((QTS_TrueHeightAtPoint#(x+EdgeOffset,z+EdgeOffset) + QTS_TrueHeightAtPoint#( x-EdgeOffset,z+EdgeOffset) ) /2))
					If morph#> Error Then
						QTS_SetMatrixValue( x,z+EdgeOffset, 1 )
					Else
						If EdgeLength>3 Then

								QTS_SetMatrixValue( x,z+EdgeOffset , 0 )
							
						EndIf
						kill = kill +1
					EndIf					


					; left Edge
					morph# = Abs(QTS_TrueHeightAtPoint#(x-EdgeOffset,z) - ((QTS_TrueHeightAtPoint#(x-EdgeOffset,z+EdgeOffset) + QTS_TrueHeightAtPoint#( x-EdgeOffset,z-EdgeOffset) ) /2))
					If morph#> Error Then
						QTS_SetMatrixValue( x-EdgeOffset,z, 1)
					Else
						If EdgeLength>3 Then
							QTS_SetMatrixValue( x-EdgeOffset,z , 0)
						EndIf
						kill = kill +1
					EndIf

					QTS_SetMatrixValue( x,z, 1)
					
					If kill=4 Then	
				  		; top Left To bottom Right
						morph# = Abs(QTS_TrueHeightAtPoint#(x,z) - ((QTS_TrueHeightAtPoint#(x-EdgeOffset,z-EdgeOffset) + QTS_TrueHeightAtPoint#( x+EdgeOffset,z+EdgeOffset) ) /2))
						If morph#<= Error Then
							morph# = Abs(QTS_TrueHeightAtPoint#(x,z) - ((QTS_TrueHeightAtPoint#(x+EdgeOffset,z-EdgeOffset) + QTS_TrueHeightAtPoint#( x-EdgeOffset,z+EdgeOffset) ) /2))
							If morph#<= Error Then
								QTS_SetMatrixValue( x,z , 0 )
							EndIf
						EndIf
					EndIf
						
				Else If EdgeLength>3
				
					QTS_SetMatrixValue( x , z-EdgeOffset , 1 )
					QTS_SetMatrixValue( x+EdgeOffset , z , 1 )
					QTS_SetMatrixValue( x , z+EdgeOffset , 1 )
					QTS_SetMatrixValue( x-EdgeOffset , z , 1 )	

				EndIf

				x = x + EdgeLength-1
				
			Wend

			
			z = z + EdgeLength-1
		Wend

		EdgeLength = (EdgeLength Shl 1 ) - 1

		
	Wend

	; Propagation
	For z=16 To 513-1 Step 32
		For x=16 To 513-1 Step 32
			QTS_ProcessNode( x,z, 33, False , False )
		Next
	Next
			
End Function

; Create a node of a terrain patch
Function QTS_RenderNode( x,z,EdgeLength , EdgeOffset ,surf , bRender )

	 
	; top
	If bRender Then	VC = QTS_AddVertex( x,z,surf)

	
	If bRender Then  V1 = QTS_AddVertex( x-EdgeOffset , z-EdgeOffset ,surf)
	If bRender=False Then QTS_SetMatrixValue( x-EdgeOffset , z-EdgeOffset)

	If bRender Then VE = QTS_Addvertex( x+EdgeOffset , z-EdgeOffset , surf)
	If bRender=False Then QTS_SetMatrixValue( x+EdgeOffset , z-EdgeOffset )
	
	
	zz = z-EdgeOffset
	xstart = x-EdgeOffset+1
	xend = x-EdgeOffset+EdgeLength -1 - 1
	
	For xx=xstart To xend

		If QTS_GetMatrixValue(xx,zz)>0 Then
		
			If bRender Then V2 = QTS_AddVertex( xx , zz ,surf)
			If bRender=False Then QTS_SetMatrixValue( xx , zz )
			
			If bRender Then AddTriangle surf,V1,V2,VC
			V1=V2
		EndIf
		
	Next

	If bRender Then AddTriangle surf,v1,ve,vc

	
	; bottom
	If bRender Then VC = QTS_AddVertex( x,z,surf)

	If bRender Then V1 = QTS_AddVertex( x-EdgeOffset , z+EdgeOffset ,surf)
	If bRender=False Then QTS_SetMatrixValue( x-EdgeOffset , z+EdgeOffset)

	If bRender Then VE = QTS_Addvertex( x+EdgeOffset , z+EdgeOffset , surf)
	If bRender=False Then QTS_SetMatrixValue( x+EdgeOffset , z+EdgeOffset )
	
	
	zz = z+EdgeOffset
	xstart = x-EdgeOffset+1
	xend = x-EdgeOffset+EdgeLength -1 - 1
	
	For xx=xstart To xend

		If QTS_GetMatrixValue(xx,zz)>0 Then
		
			If bRender Then V2 = QTS_AddVertex( xx , zz ,surf)
			If bRender=False Then QTS_SetMatrixValue( xx , zz )
			
			If bRender Then AddTriangle surf,V2,V1,VC
			V1=V2
		EndIf
	Next

	If bRender Then AddTriangle surf,ve,v1,vc


	; right
	If bRender Then VC = QTS_AddVertex( x,z,surf)

	If bRender Then V1 = QTS_AddVertex( x+EdgeOffset , z-EdgeOffset ,surf)
	If bRender=False Then QTS_SetMatrixValue( x+EdgeOffset , z-EdgeOffset)

	If bRender Then VE = QTS_Addvertex( x+EdgeOffset , z+EdgeOffset , surf)
	If bRender=False Then QTS_SetMatrixValue( x+EdgeOffset , z+EdgeOffset )
	
	
	xx = x+EdgeOffset
	zstart = z-EdgeOffset+1
	zend = z-EdgeOffset+EdgeLength -1 - 1
	
	For zz=zstart To zend

		If QTS_GetMatrixValue(xx,zz)>0 Then
			If bRender Then V2 = QTS_AddVertex( xx , zz ,surf)
			If bRender=False Then QTS_SetMatrixValue( xx , zz )
			
			If bRender Then AddTriangle surf,V1,V2,VC
			V1=V2
		EndIf
	Next

	If bRender Then AddTriangle surf,v1,ve,vc

	; left
	If bRender Then VC = QTS_AddVertex( x,z,surf)

	If bRender Then V1 = QTS_AddVertex( x-EdgeOffset , z-EdgeOffset ,surf)
	If bRender=False Then QTS_SetMatrixValue( x-EdgeOffset , z-EdgeOffset)

	If bRender Then VE = QTS_Addvertex( x-EdgeOffset , z+EdgeOffset , surf)
	If bRender=False Then QTS_SetMatrixValue( x-EdgeOffset , z+EdgeOffset )
	
	xx = x-EdgeOffset
	zstart = z-EdgeOffset+1
	zend = z-EdgeOffset+EdgeLength -1 - 1
	
	For zz=zstart To zend

		If QTS_GetMatrixValue(xx,zz)>0 Then
			If bRender Then V2 = QTS_AddVertex( xx , zz ,surf)
			If bRender=False Then QTS_SetMatrixValue( xx , zz )
			
			If bRender Then AddTriangle surf,V2,V1,VC
			V1=V2
		EndIf
	Next

	If bRender Then AddTriangle surf,ve,v1,vc

	
End Function

; Create a terrain patch
Function QTS_CreatePatch( BlockSize )

	QTS_NbPatch=0
	
	qts=CreateBank( 64*64*4)
	
	z=0
	ztab=0
	While z <=  QTS_HeightMapSize

		x=0
		xtab=0
		While x <= QTS_HeightMapSize

			PatchNumer = PatchNumer + 1
			
			xx# = x  + (BlockSize * 16/2 )
			zz# = z  + (BlockSize * 16/2 )

				
			TerrainPatch = CreateMesh()

			
			TerrainPatchSurface = CreateSurface( TerrainPatch )

			QTS_Vertex = CreateBank( (QTS_HeightMapSize) * (QTS_HeightMapSize) * 4)
			
			For bz=8 To Blocksize*16 Step 16
				For bx=8 To Blocksize*16 Step 16
					cx = x+bx
					cz = z+bz
					If cx<QTS_HeightMapSize And cz<QTS_HeightMapSize Then		
						QTS_ProcessNode( cx,cz, 17 , TerrainPatchSurface ,True )
					EndIf
				Next
			Next

			QTS_NbPatch = QTS_NbPatch +1
			
			FreeBank QTS_Vertex
			UpdateNormals TerrainPatch

			
			
			PositionMesh terrainpatch,-xx#,-MeshHeight(terrainpatch)/2,zz#

			
			
			EntityParent TerrainPatch,QTS_Terrain
			EntityType TerrainPatch,QTS_TerrainCollision

			
			tile.QTS_TPatch = New QTS_TPatch
			
			tile\mesh = TerrainPatch
			tile\x# = xtab * (BlockSize * 16/2 ) *2
			tile\y# = MeshHeight(terrainpatch)/2
			tile\z# = -ztab *(BlockSize * 16/2 ) *2 
 			tile\inView = False
			
			PositionEntity tile\mesh,tile\x#,tile\y#,tile\z#
			EntityPickMode tile\mesh,2

			EntityColor tile\mesh,250,250,250
			
			PokeInt QTS_Tile, ((ztab*64 + xtab)*4),Handle( tile )
			
			x = x + (BlockSize * 16)
			xtab=xtab+1
		Wend
		z = z + (BlockSize * 16)
		ztab=ztab+1
	Wend
	
End Function


; Check a Node of a terrain patch
Function QTS_ProcessNode( x,z, EdgeLength, surf , bRender )

	EdgeOffset = (EdgeLength-1)/2
	ChildOffset = (Edgelength-1)/4
		
	node = QTS_GetMatrixValue( x,z )
	
	If node=1   Then
		
		If  EdgeLength=3 Then
			QTS_RenderNode( x,z,EdgeLength , EdgeOffset ,surf ,bRender)
		Else
			; top left child
			If QTS_GetMatrixValue( x-ChildOffset,z-ChildOffset ) > 0 Then
				QTS_ProcessNode( x-ChildOffset,z-ChildOffset, EdgeLength-(Edgelength/2), surf ,bRender)
			Else
				 QTS_RenderNode(  x-ChildOffset,z-ChildOffset, EdgeLength-(Edgelength/2) , EdgeOffset-(EdgeOffset/2) ,surf,bRender)
			EndIf

			; top right child
			If QTS_GetMatrixValue( x+ChildOffset,z-ChildOffset ) > 0 Then
				QTS_ProcessNode( x+ChildOffset,z-ChildOffset, EdgeLength-(Edgelength/2), surf ,bRender)
			Else
		
			 QTS_RenderNode(  x+ChildOffset,z-ChildOffset, EdgeLength-(Edgelength/2) , EdgeOffset-(EdgeOffset/2) ,surf,bRender)

			EndIf

			; bottom left child
			If QTS_GetMatrixValue( x-ChildOffset,z+ChildOffset ) > 0 Then
				QTS_ProcessNode( x-ChildOffset,z+ChildOffset, EdgeLength-(Edgelength/2), surf,bRender)
			Else
		
			 QTS_RenderNode(  x-ChildOffset,z+ChildOffset, EdgeLength-(Edgelength/2) , EdgeOffset-(EdgeOffset/2) ,surf,bRender)
			EndIf

			; bottom right child
			If QTS_GetMatrixValue( x+ChildOffset,z+ChildOffset ) > 0 Then
				QTS_ProcessNode( x+ChildOffset,z+ChildOffset, EdgeLength-(Edgelength/2), surf,bRender)
			Else
			
				 QTS_RenderNode(  x+ChildOffset,z+ChildOffset, EdgeLength-(Edgelength/2) , EdgeOffset-(EdgeOffset/2) ,surf,bRender)
			EndIf

		EndIf
	
	Else
		
		QTS_RenderNode( x,z,EdgeLength , EdgeOffset ,surf,bRender)
		
	EndIf


	
End Function

Function QTS_AddVertex( x,z,surf)


	If PeekInt( QTS_Vertex, QTS_MatrixIndex( x,z)*4)=0 Then
		y# = QTS_TrueHeightAtPoint(x,z) *0.1
		vertex = AddVertex( surf,x,y#,-z,0,0)
		PokeInt QTS_Vertex, QTS_MatrixIndex( x,z)*4 , vertex+1

	Else
		vertex = PeekInt( QTS_Vertex, QTS_MatrixIndex( x,z)*4)-1
	EndIf
	

	
	Return Vertex
	
End Function


Function QTS_LoadHeightMap(filename$ ,shadow=False)

	
	heightmap = LoadImage( filename$ )
	
	QTS_HeightMapSize = ImageWidth( heightmap )

	QTS_HeightMap = CreateBank( (QTS_HeightMapSize) * (QTS_HeightMapSize) )
	If Not shadow Then
		QTS_QuadTree = CreateBank( (QTS_HeightMapSize) * (QTS_HeightMapSize) )
	EndIf
	

	LockBuffer ImageBuffer( heightmap)

	For z=0 To QTS_HeightMapSize-1
		For x=0 To QTS_HeightMapSize-1
			pixel = ReadPixelFast( x,z, ImageBuffer(heightmap) ) And 255
			offset = z * QTS_HeightMapSize + x
			PokeByte QTS_HeightMap, offset , pixel
			If Not shadow Then	
				PokeByte QTS_QuadTree, offset , 0
			EndIf
		Next
		
	Next

	UnlockBuffer ImageBuffer( heightmap)
	FreeImage heightmap
		
End Function

Function QTS_Texture()


	size = QTS_HeightMapSize 

	For z=0 To 63
		For x=0 To 63
			obj = PeekInt( QTS_Tile, (z*64+x)*4)
			If obj>0
				tile.QTS_TPatch = Object.QTS_TPatch( obj)
				If tile\mesh <>-1 Then

					Surface = GetSurface(tile\mesh, 1)
					Vertices = CountVertices(Surface)

					For Vertex = 0 To Vertices-1

						VX# = EntityX#(tile\mesh) +  (VertexX#(Surface, Vertex) + (4 * 16 )/2)
						VZ# = EntityZ#(tile\mesh) +  (VertexZ#(Surface, Vertex) -  (4 * 16 )/2)
						VertexTexCoords Surface, Vertex, VX#/size, -VZ#/size, 0,0
						
					Next
			
				EndIf					
			EndIf
		Next
	Next
	
	
End Function

Function QTS_GetMatrixValue( x,z )

	value=PeekByte(QTS_QuadTree, QTS_MatrixIndex( x,z))
	
	Return value
	
End Function

Function QTS_SetMatrixValue( x,z , value=1 )

		
	PokeByte QTS_QuadTree , QTS_MatrixIndex( x , z) , value


End Function

Function QTS_MatrixIndex( x,z)

	Return (( z * QTS_HeightMapSize) + x)
	
End Function

Function QTS_Max#(v1#,v2#)

	If v1#>V2# Then
		Return v1#
	Else
		Return v2#
	EndIf
	
End Function

Function QTS_TrueHeightAtPoint#( x, z)

	value#=PeekByte(QTS_HeightMap, (z * QTS_HeightMapSize) + x)
	
	Return value#
	
End Function






Eole,

I'm a blithering idiot -- any chance for some example usage to look at??

er.... Ditto :)

Oki a little example ... th QTS_V1.bb is the engine

Include "QTS_V1.bb"

Graphics3D 800,600,32,2
SetBuffer BackBuffer()


; Creating the terrain
QTS_CreateTerrain( "demo\height01.jpg",4,5)
ScaleEntity QTS_Terrain,10,10,10
PositionEntity QTS_Terrain,-513*10/2,0,513*10/2
	
; Add texture to it
texture = LoadTexture("demo\grass.bmp")
QTS_TextureTerrain(texture,0.5,1)

texture = LoadTexture("demo\detail.bmp")
QTS_TextureTerrain(texture,0.01,0)


; Add object on patch
treee = LoadMesh("demo\tree.b3d")

ScaleMesh treee,0.2,0.2,0.2
HideEntity treee

For i=0 To 1000

	x = Rnd(-256*10 , 256*10)
	z = Rnd(-256*10 , 256*10)
	

	; Get the mesh of this position
	parent  = QTS_GetMesh(x ,z,10 )

 	; Get height a point x,z
	y# = QTS_TerrainY#(x,z)
	tmp = CopyEntity( treee )
	
	; The patch will be the parent 
	PositionEntity tmp,x,y,z
	EntityParent tmp,parent

Next



; Camera
Global AxisCamera = CreatePivot()
Global camera=CreateCamera(AxisCamera)

PositionEntity camera,0,1.78,0
CameraRange Camera,1,10000

CameraClsColor camera,50,0,200
PositionEntity AxisCamera,0,160,0
EntityRadius AxisCamera,2
EntityType AxisCamera,1


; Light
light = CreateLight()
PositionEntity light,1280,100,1280


CameraFogColor camera,52,57,40
CameraFogRange camera,800,1500
CameraFogMode camera,True


Tp_OldTime = MilliSecs()





HidePointer()

;HideEntity QTS_Terrain


While Not KeyHit(1)

	QTS_UpdateTerrain( camera , 2000  )


        renderworld()


	Flip False

	
Wend


Eole,

Blitz keeps crashing with the demo.
It doesn't seem to like my heightmap.

Can you provide the heightmap you used when you tested the demo?
I keep getting an "Offset out of range" error
on:
Function QTS_MatrixIndex( x,z)
Return (( z * QTS_HeightMapSize) + x)
End Function

QTS_HeightMapSize value is: 256

Read my post you must use a n^2+1 Heightmap size :

Heightmap size :
- 257
- 513
- 1025

Try with an heightmap of 513X513

Would not work with 257x257 only got it to run at 513x513. I did notice that there are visible lines between each patch - I assume this is since the normals are not calculated correctly at the joins?

nice though :) How does it's speed compare to blitz terrains? have you done any tests?

Hi, It also looks like you create a new surface for each patch... Is this not bad practice?

Ok !

>>Would not work with 257x257
I see, the lib it's not really finish, somewhere there is a FOR NEXT with 513-1 step this walue must be egal at the width oh the heightmap not only 513

>> I assume this is since the normals are not calculated correctly at the joins?
Yes, I use the build in update normal

>> How does it's speed compare to blitz terrains? have you done any tests?
It's little more speed than a blitz terrain, the objectiv it's to manage a lot of range object

You can attach object on each patch of the terrain, so when a patch is hide, all the child are hide too .. With this, you can't test all the objects on terrain :-)

After when a patch is visible you can test if the child are in a correct distance from the camera etc ...

>Hi, It also looks like you create a new surface for each >patch... Is this not bad practice?
Actualy I stop it, I work on 3D Space FPS Shooter :-) alone :-(

You will find lovely young french ladies to work on your space shooter.

You mind if I "try" and make some improvements?

Do you have samples of Height, grass, detail, and tree?
So we can see what it looks like with the right images.

Have added simple movement code to the example

Include "QTS_V1.bb"

Graphics3D 800,600,32,2
SetBuffer BackBuffer()


; Creating the terrain
QTS_CreateTerrain( "heightmaptest.png",4,5)
ScaleEntity QTS_Terrain,10,10,10
PositionEntity QTS_Terrain,-513*10/2,0,513*10/2
	
; Add texture to it
texture = LoadTexture("Grass.jpg")
QTS_TextureTerrain(texture,0.5,1)

texture = LoadTexture("detail.jpg")
QTS_TextureTerrain(texture,0.01,0)


; Add object on patch
;treee = LoadMesh("demo\tree.b3d")

;ScaleMesh treee,0.2,0.2,0.2
;HideEntity treee

For i=0 To 1000

	x = Rnd(-256*10 , 256*10)
	z = Rnd(-256*10 , 256*10)
	

	; Get the mesh of this position
	parent  = QTS_GetMesh(x ,z,10 )

 	; Get height a point x,z
	y# = QTS_TerrainY#(x,z)
	;tmp = CopyEntity( treee )
	
	; The patch will be the parent 
	;PositionEntity tmp,x,y,z
	;EntityParent tmp,parent

Next



; Camera
Global AxisCamera = CreatePivot()
Global camera=CreateCamera(AxisCamera)

PositionEntity camera,0,1.78,0
CameraRange Camera,1,10000

CameraClsColor camera,50,0,200
PositionEntity AxisCamera,0,160,0
EntityRadius AxisCamera,2
EntityType AxisCamera,1


; Light
light = CreateLight()
PositionEntity light,1280,100,1280


CameraFogColor camera,52,57,40
CameraFogRange camera,800,1500
CameraFogMode camera,True


Tp_OldTime = MilliSecs()





HidePointer()

;HideEntity QTS_Terrain


While Not KeyHit(1)

	QTS_UpdateTerrain( camera , 2000  )

	If KeyDown(30) MoveEntity camera,0,2,0
	If KeyDown(44) MoveEntity camera,0,-2,0
	If KeyDown(200) MoveEntity camera,0,0,5
	If KeyDown(208) MoveEntity camera,0,0,-5
	If KeyDown(203) TurnEntity camera,0,1,0
	If KeyDown(205) TurnEntity camera,0,-1,0

        RenderWorld()


	Flip False

	
Wend