Triangle Placing to match grid
Blitz3D Forums/Blitz3D Programming/Triangle Placing to match grid| 
 | ||
| In attempt to save surfaces and triangles, rather than use a number of cube primitives, I wanted to construct geometry by code to form a single-surface mesh, eradicating overlaps and invisible triangles. Generally it seems as though the core concept is working, but there's some issues with the fidelity of placement: I would really apprecaite any help orsuggestions on the matter. The following code provides an executable overview of the idea and highlights the problem; ;;Identifies efficient single-surface triangleplacement for square-grid based maps.
;For this example purpose, an ARRAY data type is used, it may be more suitable to utilise banks or other data structures in actual usage.
Graphics3D 1024,768,32,2
SetBuffer BackBuffer()
Global SUN=CreateLight()
Const WLS_TOP_BOUND=1
Const WLS_BOTTOM_BOUND=2
Const WLS_LEFT_BOUND=4
Const WLS_RIGHT_BOUND=8
Const WLS_ROOF_H=16
Const WLS_ROOF_V=32
Dim ARRAY(0,0)
Dim TempArray(0,0)
Type ROOFED
	Field X
	Field Y
End Type
SeedRnd MilliSecs()
Local W=100
Local H=100
;Example Populate Random Grid map (0 = blank, 1 = Wall)
PopulateRandomMap(W,H)
WaitKey()
;Now To call the Function And generate single-surface geometry
Local MESH=CreateMesh()
Local SURF=CreateSurface(MESH)
Walls(W,H,SURF)
;EntityFX MESH,16
EntityAlpha MESH,0.5
UpdateNormals MESH
DISPLAY3DOUTPUT(MESH,W,H)
Function Walls(W,H,Surface,AddTop=True)
	W=W-1
	H=H-1
	
	Local X
	Local Y
	
	Dim TempArray(W,H)
	
	Local Bounds
	
	;First Pass : Identify each grid unit boundaries. This can remove any hidden or adjoining wall faces
	For Y=0 To H
		For X=0 To W
			Bounds=0
			
			If (ARRAY(X,Y)=1)
				Bounds=Bounds+GetTopBound(X,Y)
				Bounds=Bounds+GetBottomBound(X,Y,H)
				Bounds=Bounds+GetLeftBound(X,Y)
				Bounds=Bounds+GetRightBound(X,Y,W)
				
				TempArray(X,Y)=Bounds
			End If
			
		Next
	Next
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	;HORIZONTAL Pass : CHECK FOR CONTINUOUS HORIZONTAL WALL SEGMENTS - EACH WALL HAS A TOP (Z+1) AND BOTTOM (Z+0) FACE ALIGNED WITH X AXIS
	
	Local LengthTop
	Local LengthBottom
	Local CountingTop
	Local CountingBottom
	
	For Y=0 To H
		For X=0 To W
			
			If (TempArray(X,Y) And WLS_TOP_BOUND)
				LengthTop=LengthTop+1
				CountingTop=True
			Else
				If (CountingTop)
					AddZ_PLUSGeometry(X-LengthTop,H-Y,LengthTop,Surface)
					
					LengthTop=0
					CountingTop=False	
				End If
			End If
			
			
			If (TempArray(X,Y) And WLS_BOTTOM_BOUND)
				LengthBottom=LengthBottom+1
				CountingBottom=True
			Else
				If (CountingBottom)
					AddZ_MINUSGeometry(X-LengthBottom,H-Y,LengthBottom,Surface)
					
					LengthBottom=0
					CountingBottom=False	
				End If
			End If
			
			
			
			
		Next
		
		;Break at end of row
		If (CountingTop)
			AddZ_PLUSGeometry(X-LengthTop,H-Y,LengthTop-1,Surface)
			
			LengthTop=0
			CountingTop=False	
		End If
		
		If (CountingBottom)
			AddZ_MINUSGeometry(X-LengthBottom,H-Y,LengthBottom-1,Surface)
			
			LengthBottom=0
			CountingBottom=False	
		End If
		
	Next
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
		;VERTICAL Pass: CHECK FOR CONTINUOUS VERTICAL WALL SEGMENTS - EACH WALL HAS A RIGHT (X+1) AND LEFT (X+0) FACE ALIGNED WITH Z AXIS
	Local LengthLeft
	Local LengthRight
	Local CountingLeft
	Local CountingRight
	
	For X=0 To W
		For Y=0 To H
			
			If (TempArray(X,Y) And WLS_LEFT_BOUND)
				LengthLeft=LengthLeft+1
				CountingLeft=True
			Else
				If (CountingLeft)
					AddX_MINUSGeometry(X,H-(Y-LengthLeft),LengthLeft,Surface)
					
					LengthLeft=0
					CountingLeft=False	
				End If
			End If
			
			
			If (TempArray(X,Y) And WLS_RIGHT_BOUND)
				LengthRight=LengthRight+1
				CountingRight=True
			Else
				If (CountingRight)
					AddX_PLUSGeometry(X,H-(Y-LengthRight),LengthRight,Surface)
					
					LengthRight=0
					CountingRight=False	
				End If
			End If
			
			
			
			
		Next
		
		;Break at end of row
		If (CountingLeft)
			AddX_MINUSGeometry(X,H-(Y-LengthLeft),LengthLeft-1,Surface)
			
			LengthLeft=0
			CountingLeft=False
		End If
		
		If (CountingRight)
			AddZ_PLUSGeometry(X,H-(Y-LengthRight),LengthRight-1,Surface)
			
			LengthRight=0
			CountingRight=False	
		End If
		
		
	Next
	
	
	
	
	If (AddTop)
		;Adds a "roof" plane geometry to the walls
		
		;[Block]
	;PLANAR PASS HORIZONTAL 1 : Determines potential rows of wall segments
		
	Local CountingHorizontal
	Local HorizontalLength
	
	For Y=0 To H
		For X=0 To W
			
			If (TempArray(X,Y) And (WLS_TOP_BOUND Or WLS_BOTTOM_BOUND))
				CountingHorizontal=True
				HorizontalLength=HorizontalLength+1
			Else
				If (CountingHorizontal)
					ProcessPlanarHorizontal(X-HorizontalLength,Y,HorizontalLength)
					HorizontalLength=0
					CountingHorizontal=False	
				End If
			End If
		Next
		
		;Break at end of row
		If (CountingHorizontal)
			ProcessPlanarHorizontal(X-HorizontalLength,Y,HorizontalLength-1)
			
			HorizontalLength=0
			CountingHorizontal=False	
		End If
		
		
	Next
	
	;PLANAR PASS VERTICAL 1 : Determines potential columns of wall segments
	
	Local CountingVertical
	Local VerticalLength
	
	For X=0 To W
		For Y=0 To H
			
			If (TempArray(X,Y) And (WLS_LEFT_BOUND Or WLS_RIGHT_BOUND))
				CountingVertical=True
				VerticalLength=VerticalLength+1
			Else
				If (CountingVertical)
					ProcessPlanarVertical(X,Y-VerticalLength,VerticalLength)
					VerticalLength=0
					CountingVertical=False	
				End If
			End If
		Next
		
		;Break at end of row
		If (CountingVertical)
			ProcessPlanarVertical(X,Y-VerticalLength,VerticalLength-1)
			
			VerticalLength=0
			CountingVertical=False	
		End If
		
		
	Next
	
	
	;PLANAR PASS HORIZONTAL 2 : Appliess planar roofing geometry across horizontal wall segments
	
	
	For Y=0 To H
		For X=0 To W
			
			If (TempArray(X,Y) And (WLS_ROOF_H))
				CountingHorizontal=True
				HorizontalLength=HorizontalLength+1
			Else
				If (CountingHorizontal)
					AddPLANAR_XZ_X_Geometry(X-HorizontalLength,H-Y,HorizontalLength,Surface)
					HorizontalLength=0
					CountingHorizontal=False	
				End If
			End If
		Next
		
		;Break at end of row
		If (CountingHorizontal)
			AddPLANAR_XZ_X_Geometry(X-HorizontalLength,H-Y,HorizontalLength-1,Surface)
			
			HorizontalLength=0
			CountingHorizontal=False	
		End If
		
		
	Next
	
	;PLANAR PASS VERTICAL 2:  Appliess planar roofing geometry across horizontal wall segments
	
	
	For X=0 To W
		For Y=0 To H
			
			If (TempArray(X,Y) And (WLS_ROOF_V))
				CountingVertical=True
				VerticalLength=VerticalLength+1
			Else
				If (CountingVertical)
					AddPLANAR_XZ_Z_Geometry(X,H-(Y-VerticalLength),VerticalLength,Surface)
					VerticalLength=0
					CountingVertical=False	
				End If
			End If
		Next
		
		;Break at end of row
		If (CountingVertical)
			AddPLANAR_XZ_Z_Geometry(X,H-(Y-VerticalLength),VerticalLength-1,Surface)
			
			VerticalLength=0
			CountingVertical=False	
		End If
		
		
	Next
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	;[End Block]
End If
Dim TempArray(0,0)
End Function
Function ProcessPlanarHorizontal(X,Y,Length)
	Local X1=X
	Local X2=X+Length
	
	For X=X1 To X2
		TempArray(X,Y)=TempArray(X,Y) Or WLS_ROOF_H
	Next
