Creating a 3D Grid

Blitz3D Forums/Blitz3D Programming/Creating a 3D Grid

How would you create a 3D grid like on Maya or Milkshape3D (maybe 3DSMax too) where you can change the grid size and grid spacing? The math of it and displaying it confuses me.

Edit:
Displaying using CameraProject can get kind of slow
I can't get the grid to center when using certain numbers like 3
Changing the GridSpace shouldn't change the size of the GridSize

One way I think that might help, is if someone (including me) can figure out how to make the points come out from the center instead of point X:1,Z:1 on the grid.

An example program
Global GridTexture
Global GridSize#=16
Global GridSpace#=2

InitGraphics(800,600,"GIA Map Editor")
GridTexture = CreateGridTexture(2+4)

Global DefaultLight = CreateLight()

Global cube = CreateCube()
EntityTexture cube,GridTexture
ScaleEntity cube,GridSpace,GridSpace,GridSpace

Global Camera = CreateCamera()
	PositionEntity Camera,0,GridSize*.5,-GridSize*1.5
	CameraClsColor Camera,100,100,100
	CameraRange Camera,.01,1000
	RotateEntity Camera,20,0,0


While Not KeyDown(1)
	
	If KeyHit(20) GridSize = GridSize + 1
	If KeyHit(34) GridSize = GridSize - 1
	
	If KeyHit(21) GridSpace = GridSpace + 1
	If KeyHit(35) GridSpace = GridSpace - 1
	
	If KeyDown(31) TranslateEntity Camera,0,0,-.25
	If KeyDown(17) TranslateEntity Camera,0,0,.25
	If KeyDown(32) TranslateEntity Camera,.25,0,0
	If KeyDown(30) TranslateEntity Camera,-.25,0,0
	If KeyDown(18) TranslateEntity Camera,0,.25,0
	If KeyDown(16) TranslateEntity Camera,0,-.25,0
	
	If KeyDown(200) TurnEntity Camera,-4,0,0
	If KeyDown(208) TurnEntity Camera,4,0,0
	
	DrawWorld()
	
	TempPoints = 0
	
	For x# = -(GridSize/2) To (GridSize/2)
		For y# = -(GridSize/2) To (GridSize/2)
			CameraProject Camera,x*GridSpace,0,y*GridSpace
			Color 255,0,0
			TempX# = ProjectedX()
			TempY# = ProjectedY()
			Rect TempX,TempY,4,4
			
			Color 0,255,255
			TempPoints = TempPoints + 1
			
			If TempPoints < 32
				Text TempX,TempY-22.5,"Point:"+TempPoints,1,1
				Text TempX,TempY-7.5,"X:"+(x),1,1
				Text TempX,TempY+7.5,"Y:"+(y),1,1
			EndIf
		Next
	Next
	
	Text 0,40,"Points = " + TempPoints
	
	Color 0,0,0
	Text 0,80,"Cube depth " + MeshDepth(cube)
	Text 0,120,"Grid Size " + GridSize
	Text 0,140,"Grid Space " + GridSpace
	Text 0,160,"Press T and G to change the Grid Size"
	Text 0,180,"Press Y and H to change the Grid Space"
	
	
	Flip
Wend
ClearWorld 1,1,1
End

Function CreateGridTexture(flags%)
	Local gtexture = CreateTexture(32,32,flags)
	
	SetBuffer TextureBuffer(gtexture)
	Color 0,0,0
	Rect 0,0,32,32
	
	Color 90,90,90
	Line 16,0,16,32
	Line 0,16,32,16
	
	SetBuffer BackBuffer()
	
	Return gtexture
End Function

Function DrawWorld()
	UpdateWorld
	RenderWorld
End Function

Function InitGraphics(width = 800, height = 600,title$="Blitz3D Program",exit_message$="Are you sure?")
	Graphics3D width, height, 32, 2
	SetBuffer BackBuffer()
	SeedRnd MilliSecs()
	AppTitle title,exit_message
End Function


If you change these two lines to this I think you will get what you are looking for.

If KeyHit(20) GridSize = GridSize + 2
If KeyHit(34) GridSize = GridSize - 2


It's the odd numbers that are messing up your grid. When you only add one point, the whole thing will shift over 1/2 of a unit. By adding 2 at a time you can avoid this.

