The 3D grid

Blitz3D Forums/Blitz3D Programming/The 3D grid

BLaBZ(Posted 2007) [#1]
Im trying to create a 3d grid but unfortunately I haven't found the brain power to pull it off yet.

Each grid square needs the capability of being hidden/deleted/removed.

Im not sure how I would create a 1000x1000 grid with each square being independently removable.

Any Ideas?

Here's my start, there's not much to it.

Graphics3D 400,400,16,2

SetBuffer BackBuffer()


;;;;Grid Array//Determines how many squares in the grid
Dim mapgrid(1000,1000)
;;;;The size of each square
Global gridindex = 20




cam1 = CreateCamera()
CameraViewport cam1,0,0,400,400
light1 = CreateLight()




;;;CreateGrid Function
CreateGrid()

While Not KeyHit(1)


UpdateWorld 
RenderWorld

FPS()

Flip
Cls


Wend


;;;;;;Creates a map mesh grid
Function CreateGrid()

shroud = CreateMesh()

   s = CreateSurface(shroud)
	AddVertex s,-10,+10,+100:AddVertex s,+10,+10,+100
	AddVertex s,-10,-10,+100:AddVertex s,+10,-10,+100
	AddTriangle s,0,1,2:AddTriangle s,2,1,3


End Function


;;;;;;//FPS
Global fpstime,fpscount,fps
Function FPS()
fpscount=fpscount+1
If MilliSecs()>fpstime Then 
    fpstime=MilliSecs()+1000
    fps=fpscount
    fpscount=0
EndIf 
Text 10,0,"FPS: "+fps
End Function
;;;;;\\FPS



PowerPC603(Posted 2007) [#2]
Graphics3D 800,600,0,2

SetBuffer BackBuffer()

Const MapX = 100
Const MapZ = 100
Const GridSize = 2

;;;;Grid Array//Determines how many squares in the grid
Dim mapgrid(MapX,MapZ)

For z = 0 To MapZ-1
	For x = 0 To MapX-1
		mapgrid(x,z) = Rand(0,1)
	Next
Next

cam1 = CreateCamera()
AmbientLight 255, 255, 255
PositionEntity cam1, 0, 20, 0

gridmesh = CreateGrid()

While Not KeyHit(1)
	If KeyDown(200) Then MoveEntity cam1, 0, 0, 1
	If KeyDown(208) Then MoveEntity cam1, 0, 0, -1
	If KeyDown(203) Then TurnEntity cam1, 0, 1, 0
	If KeyDown(205) Then TurnEntity cam1, 0, -1, 0

	; If you want to test mesh-generating speed, replace keyhit(57) by keydown(57), then every frame a new random mesh will be generated
	; while holding down the spacebar
	If KeyHit(57) Then
		; Create a random tiled map (place new random numbers in the array)
		For z = 0 To MapZ-1
			For x = 0 To MapX-1
				mapgrid(x,z) = Rand(0,1)
			Next
		Next

		; Remove the mesh from memory
		FreeEntity gridmesh
		; Re-create the mesh
		CreateGrid()
	EndIf

	UpdateWorld 
	RenderWorld

	FPS()
	Text 10, 20, "Tris rendered: " + TrisRendered()

	Flip
	Cls
Wend



Function CreateGrid()
	Local mesh = CreateMesh()
	Local surf = CreateSurface(mesh)

	For z = 0 To MapZ-1
		For X = 0 To MapX-1
			If mapgrid(x,z) = 1 Then
				CreateTile(surf,x,z)
			EndIf
		Next
	Next

	Return mesh
End Function

Function CreateTile(surf, x, z)
	v0 = AddVertex(surf, (x*GridSize)+((GridSize/2)*(-1)), 0, (z*GridSize)+((GridSize/2)))
	v1 = AddVertex(surf, (x*GridSize)+((GridSize/2)), 0, (z*GridSize)+((GridSize/2)))
	v2 = AddVertex(surf, (x*GridSize)+((GridSize/2)), 0, (z*GridSize)+((GridSize/2)*(-1)))
	v3 = AddVertex(surf, (x*GridSize)+((GridSize/2)*(-1)), 0, (z*GridSize)+((GridSize/2)*(-1)))
	t0 = AddTriangle(surf, v0, v1, v3)
	t1 = AddTriangle(surf, v1, v2, v3)
End Function



;;;;;;//FPS
Global fpstime,fpscount,fps

Function FPS()
	fpscount=fpscount+1
	If MilliSecs()>fpstime Then 
		fpstime=MilliSecs()+1000
		fps=fpscount
		fpscount=0
	EndIf 
	Text 10,0,"FPS: "+fps
End Function
;;;;;\\FPS

This code generates a mesh with size 100x100 (1000x1000 creates a MAV, because meshes are limited to 65535 vertices) as one big mesh.
It creates one mesh and adds vertices to it to generate the entire mesh, based on the value in the corresponding index in the array.
First the code places random values (0 or 1) in the array.
The the CreateGrid loops through the array and if it sees "1", it creates a tile in the big mesh.
If it's 0, do nothing.

You can move the camera using the up/down arrowkeys, and turn the camera using left/right arrowkeys.
When you hit the spacebar, the program places new random values in the array, frees the current big mesh and re-creates the mesh.
You will see that this works very fast, as continued hitting the spacebar doesn't even slow down.
If you want to create a map of size 1000x1000, I suggest that you create 100 big meshes, each of size 100x100, and place them next to eachother.
This way you reduce surface-count (this big mesh has only 1 surface).
If you where to create 1000x1000 seperate meshes, then you would have 1000.000 meshes and thus 1000.000 surfaces and your computer will crawl while rendering that much surfaces.


BLaBZ(Posted 2007) [#3]
Thanks for the code, you must have been doing this for awhile.

Some of the triangles appear backwards and show up black. I messed around for a few hours and managed to get what I was looking for.

Something like this


Graphics3D 400,400,16,2

SetBuffer BackBuffer()

;;;;The size of each square
Global gridindex# = 20.0;;20.0 is the actual size, divided by 2 to represent the + side of the x/y axis and the - side of x/y
Global gridsize = (gridindex#/2.0)
Global gridx = 20,gridy = 10;;;;how many grid squares

;;;Use this to center the entire grid to the screen
Global centerx = (gridx*gridsize)/2
Global centery = (gridy*gridsize)/2

;;;;Grid Type
Type grid
	Field mesh
	Field surface
	Field ispicked
End Type 
;;;;Grid Array//Determines how many squares in the grid
Dim mapgrid(gridx,gridy)


;Environmental variables
Global cam1,light1
;setup camera and light
cam1 = CreateCamera()
CameraViewport cam1,0,0,400,400
light1 = CreateLight()




;;;CreateGrid Function
CreateGrid(gridsize)

While Not KeyHit(1)


PickAndKill()

UpdateWorld 
RenderWorld

FPS()

 
Flip
Cls

Wend

;;;;create grid according to dimensions
Function CreateGrid(size)
For x = 1 To (gridx - 1)
	For y = 1 To (gridy - 1)
		newgrid.grid = New Grid
		newgrid\mesh = CreateMesh()
		newgrid\surface = CreateSurface(newgrid\mesh)
	
		AddVertex newgrid\surface,-size,+size,+100:AddVertex newgrid\surface,+size,+size,+100
		AddVertex newgrid\surface,-size,-size,+100:AddVertex newgrid\surface,+size,-size,+100
		AddTriangle newgrid\surface,0,1,2:AddTriangle newgrid\surface,2,1,3
	
	
		PositionEntity newgrid\mesh,(x*gridsize) - centerx,(y*gridsize) - centery,100
		EntityPickMode newgrid\mesh,2
	Next
	
Next 

End Function 

;;Click and kill each grid square
Function PickAndKill()
CameraPick(cam1,MouseX(),MouseY())
PickedEnt = PickedEntity()
	If MouseDown(1)
		If PickedEnt <> 0 
			For tile.grid = Each grid
				If PickedEnt = tile\mesh
					FreeEntity tile\mesh				
			EndIf
		Next
	EndIf
EndIf
End Function

;;;;;;//FPS
Global fpstime,fpscount,fps
Function FPS()
fpscount=fpscount+1
If MilliSecs()>fpstime Then 
    fpstime=MilliSecs()+1000
    fps=fpscount
    fpscount=0
EndIf 
Text 10,0,"FPS: "+fps
End Function
;;;;;\\FPS


Yours appears to render much faster then this code. I'm wondering if I could some how get the effect and visuals of this code with the speed of yours?


PowerPC603(Posted 2007) [#4]
Actually, I began with this just a week ago. :-)

This code adds picking to the program.
It creates an infinity plane which is pickable, but entityalpha is set to 0 to make in invisible.
I did it this way to be able to add tiles to the big mesh too, instead of only removing them.
Graphics3D 800,600,0,2

SetBuffer BackBuffer()

Const MapX = 100
Const MapZ = 100
Const GridSize = 2

;;;;Grid Array//Determines how many squares in the grid
Dim mapgrid(MapX,MapZ)

For z = 0 To MapZ-1
	For x = 0 To MapX-1
		mapgrid(x,z) = Rand(0,1)
	Next
Next

; Create an endless plane (used to do the picking), move it down a bit, set a different color and set pickmode
plane = CreatePlane()
MoveEntity plane, 0, -0.1, 0
EntityColor plane, 255, 0, 0
EntityPickMode plane, 2
EntityAlpha plane, 0

; Create camera and position it above the world
cam1 = CreateCamera()
AmbientLight 255, 255, 255
PositionEntity cam1, 100, 100, 100
TurnEntity cam1, 90, 0, 0

; Create a big mesh where each tile is created based on the value in the array
Global gridmesh = CreateGrid()
Global texture = LoadTexture("texture.jpg")
EntityTexture gridmesh, texture

While Not KeyHit(1)
	If KeyDown(203) Then MoveEntity cam1, -1, 0, 0
	If KeyDown(205) Then MoveEntity cam1, 1, 0, 0
	If KeyDown(200) Then MoveEntity cam1, 0, 1, 0
	If KeyDown(208) Then MoveEntity cam1, 0, -1, 0
	If KeyDown(201) Then MoveEntity cam1, 0, 0, 1
	If KeyDown(209) Then MoveEntity cam1, 0, 0, -1

	If MouseHit(1) Then
		PickedEnt = CameraPick(cam1, MouseX(), MouseY())
		; Calculate which tile to be switched on/off
		x = PickedX() / GridSize
		z = PickedZ() / GridSize
		If (x>= 0) And (x<=MapX) And (z>=0) And (z<=MapZ) Then
			; Toggle the tile on/off
			If mapgrid(x,z) = 1 Then mapgrid(x,z) = 0 Else mapgrid(x,z) = 1
			; Delete the big mesh
			FreeEntity gridmesh
			; Re-create the big mesh
			gridmesh = CreateGrid()
			; Apply the texture to it
			EntityTexture gridmesh, texture
		EndIf
	EndIf

	UpdateWorld 
	RenderWorld

	FPS()
	Text 10, 20, "Tris rendered: " + TrisRendered()

	Flip
	Cls
Wend



Function CreateGrid()
	Local mesh = CreateMesh()
	Local surf = CreateSurface(mesh)

	For z = 0 To MapZ-1
		For X = 0 To MapX-1
			If mapgrid(x,z) = 1 Then
				CreateTile(surf,x,z)
			EndIf
		Next
	Next

	Return mesh
End Function

Function CreateTile(surf, x, z)
	v0 = AddVertex(surf, (x*GridSize)+((GridSize/2)*(-1)), 0, (z*GridSize)+((GridSize/2)), 0, 0)
	v1 = AddVertex(surf, (x*GridSize)+((GridSize/2)), 0, (z*GridSize)+((GridSize/2)), 1, 0)
	v2 = AddVertex(surf, (x*GridSize)+((GridSize/2)), 0, (z*GridSize)+((GridSize/2)*(-1)), 1, 1)
	v3 = AddVertex(surf, (x*GridSize)+((GridSize/2)*(-1)), 0, (z*GridSize)+((GridSize/2)*(-1)), 0, 1)
	t0 = AddTriangle(surf, v0, v1, v3)
	t1 = AddTriangle(surf, v1, v2, v3)
End Function



;;;;;;//FPS
Global fpstime,fpscount,fps

Function FPS()
	fpscount=fpscount+1
	If MilliSecs()>fpstime Then 
		fpstime=MilliSecs()+1000
		fps=fpscount
		fpscount=0
	EndIf 
	Text 10,0,"FPS: "+fps
End Function
;;;;;\\FPS


By a quick peek at your code, it seems that you create each tile as a seperate mesh, that's why your code renders slower, as it has much more seperate meshes and seperate surfaces.

My code creates one big mesh, and each tile's vertices and triangles are added to it.
It also adds UV coords to the vertices and applies a texture on the mesh.

Now the camera floats above the mesh, looking down.
Move the camera with up/down/left.right, and zoom in/out using pageup/pagedown.
Clicking will toggle the tile on/off.


BLaBZ(Posted 2007) [#5]
This is excellent, its taking me awhile to read through and understand everything but this is exactly what I need.

Out of curiosity, do you interpret code pretty quickly since you started coding?


PowerPC603(Posted 2007) [#6]
I programmed some stuff in Blitz3D and Visual Basic and I've been learning about programming since I was 8 years old (now 28).
I didn't use all my free time to code though, but I learn stuff quickly that makes sense.
Some things are chinese to me too, but after some testing, most of the time I start to grasp it.

And I'm thinking of creating a game which requires the same stuff as I've posted here, but a bit more difficult than this.
In my game, I need to generate the terrain while you play, same as the roads and buildings (dynamic loading like GTA does) as I hate loading screens. :-)

Imagine a game where you drive through a city and suddenly you get a loading screen in front of you, that would be annoying, don't you think?
When the loading has finished, the game goes on and you're momentarily distracted, that wouldn't make a good game I think.

Last week, I've been searching some options about how to dynamically load my terrain, road-system and much more and creating test code.
I've also been looking into pathfinding and came up with my own system to find a path via roads to my destination, but I need to convert the idea into code, which may take some time.

I'm a technician in RL, so analysing problems and coming up with a solution is what I do.
The same with programming.
I started with code like yours (lots of different meshes) and my framerate was down from 999 fps (1 tile generated) to 30 (2500 seperate tiles).
And then I only generated the terrain, no roads, buildings, trees or vehicles yet.
I remembered something about keeping your surface-count as low as you can to increase framerate, so I began thinking of merging several tiles into one bigger mesh.

My game also needs to give the player the ability to build new factories, which require and produce goods.
Then you need trucks to transport those goods from one factory to another.
The player must also be able to add/remove roads to connect the buildings to the existing roads.
Building tunnels and bridges must also be possible.
When you create a tunnel, then the terraintile where the tunnel entrance and exit are located, may not be generated, so I cannot create a map in a modelling package and just load it.
While generating the terrain, I must keep track if there is a tunnel entrance or exit on that tile, and if so, don't create a tile, as the terrain has collisions and would block the tunnel entrance/exit.
I have to have a system which holds the entire map into memory and create the models on-the-fly.
I also did find a way to reduce memory requirements.
I had an array: Map.Tile(1000,1000).
After creating all type-instances to fill the array, the program required 46Mb RAM. This was only after creating the array and the type-instances, no 3D-stuff or anything else was created.
The Tile type has only 3 fields which define each tile of the terrain, but only needs values from 0 - 200, so bytes would suffice.
But Blitz doesn't have byte-variables, only integers, floats and strings.

So for a map of size 1000x1000 and 3 bytes to define the tile, I tested memory-usage with banks, which I've never used before. The bank now has a size of 3.000.000 bytes, which is all I need to define all properties of each tile on the map.
Now memory-usage was only 12Mb RAM, so I'll be using 34Mb RAM less than before and it holds exactly the same data.


BLaBZ(Posted 2007) [#7]
Thats very interesting. So basically your terrain and environment are all going to be produced by built in algorithms?

The thought of building a GTA style like game cramps my brain. I can't imagine........

Have you ever considered programming in c++? Just out of curiosity, do you think Blitz is much much faster to work with then c++?


PowerPC603(Posted 2007) [#8]
Yes, my entire 3D-world will be generated while you play using built-in algorithms.
Maybe that some buildings will be modelled in some modelling-tool, but I'm not sure about that yet.
But I'm 100% sure about the terrain-generating and road-construction, they will be generated by algorithms, as they need to be modified frequently.
If the game would not allow you to build your own roads, then I could load them from disk.
But now, when you have a straight road and place a road tile next to it, that straight road needs to be transformed into a T-junction, so I can't have pre-made models.

If you ever played Transport Tycoon, this is what I want to create, but in 3D where you can drive your own vehicle while other vehicles (that you own) transport goods from one factory to another.
Plus you can do GTA-style missions and a lot more.
It's actually a combination of Transport Tycoon, GTA and X2 (a spacesim from Egosoft).
Not that you'll be able to fly your own spacecraft, but the trading system (dynamic prices for goods based on stock) and missions will be in my game.
Those missions where given to you (in X2) in spacestations and required you to bring some goods (microchips for example) to another factory because of a computer-malfunction or something similar.
Or they wanted you to get some goods, because their stock is low. They paid you the maximum price per unit you delivered plus some bonus if you delivered the goods within the timelimit. Something like that.

I've seen a bit about C++ on highschool, but the syntax is quite complex for me.
Once on this forum I read that you need several pages of code in C++ just to generate a 3D-capable fullscreen engine, where Blitz only needs 1 command.
And that loading 3D-models is a lot more code too, unless you search the web for some finished code to do what you want.
If that's true, I don't know, but I know that C++ is something too complex for me.

A while back, they did some speed-comparisons between C++ and Blitz (like counting to 1.000.000) and the results where about the same, so I guess Blitz3D is fast enough and easy to use.

For me, working with Blitz is faster than c++, because I know a lot about Blitz3D and almost nothing about C++.
Converting to C++ would require me to learn another programming-style and syntax, while I'm already working with 2 programming environments (Blitz and Visual Basic).


BLaBZ(Posted 2007) [#9]
Thats cool. Our interests sound similar. I've actually been working quite a bit with Visual Basic Express 2005 lately.

Do you spend a lot of time pondering about problem solving and algorithms?

Have you started writing this game or are you in the planning stage?

I'm writing an rts engine thats completely customizable from a windows gui, which will be created in visual basic.
One thing I've been planning is.....
Visual Basic will write to a text file which will then be read by the engine. But I'd like to make something more "tamper proof." For instance create my own type of encryption. Or even better, create a file format thats encrypted. Any ideas?

If I were to change the extension to a text file, for example.. to .rts, would blitz still be able to read it as a text file???


PowerPC603(Posted 2007) [#10]
I spend a lot of time about problem solving, that's correct.
Even at work, when I'm doing my job, I'm busy thinking about how to do things in my game (and still being able to do my job good too).

My game is still in the planning stage, but I've started already with writing some test-code to see if the things I need can be done.
For now, everything I've tested works perfectly.

I've written some database programs within VB6, but they just use plain ASCII-text files, no encryption (yet), because all these programs will be used by myself only, so I can't help you with encryption algorithms.

Even if you removed the extension from a file, Blitz can read it as a normal text-file.
Blitz can read any file, just as long as you know how data is stored in the file to read it properly, otherwise you get some strange results (wrong data).
If you would write an integer to a file in binary, you write 4 bytes. If you were to read it as plain text, then your data is screwed up.

When writing data to a file, write it in binary.
When people see some strange stuff in your file (not plain readable text), most people don't touch that file.
They would like to change some things when the file was a plain ASCII-file that can be read using Notepad and see how it impacts the game/program.

Image a game where you need money to buy stuff and you save the game as a plain text-file like this:
LocationX = 2569
LocationY = 4888
LocationZ = 471
Money = 19

Here most people will change the Money value to some greater value, load their game and say: hey, I've got lots of money now, easy.

But if you write the values in binary mode, then they would need a Hex-editor to figure out where the money-value is stored, how it's stored (most significant bit first or last) and then change the value in hex.
That's a lot more difficult, so most people don't even try it, because they need to do a lot of work, just to figure out IF they can change their money in the game.


FBEpyon(Posted 2008) [#11]
This is very interesting I also have been looking for code like this.

I was wondering if this could be used to make a 3D terrain system to make heightmaps..

If so could you make a example I have been trying to do this for weeks!!!