End Function
Function ProcessPlanarVertical(X,Y,Length)
	Local Y1=Y
	Local Y2=Y+Length
	
	Local Skip
	
	For Y=Y1 To Y2
		Skip=False
		
		If (TempArray(X,Y) And WLS_ROOF_H)
			If (Length>0) 
				TempArray(X,Y)= (TempArray(X,Y) Xor WLS_ROOF_H)
			Else
				Skip=True
			End If
		End If
		
		If (Not(Skip))
			TempArray(X,Y)=(TempArray(X,Y) Or WLS_ROOF_V)
		End If
	
	Next
End Function
Function GetTopBound(X,Y)
	Local Value
	If (Y>0)
		Value=(ARRAY(X,Y-1)=0)
	End If
	If (Value>1) DebugLog("GOtcha")
	Return Value * WLS_TOP_BOUND
End Function
Function GetBottomBound(X,Y,H)
	Local Value
	If (Y<H)
		Value=(ARRAY(X,Y+1)=0)
	End If
	If (Value>1) DebugLog("GOtcha")
	Return Value * WLS_BOTTOM_BOUND
End Function
Function GetLeftBound(X,Y)
	Local Value
	If (X>0)
		Value=(ARRAY(X-1,Y)=0)
	End If
	If (Value>1) DebugLog("GOtcha")
	Return Value * WLS_LEFT_BOUND