Well the thing is, I don't want just even numbers.

I'm trying a different way now by making the points come out from the center instead of... somewhere else. So far it works except I can't get it to show it like a grid, it's more like one big X. I'll post code later.

The grid scale can be anything, but to expand the grid size you need to add a border all the way around, and that means adding 2 rows or columns at a time. (One on the negative axis, the other on the positive) These can be even or odd, but they need to increment by 2.

If you have odd numbers, then the center will always fall on 0, which is probably what you want. You just have to increment by 2 each time.

For example,...draw a grid on paper,... then try to add a single line. You will see that you need to add one to each side, or you will be making one side bigger than the other. (Unless the grid shifts, which you stated you don't want)

Edit: I made the way the dots are displayed a lot better by adding functions and found out that I needed to do

For pos# = 0 To GridSize*(GridSpace^-1)
instead of
For pos# = 0 To GridSize

to show more dots when the GridSpace goes below 1

Global GridTexture
Global GridSize#=16
Global GridSpace#=2

InitGraphics(800,600,"GIA Map Editor")
GridTexture = CreateGridTexture(2+4)

Global DefaultLight = CreateLight()

Global cube[1]

cube[0] = CreateCube()
	EntityTexture cube[0],GridTexture

cube[1] = CreateCube()
	EntityTexture cube[1],GridTexture
	ScaleEntity cube[1],.25,.25,.25
	PositionEntity cube[1],3,0,0,1

Global Camera = CreateCamera()
	PositionEntity Camera,0,GridSize*.5,-GridSize*1.5
	CameraClsColor Camera,100,100,100
	CameraRange Camera,.01,1000
	RotateEntity Camera,20,0,0

Global Multiplier#=.5
Global TempPoints%

While Not KeyDown(1)
	
	If KeyHit(20) GridSize = GridSize + Multiplier
	If KeyHit(34) GridSize = GridSize - Multiplier
	
	If KeyHit(21) GridSpace = GridSpace + Multiplier
	If KeyHit(35) GridSpace = GridSpace - Multiplier
	
	If GridSize < Multiplier Then GridSize = Multiplier
	If GridSpace < Multiplier Then GridSpace = Multiplier
	
	If KeyDown(31) TranslateEntity Camera,0,0,-.25
	If KeyDown(17) TranslateEntity Camera,0,0,.25
	If KeyDown(32) TranslateEntity Camera,.25,0,0
	If KeyDown(30) TranslateEntity Camera,-.25,0,0
	If KeyDown(18) TranslateEntity Camera,0,.25,0
	If KeyDown(16) TranslateEntity Camera,0,-.25,0
	
	If KeyDown(200) TurnEntity Camera,-4,0,0
	If KeyDown(208) TurnEntity Camera,4,0,0
	
	TempPitch# = EntityPitch(Camera)
	RotateEntity Camera,TempPitch,0,0
	
	DrawWorld()
	
	TempPoints = 0
	
	ProjectLine(0,0,0,GridSize,0,0,255,0,0) ; X Line
	ProjectLine(0,0,0,0,GridSize,0,0,255,0) ; Y Line
	ProjectLine(0,0,0,0,0,GridSize,0,0,255) ; Z Line
	
	Local TempX#[3]
	Local TempZ#[3]
	Local TempPZ#[3]
	
	Color 255,0,0
	
	For pos# = 0 To GridSize*(GridSpace^-1) ; Instead of doing GridSize/GridSpace which freezes the program if either are 0
											; The smaller the GridSpace, the more points/dots there are
		
		TempSpacing# = GridSpace*pos
		
		If TempSpacing <= GridSize
			ProjectPoint(TempSpacing,0,TempSpacing,TempSpacing,255)
			ProjectPoint(TempSpacing,0,-TempSpacing,TempSpacing,255)
			ProjectPoint(-TempSpacing,0,TempSpacing,TempSpacing,255)
			ProjectPoint(-TempSpacing,0,-TempSpacing,TempSpacing,255)
		EndIf
	Next
	
	Color 0,255,0
	
	Text 0,40,"Points = " + TempPoints
	
	Color 0,0,0
	Text 0,80,"Center Cube depth = " + MeshDepth(cube[0])
	Text 0,100,"Smaller Cube X position = " + EntityX(cube[1])
	Text 0,120,"Grid Size " + GridSize
	Text 0,140,"Grid Space " + GridSpace
	Text 0,160,"Press T and G to change the Grid Size"
	Text 0,180,"Press Y and H to change the Grid Space"
	
	
	Flip
Wend
ClearWorld 1,1,1
End

Function ProjectPoint(x#,y#,z#,value$="",point_red%=0,point_green%=0,point_blue%=0)
	CameraProject Camera,x,y,z
	
	If ProjectedZ() > 0
		
		RectSize# = Sqr(EntityX(Camera,1)^2+EntityY(Camera,1)^2+EntityZ(Camera,1)^2 + x^2 + y^2 + z^2)
		RectSize = Cos(RectSize)*4
		
		If RectSize > 0
			TempX# = ProjectedX()
			TempY# = ProjectedY()
			Color point_red,point_green,point_blue
			Rect TempX,TempY,RectSize,RectSize
			Color 250,250,0
			Text TempX,TempY,value
			TempPoints = TempPoints + 1
		EndIf
	EndIf
	
	Return ProjectedZ()
End Function

Function ProjectLine(x1#,y1#,z1#,x2#,y2#,z2#,line_red%=0,line_green%=0,line_blue%=0)
	TempPivot1% = CreatePivot()
		PositionEntity TempPivot1,x1,y1,z1,1
	
	TempPivot2% = CreatePivot()
		PositionEntity TempPivot2,x2,y2,z2,1
	
	TempX1#=0
	TempY1#=0
	
	TempX2#=0
	TempY2#=0
	
	
	If EntityInView(TempPivot1,Camera)
		If EntityInView(TempPivot2,Camera)
			CameraProject Camera,x1,y1,z1
			
				TempX1 = ProjectedX()
				TempY1 = ProjectedY()
				
			CameraProject Camera,x2,y2,z2
			
				TempX2 = ProjectedX()
				TempY2 = ProjectedY()
			
			Color line_red,line_green,line_blue
			Line TempX1,TempY1,TempX2,TempY2
		EndIf
	EndIf
	
	FreeEntity TempPivot1
	FreeEntity TempPivot2
	
End Function

Function CreateGridTexture(flags%)
	Local gtexture = CreateTexture(32,32,flags)
	
	SetBuffer TextureBuffer(gtexture)
	Color 0,0,0
	Rect 0,0,32,32
	
	Color 90,90,90
	Line 16,0,16,32
	Line 0,16,32,16
	
	SetBuffer BackBuffer()
	
	Return gtexture
End Function

Function DrawWorld()
	UpdateWorld
	RenderWorld
End Function

Function InitGraphics(width = 800, height = 600,title$="Blitz3D Program",exit_message$="Are you sure?")
	Graphics3D width, height, 32, 2
	SetBuffer BackBuffer()
	SeedRnd MilliSecs()
	AppTitle title,exit_message
End Function


The grid spacing shouldn't matter whether its 1002.5125 or 2.9.
The grid size is the border and should limit how many dots are made/displayed.

Here is what it should look like on paper (note, I made this the day BEFORE Pongo posted the idea)


The number above each grid is the grid size, the one to the right is the grid space. The grids on the the right side of the page are all a grid space of 2.



Now I just gotta figure out how I'm gonna draw all the grid lines instead using a whole bunch of dots in the shape of an X

I wish using CameraProject wasn't so friggin slow.

I HAVE FOUND IT!

Edit: Fixed the borders not showing exactly the way they're supposed to ;)
Global GridTexture
Global GridSize#=16
Global GridSpace#=2

InitGraphics(1024,768,"GIA Map Editor")
GridTexture = CreateGridTexture(2+4)

Global DefaultLight = CreateLight()

Global cube[1]

cube[0] = CreateCube()
	EntityTexture cube[0],GridTexture

cube[1] = CreateCube()
	EntityTexture cube[1],GridTexture
	ScaleEntity cube[1],.25,.25,.25
	PositionEntity cube[1],3,0,0,1

Global Pivot = CreatePivot()
	PositionEntity Pivot,0,GridSize*.5,-GridSize*1.5
	
Global Camera = CreateCamera(Pivot)
	CameraClsColor Camera,100,100,100
	CameraRange Camera,.01,100
	RotateEntity Camera,20,0,0

Global Plane = CreatePlane()
	EntityPickMode Plane,2
	EntityAlpha Plane,0

Global Multiplier#=.5
Global TempPoints%
Global Pause%=0
Global Cursor%=1

While Not KeyDown(1)
	If KeyHit(25)
		Pause = Not Pause
		FlushKeys
	EndIf
	
	If MouseHit(1)
		Cursor = Not Cursor
		
		If Cursor = 1 Then ShowPointer
		If Cursor = 0 Then HidePointer
	EndIf
	
	If Pause = 0
		If KeyHit(20) GridSize = GridSize + Multiplier
		If KeyHit(34) GridSize = GridSize - Multiplier
		
		If KeyHit(21) GridSpace = GridSpace + Multiplier
		If KeyHit(35) GridSpace = GridSpace - Multiplier
		
		If GridSize < Multiplier Then GridSize = Multiplier
		If GridSpace < Multiplier Then GridSpace = Multiplier
		
		If KeyDown(31) MoveEntity Pivot,0,0,-.25
		If KeyDown(17) MoveEntity Pivot,0,0,.25
		
		If KeyDown(32) MoveEntity Pivot,.25,0,0
		If KeyDown(30) MoveEntity Pivot,-.25,0,0
		
		If KeyDown(18) TranslateEntity Pivot,0,.25,0
		If KeyDown(16) TranslateEntity Pivot,0,-.25,0
		
		If KeyDown(200) TurnEntity Camera,-4,0,0
		If KeyDown(208) TurnEntity Camera,4,0,0
		
		If KeyDown(203) TurnEntity Pivot,0,4,0
		If KeyDown(205) TurnEntity Pivot,0,-4,0
		
		TempPitch# = EntityPitch(Camera)
		TempYaw# = EntityYaw(Pivot)
		
		RotateEntity Camera,TempPitch,0,0
		RotateEntity Pivot,0,TempYaw,0
		
		DrawWorld()
		
		TempPoints = 0
		
		ProjectLine(-GridSize,0,0,GridSize,0,0,255,0,0,1) ; X Line
		ProjectLine(0,-GridSize,0,0,GridSize,0,0,255,0) ; Y Line
		ProjectLine(0,0,-GridSize,0,0,GridSize,0,0,255,1) ; Z Line
		
		For pos# = 1 To (GridSize*(GridSpace^-1)) ; Instead of doing GridSize/GridSpace which freezes the program if either are 0
												; The smaller the GridSpace, the more points/dots there are
			
			TempSpacing# = GridSpace*pos
			
			If TempSpacing <= GridSize
				
				;X Axis Lines
				ProjectLine(GridSize,0,TempSpacing ,-GridSize,0,TempSpacing ,50,50,50)
				ProjectLine(GridSize,0,-TempSpacing ,-GridSize,0,-TempSpacing ,50,50,50)
				
	;			;YX Axis Lines
	;			ProjectLine(GridSize,TempSpacing,0 ,-GridSize,TempSpacing,0 ,50,50,50)
	;			ProjectLine(GridSize,-TempSpacing,0 ,-GridSize,-TempSpacing,0 ,50,50,50)
	;			
	;			;YZ Axis Lines
	;			ProjectLine(TempSpacing,GridSize,0 ,TempSpacing,-GridSize,0 ,50,50,50)
	;			ProjectLine(-TempSpacing,GridSize,0 ,-TempSpacing,-GridSize,0 ,50,50,50)
				
				;Z Axis Lines
				ProjectLine(TempSpacing,0,GridSize ,TempSpacing,0,-GridSize ,50,50,50)
				ProjectLine(-TempSpacing,0,GridSize ,-TempSpacing,0,-GridSize ,50,50,50)
				
				
				
				ProjectPoint(TempSpacing,0,0,TempSpacing,255,0,0,4)
			EndIf
		Next
		
		;TempGridSize#=Floor(GridSize*(GridSpace^-1))*GridSpace
		
		CameraPick(Camera,MouseX(),MouseY())
		
		If PickedEntity() <> 0
			TempPickedX# = Int(PickedX()/GridSpace)*GridSpace
			TempPickedY# = Int(PickedY()/GridSpace)*GridSpace
			TempPickedZ# = Int(PickedZ()/GridSpace)*GridSpace
			
			ProjectPoint(TempPickedX,TempPickedY,TempPickedZ,"HERE",180,50,2,32)
		EndIf
		
		Color 0,255,0
		
		Text 0,40,"Points = " + TempPoints
		
		Color 0,0,0
		Text 0,80,"Center Cube depth = " + MeshDepth(cube[0])
		Text 0,100,"Smaller Cube X position = " + EntityX(cube[1])
		Text 0,120,"Grid Size " + GridSize
		Text 0,140,"Grid Space " + GridSpace
		Text 0,160,"Press T and G to change the Grid Size"
		Text 0,180,"Press Y and H to change the Grid Space"
		Text 0,200,"Press P to pause the program"
		
		
		Flip
	EndIf
Wend
ClearWorld 1,1,1
End

Function ProjectPoint(x#,y#,z#,value$="",point_red%=0,point_green%=0,point_blue%=0,point_size#=4)
	CameraProject Camera,x,y,z
	
	If ProjectedZ() > 0
		
		RectSize# = Sqr(EntityX(Camera,1)^2+EntityY(Camera,1)^2+EntityZ(Camera,1)^2 + x^2 + y^2 + z^2)
		RectSize = Cos(RectSize)*point_size
		
		If RectSize > 0
			TempX# = ProjectedX()
			TempY# = ProjectedY()
			Color point_red,point_green,point_blue
			Rect TempX-(RectSize*.5),TempY-(RectSize*.5),RectSize,RectSize
			Color 250,250,0
			Text TempX,TempY,value
			TempPoints = TempPoints + 1
		EndIf
	EndIf
	
	Return ProjectedZ()
End Function

Function ProjectLine(x1#,y1#,z1#,x2#,y2#,z2#,line_red%=0,line_green%=0,line_blue%=0,line_thick#=0)
	
	Local TempX#[1]
	Local TempY#[1]
	Local TempZ#[1]

	CameraProject Camera,x1,y1,z1
	
		TempX[0] = ProjectedX()
		TempY[0] = ProjectedY()
		TempZ[0] = ProjectedZ()
		
	CameraProject Camera,x2,y2,z2
	
		TempX[1] = ProjectedX()
		TempY[1] = ProjectedY()
		TempZ[1] = ProjectedZ()
		
	If TempZ[0] > 0
		If TempZ[1] > 0
			Color line_red,line_green,line_blue
			If line_thick = True
				For t# = -1 To 1
					Line TempX[0],TempY[0]+t,TempX[1],TempY[1]+t
				Next
					Else
						Line TempX[0],TempY[0],TempX[1],TempY[1]
			EndIf
			TempPoints = TempPoints + 2
		EndIf
	EndIf
End Function

Function CreateGridTexture(flags%)
	Local gtexture = CreateTexture(32,32,flags)
	
	SetBuffer TextureBuffer(gtexture)
	Color 0,0,0
	Rect 0,0,32,32
	
	Color 90,90,90
	Line 16,0,16,32
	Line 0,16,32,16
	
	SetBuffer BackBuffer()
	
	Return gtexture
End Function

Function DrawWorld()
	UpdateWorld
	RenderWorld
End Function

Function InitGraphics(width = 800, height = 600,title$="Blitz3D Program",exit_message$="Are you sure?")
	Graphics3D width, height, 32, 2
	SetBuffer BackBuffer()
	SeedRnd MilliSecs()
	AppTitle title,exit_message
End Function


...now if only I could find a way so I don't have to make the grid disappear(if I don't, then the lines will appear in odd places)

if this is for an editing tool consider doing it with a surface and verts rather than a texture.

Then it will be a lot easier to do grid snapping etc.

This isn't a texture... it's just putting a bunch of 2D lines on screen depending on the GridSize and GridSpace.

And grid snapping isn't hard to do anyways XD I've known how for awhile.

I'm trying to make a simple 3D Modeling program and don't try to tell me not to make one because I'm going to anyways.

Edit:
Do you think other 3D modeling programs use a surface to make the grid? I don't understand how you could make the grid lines not look distorted if you use a texture, and how you could change the grid size and spacing in real time.

I started a 3D model viewer years ago and used this basic technique to render the grid:
http://www.blitzbasic.com/codearcs/codearcs.php?code=839

I also developed this technique for vertex 'handles':
http://www.blitzbasic.com/codearcs/codearcs.php?code=1008

Thanks, I'll see what I can get out of it. ;)

I thought you might find this useful. It's a bit of code I use for navigating the camera around my objects when I am testing things out.

Left button down orbits around the pivot
middle button pans
mouse wheel zooms


Graphics3D 800,600,0,2

;create the camera rig
Global mxs,mys	;for saving mouse x and y speed
;Global current_pick	;for saving current picked object						
Global campiv_h=CreatePivot()			;This is the master camera pivot,... it controls position and horizontal rotation
Global campiv_v=CreatePivot(campiv_h)	;This controls vertical rotation
Global cam=CreateCamera(campiv_v)

Global hor_rot# = -45 					;Set horizontal orbit
Global ver_rot# = 20					;set Vert orbit

MoveEntity cam,0,0,-5					;move the camera back a bit
RotateEntity campiv_h,0,hor_rot,0		
RotateEntity campiv_v,ver_rot,0,0

;hide windows cursor and create a crosshair cursor
HidePointer()
Global cursor=CreateImage(16,16)
SetBuffer ImageBuffer(cursor)
Line 1,7,15,7
Line 1,9,15,9
Line 7,1,7,15
Line 9,1,9,15

SetBuffer BackBuffer() 

;###############
; create an axis icon 
Global axis_center = CreatePivot()

axis1 = CreateCube(axis_center)
ScaleEntity axis1,.005,.005,.5
EntityColor axis1,0,0,255 

axis2 = CreateCube(axis_center)
ScaleEntity axis2,.005,.5,.005
EntityColor axis2,0,255,0

axis3 = CreateCube(axis_center)
ScaleEntity axis3,.5,.005,.005
EntityColor axis3,255,0,0
;###############


;create some object in the scene
cube = CreateCube()
ScaleEntity cube,.25,.25,.25
MoveEntity cube,-1,0,0
sphere = CreateSphere()
ScaleEntity sphere,.25,.25,.25
MoveEntity sphere,1,0,0

;light!
lightpivot = CreatePivot()
light=CreateLight(2,lightpivot)
MoveEntity light,500,800,0

;********************************************************************************
;Main loop

While Not KeyDown(1)
	
	mxs=MouseXSpeed() ; store mouse x and y speeds
	mys=MouseYSpeed()

	If MouseDown(1) Then orbit_cam() 	;if alt and middle mouse button pressed,... do orbit
	If MouseDown(3) Then Pan_cam()		;if middle mouse button pressed,... do pan
						
	MoveEntity cam,0,0,MouseZSpeed() ; move the camera back/forth based on mouse wheel

	WireFrame  KeyDown(57)

	UpdateWorld()
	RenderWorld()
		
	Text 10,10,"X: " + EntityX(campiv_h)+"   Y: " + EntityY(campiv_h)+"   Z: " + EntityZ(campiv_h)
	Text 10,25,"mouse button to orbit,... middle button to pan/zoom,...space for wireframe"

	DrawImage cursor,MouseX(),MouseY()
	
	Flip

Wend ; end main loop

End ; end program

;********************************************************************************
Function orbit_cam()
	hor_rot=(hor_rot - (mxs*.5) ) ; get the mouse x and y speed,... adjust sensitivity by half
	ver_rot=(ver_rot + (mys*.5) ) 
	RotateEntity campiv_h,0,hor_rot,0 ; update the new camera pivot rotations
	RotateEntity campiv_v,ver_rot,0,0	
End Function

Function pan_cam()
	MoveEntity campiv_h,-mxs*.01,0,mys*.01
	PositionEntity axis_center,EntityX(campiv_h),EntityY(campiv_h),EntityZ(campiv_h) ;position the axis at the camera pivot
End Function


Woo cool, thanks. That was the way I was going to do it except I was going to make it more like Maya where you hold down Alt and then use the mouse to rotate and stuff (You can pan and zoom with the middle button without the Alt button being down in Maya).