End Function
Function GetRightBound(X,Y,W)
	Local Value
	If (X<W)
		Value=(ARRAY(X+1,Y)=0)
	End If
	If (Value>1) DebugLog("GOtcha")
	Return Value * WLS_RIGHT_BOUND
End Function
;GEOM
Function AddPLANAR_XZ_X_Geometry(X,Z,Length,Surface)
	AddXZPlaneVertexPoints(X,Z,Length-1,1,Surface)
	Local v=CountVertices(Surface)-4
	
	AddTriangle(Surface,v+0,v+1,v+2)
	AddTriangle(Surface,v+3,v+2,v+1)
End Function
Function AddPLANAR_XZ_Z_Geometry(X,Z,Length,Surface)
	AddXZPlaneVertexPoints(X,Z,1,Length-1,Surface)
	Local v=CountVertices(Surface)-4
	
	AddTriangle(Surface,v+0,v+1,v+2)
	AddTriangle(Surface,v+3,v+2,v+1)
End Function
Function AddX_MINUSGeometry(X,Z,Length,Surface)
	AddZAxisVertexPoints(X,Z,Length,Surface)
	Local v=CountVertices(Surface)-4
	
	AddTriangle(Surface,v+1,v+2,v+3)
	AddTriangle(Surface,v+2,v+1,v+0)
End Function
Function AddX_PLUSGeometry(X,Z,Length,Surface)
	AddZAxisVertexPoints(X+1,Z,Length,Surface)
	Local v=CountVertices(Surface)-4
	
	AddTriangle(Surface,v+0,v+1,v+2)
	AddTriangle(Surface,v+3,v+2,v+1)
End Function
Function AddZ_PLUSGeometry(X,Z,Length,Surface)
	AddXAxisVertexPoints(X,Z,Length,Surface)
	Local v=CountVertices(Surface)-4
	
	AddTriangle(Surface,v+1,v+2,v+3)
	AddTriangle(Surface,v+2,v+1,v+0)
End Function
Function AddZ_MINUSGeometry(X,Z,Length,Surface)
	AddXAxisVertexPoints(X+Length,Z-1,0-Length,Surface)
	Local v=CountVertices(Surface)-4
	
	AddTriangle(Surface,v+1,v+2,v+3)
	AddTriangle(Surface,v+2,v+1,v+0)
End Function
Function AddXAxisVertexPoints(X#,Z#,Length,Surface)
	Local X1#=X#
	Local X2#=X#+Length
	
	AddVertex(Surface,X1#,1,Z#,1,0)
	AddVertex(Surface,X2#,1,Z#,0,0)
	AddVertex(Surface,X1#,0,Z#,1,1)
	AddVertex(Surface,X2#,0,Z#,0,1)
End Function
Function AddZAxisVertexPoints(X#,Z#,Length,Surface)
	Local Z1#=Z#-Length
	Local Z2#=Z#
	
	AddVertex(Surface,X#,1,Z1#,1,0)
	AddVertex(Surface,X#,1,Z2#,0,0)
	AddVertex(Surface,X#,0,Z1#,1,1)
	AddVertex(Surface,X#,0,Z2#,0,1)	
End Function
Function AddXZPlaneVertexPoints(X#,Z#,LengthX,LengthZ,Surface)
	Local X1#=X#
	Local X2#=X#+LengthX
	
	Local Z1#=Z#-LengthZ
	Local Z2#=Z#
	
	AddVertex(Surface,X1#,1,Z2#,1,0)
	AddVertex(Surface,X2#,1,Z2#,0,0)
	AddVertex(Surface,X1#,1,Z1#,1,1)
	AddVertex(Surface,X2#,1,Z1#,0,1)	
End Function
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;the following is for example purposes only
Function PopulateRandomMap(W,H)
	;VISUAL OUTPUT
	
	Dim ARRAY(W-1,H-1)
	
	Local Iter
	
	Local Length
	Local X,Y
	
	Local Dir
	
	Local RandX,RandY
	For Iter=1 To 100
		
		Length=Rand(1,Sqr(H))
		Dir=Rand(0,1)
		
		Select (Dir)
			Case 1:
			;VERTICAL
				X=Rand(0,W-1)
				RandY=Rand(0,H-Length)
				
				For Y=RandY To (RandY+Length)-1
					ARRAY(X,Y)=1
				Next
				
			Default:
			;HORIZONTAL
				RandX=Rand(0,W-Length)
				Y=Rand(0,H-1)
				
				For X=RandX To (RandX+Length)-1
					ARRAY(X,Y)=1
				Next
		End Select
		
	Next
	
	DRAWARRAYGRID(W-1,H-1)
	UPDATEVISUALDISPLAY
End Function
;The following is just for a visual depiction of the example and are not required for use of the system
Function DRAWARRAYGRID(W,H)
	Local X
	Local Y
	
	For Y= 0 To H
		For X=0 To W
			Color 0,255*ARRAY(X,Y),255
			Rect X*10,Y*5,10,5,ARRAY(X,Y)
		Next
	Next
End Function
Function DISPLAY3DOUTPUT(Mesh,W,H)
	AmbientLight 128,128,128
	Local Cam=CreateCamera()
	MoveEntity Cam,MeshWidth(Mesh)*0.5,MeshDepth(Mesh)*0.5,0-(MeshWidth(Mesh)*0.75)
	RotateEntity Mesh,-90,0,0,True
	
	Local Wire%				=	False;
	FlushMouse();
	
	Local Prim=True
	
	Local PIV=CreatePivot()
	
	For x=0 To W-1
		For y=0 To H-1
			If ARRAY(x,y)
				c=CreateCube(PIV)
				PositionEntity c,x+0.5,((H-1)-y)-0.5,0,True
				ScaleMesh c,0.45,0.45,0.45
				EntityAlpha c,0.5
				EntityColor c,128,0,0
			End If
		Next
	Next
	
	While Not KeyDown(1)
		Cls
		
		If (KeyHit(57)>0)
			Wire			=	Not(Wire);
			WireFrame			( Wire );
		EndIf;
		
		If KeyHit(28)	
			Prim=Not(Prim)
			If Prim
				ShowEntity PIV
			Else
				HideEntity PIV
			End If
		End If	
		
		TranslateEntity Cam,Float(KeyDown(205)-KeyDown(203))*.1, Float(KeyDown(200)-KeyDown(208))*.1,MouseZSpeed(),1
		
		UpdateWorld
		RenderWorld
		
		
		Color				( 255,128,000 );
		Text				( 10,20,"Arrow -> move" );
		Text				( 10,80,"space -> wireframe" );
		Text				( 10,100,"Enter -> primitives" );
		Text				0,0,TrisRendered()
		
		UPDATEVISUALDISPLAY
	Wend
	
End Function
Function UPDATEVISUALDISPLAY()
	Flip
End Function | 
| 
 | ||
| why don't you add premade rectangle meshes (each corresponding to the side of a cube) to a surface ? apart from that i would use a similar logic than the one you use (use a 2d array to store the properties of each tile and analyze if there is (or not) a tile at front, at back, at left, at right here is the function i use to add one surface to another surface : http://www.blitzbasic.com/codearcs/codearcs.php?code=3291 | 
| 
 | ||
| The intent is to use the least possible triangles where possible. This means, that when a wall segment extends along, say, 5 units, I do not need 10 triangles but just two per each side. For example: Using indivdual cubes: A wall segment of 3 units comprises a total of 36 triangles: ._..._..._. |_|.|_|.|_| Current method: A wall segment of 3 units comprises just 12 triangles ._________. |_________| ________________________________________________________________________ This is detracting form the point of the discussion which is to ask for help in the position of the geometry. I suspect, ultimately, it ought to be a minor tweak to the values of Add**Geometry() functions, since otherwise, it seems to be creating the triangles with correct facing etc. | 
| 
 | ||
| The intent is to use the least possible triangles where possible. This means, that when a wall segment extends along, say, 5 units, I do not need 10 triangles but just two per each side. ok but you will encounter a problem (overlapping triangles) when you have tiles arranged in this way : 00100 11111 00100 | 
| 
 | ||
| . | 
| 
 | ||
| yes i took a look at your code, but i am not really in the mood to debug today. sorry good luck | 
| 
 | ||
| i just remembered this code by sswift, maybe it can help : http://www.blitzbasic.com/codearcs/codearcs.php?code=526 | 
| 
 | ||
| I am convinced the issue lies within the Add*Geometry() functions or the values passed to them. This should help in narrowing down the root of the issue. Thanks for taking the time to look at this, and I do very much appreciate your help and hope that you are feeling better :) | 
| 
 | ||
| one question : Do you want the walls to care about corners ? 123456 X numbers are just to identify the cells, the X is the block a the next line obviously, you can create a wall along the top of the cells from 1 to 6 But what do you expect for the bottom wall ? Does it go grom 1 to 6 ? or do you split it in 2 walls (bottom of 1, and bottom of 3 to 6) Then, just a thing : > in the function DISPLAY3DOUTPUT If ARRAY(x,y) c=CreateCube(PIV) PositionEntity c,x,y,0,True ScaleMesh c,0.9,0.9,0.9 EntityAlpha c,0.5 EntityColor c,128,0,0 If you set the position of your cubes every one unit, then your scalemesh is too large -> a cube goes from -1 to 1, so scale to 0.45 if you want it do be a bit lower than one unit. | 
| 
 | ||
| But what do you expect for the bottom wall ? Does it go grom 1 to 6 ? or do you split it in 2 walls (bottom of 1, and bottom of 3 to 6) As you will see if you run the example code, the walls do as I want in this regard. The top wall would run from 1 to 6 the bottom wall will be split into two: one segment at 1 (1 unit length) another from 3 to 6 (4 unit length) | 
| 
 | ||
| If you set the position of your cubes every one unit, then your scalemesh is too large -> a cube goes from -1 to 1, so scale to 0.45 if you want it do be a bit lower than one unit. I forgot this. Thank you. | 
| 
 | ||
| Updated the initial code again. 1) The RED Primitive cubes used as template are now scaled accordingly. 2) Horizontal and Vertical Wall sections are now mostly accurate. 3) Errors at the extremeties of the map are likely to be non-critical 4) Errors as result of parrallel wall segments placed adjacently will not be an issue. 5) The PLANAR "roof" seems to fail, I suspect due to situations whereby the n -> n+Length should be n-length to n and the ordering of vertices for triangle addition needs to be amended This is what needs to be looked at, and I am not proficient in 3D triangles and vertices to solve it. | 
| 
 | ||
| here is what I got so far. | 
| 
 | ||
| I think you misinterpreted the problem I have with the code. Your code sample does not solve these problems. The problem is with the accuracy of the placement of the triangles. __________ Your code sample has numerous issues of its own: 1) No roof for the walls - THE PROBLEM I HAVE IS WITH THE ROOF PLACEMENT _ SO HOW DOES IT HELP??? 2) Wall faces are rotated through Pi * radians. | 
| 
 | ||
| 1) Hidden geometries within wall segments i.e. .___. |_|_| In your code the dividing wall is still present and unnecessary. Here, the walls are split everytime it's required. Because, I just don't understand what you're talking about, could you make a screen of what you're trying to explain (and point at the problem you're issuing if possible) ? 2) No roof for the walls Yep, I never go further until the first step is validated, I prefer having a robust base to work on :) (So I didn't implement the roof/floors yet ... and it seems I was right, I don't know where we are going) 3) Wall faces are rotated through Pi * radians. Same as previous, I don't understand what you're meaning, sorry. | 
| 
 | ||
| Ok, so you edited your post ... I suppose there is no problem with the walls then. THE PROBLEM I HAVE IS WITH THE ROOF PLACEMENT _ SO HOW DOES IT HELP??? I think it's time for a break if you start yelling at me for nothing ^^. So, help yourself, I'm not here to support this kind of behavior. | 
| 
 | ||
| Here, the walls are split everytime it's required Yep, I never go further until the first step is validated, I prefer having a robust base to work on :) (So I didn't implement the roof/floors yet ... and it seems I was right, I don't know where we are going Roofs are where I am having the most problem, if you see the most recently updated version of my code (amended in first post). Floors arent necessary* but are simply refection of the roof anyway so easy enough to add once roofs are working. Same as previous, I don't understand what you're meaning, sorry. Now that I have looked more carefully I think I understand. You have created "Rooms" and "Corridoors" - the faces of the cuboids face inwards - whereas I was intending on an external 'maze' where the walls are 'solid'. In your case the walls are visible from INSIDE, yet mine need to be visible from OUTSIDE only.* A simple FlipMesh resolved this difference. *Hopefully this distinction between inside and outside clarifies a little why the roof is important but floors arent :) | 
| 
 | ||
| I wasn't intending to "yell" - the caps were to highlight the importance of the roofs. Sorry. | 
| 
 | ||
| Ok no problem so. If the walls have to be fliped, then the roof will be really complex and need a flood fill algorithm to detect the outline and exlude inner parts. So it needs to be devided into the largest convex polygons (or at least into convex polygons ... checking the best computation case could be a total brainacke) So, it needs to start from the first "used" cell then find the next point which create the segment (always is the same orientation), anytime you have at least 3 points, you need to check if there is any empty cell in the polygon (else, the polygon is not valid) and compute again and again until all polygons are done In other words, it's an ear-clipping algorithm. *Hopefully this distinction between inside and outside clarifies a little why the roof is important but floors arent :) Actually, it probably does not change anything to the algorithm, but it certainly modify all the result. (I was thinking about an "inside" maze, which would absolutely not look like what you were doing) | 
| 
 | ||
| I've jsut updated the initial code again. So it needs to be devided into the largest convex polygons (or at least into convex polygons ... checking the best computation case could be a total brainacke) So, it needs to start from the first "used" cell then find the next point which create the segment (always is the same orientation), anytime you have at least 3 points, you need to check if there is any empty cell in the polygon (else, the polygon is not valid) and compute again and again until all polygons are done In other words, it's an ear-clipping algorithm. Well considering there will (in the actual implementation of this system), not be any cases other than single-unit-thick walls - remember t's an external maze, not internal corridors -, then any area considerations should be restricted to the same as the side walls... So my code simply checks along the horizontal walls and flags them for a roof, then the same for the vertical - with the caveat that if already earmarked, that section will be skipped over. Then, final passes process the data for roof in the same way as the wall creation - extending the geometry to stretch from the start of a section along its length (whether in H or V direction) This code is encapsulated between the ;[Block] and ;[End Block] lines (I use IDEal) However, there s something faulty in that regions seem to be arbitrarily skipped and this is what I cannot understand. | 
| 
 | ||
| Yet another small update to the initial code. It is so VERY CLOSE now to completion. The error with the roof isnow confined to SPECIFIC CASES Where: Horizontal Wall segments (i.e extending along X axis with only "TOP"(z+1) and BOTTOM(Z-1) faces) Length > 2 units The segment at Length-1 from the horizontal start of the segment is skipped- I am unsure whether to simply "kludge" a specific fix for this, or continue to try and investigate the root of the issue. | 
| 
 | ||
| Ignore the above. Whilst that scenario described in the post above ALWAYS produces the error, it is not the only circumstance that does so... | 
| 
 | ||
| If there are no "lines" wider than one cell, then it makes things way more simple. ps : I see the issue in your code but it's a bit hard to notice where it comes from, because your code is a bit hard to follow (too many recursive function calls, it does not help tracking stuff). You might want to use Vertex color and color your segment in different colors according to the place it was called from, so you should notice easier which segment is faulty. Anyway, I think you have a weird issue that is not visible -> you have segment with no length On "PLANAR PASS VERTICAL 2" : extends from 1 block the length of the segment and they will appear as single blocks (so, with a unit less, they are just empty segment) at this part of the code If (CountingVertical) ;AddPLANAR_XZ_Z_Geometry(X,H-(Y-VerticalLength),VerticalLength,Surface) AddPLANAR_XZ_Z_Geometry(X,H-(Y-VerticalLength),VerticalLength+1,Surface); Add 1 unit to the length and the blocks appear. VerticalLength=0 CountingVertical=False End If | 
| 
 | ||
| Adding +1 tehre only adds extra unwanted geometry. _____________ The way the counting works is that each square is assessed in sequence the algorithm doesn't "know" it needs to start or stop counting length until it encounters the required trigger value X Grid Counter 0 0 nothing 1 0 nothing 2 1 START COUNTING LENGTH=1 3 1 LENGTH=2 4 1 LENGTH=3 5 0 CEASE COUNT. CURRENT X=5 - LENGTH (3) = CORRECT START X 2 6 0 ________________________________ The only exceptions are at the end of the rows/columns, whch, in my actual project will be inaccessible boundaries which are irrelevant. This can be identified easily with: Function ProcessPlanarHorizontal(X,Y,Length) If (Length<1) Then DebugLog(X+","+Y+" "+"H Length"+Length) ;....... Function ProcessPlanarVertical(X,Y,Length) If (Length<1) Then DebugLog(X+","+Y+" "+"V Length"+Length) | 
| 
 | ||
|  If there are no "lines" wider than one cell, then it makes things way more simple.  The code you posted here works perfectly. I am looking through it now to see how to change my code. It is a little difficult because they are similar but not identical approaches. I apologise for the difficulty in readability of the code I've posted - the ACTUAL project relies on data stored in banks and is reliant on other variables so much that it was simpler to throw this example together. Thanks very much for your help in this bobysait and you make it look so easy :) | 
| 
 | ||
| now have fun setting u,v coords to texture it properly ;) | 
| 
 | ||
|  now have fun setting u,v coords to texture it properly ;)   __ Not an issue, no texturing is required. However given the triangles are all aligned to axes and set to unit dimensions, the normals belie the 'top','bottom','left','right' or roof facing, therefore, it is simple to then apply the UV to each accordingly. _____________________________________________________________ Well I've made some progress and have the alignment correct, the roof is done, all invisible faces have no geometry and where a longer wall intersects a shorter one, the longer one takes priority in determining the roof geometry. | 
| 
 | ||
| In the BuildWalls function, I forgot a small mistake (it's not a bug, but it's a totally useless check) For j = 0 To H For i = 0 To W ; this cell has a top wall If ((HAS_WALL(i,j) And 1)>0) And ((HAS_WALL(i,j) And 1)>0) ; if this wall hasn't already been built If ((WALL_FLAG(i,j) And 1) = 0) -> If ((HAS_WALL(i,j) And 1)>0) And ((HAS_WALL(i,j) And 1)>0) this is twice the same test, it's an unremoved temporary code that has not been updated. replace it with If ( ( HAS_WALL(i,j) And 1 ) > 0 ) I not "better safe than sorry" but here, a single test will do the same job as two but faster :p | 
| 
 | ||
| Thanks, Bobysait. I had to essentially re-write the essence of your code entirely to match the critera and conventions of my actual project (which included a more complex determination of walls than just a binary wall or no wall,as well as using banks rather than arrays) so the minor issues such as that you mention were cleared up and addressed on the way. I do appreciate your clarity though :) |