Metaballs

Blitz3D Forums/Blitz3D Programming/Metaballs

Have anyone tried to make real-time meatballs???
I'm just starting a metaball project...

Need some pointers...perhaps

Sveinung


Have anyone tried to make real-time meatballs???



:o)

That's-a spicy metaball-a! <smooch!>

Sum one posted sum 2d mataball examples over a http://www.blitzcoder.com/ a while back.

Hi

I wrote one a while ago But stopped the project due to the heavy copyrights attached to the marching cubes algorithm.

http://quill3d.users.btopenworld.com/proggies/metaballs.zip

If I can find the info that I used I'll post a link to it here. :)

cheers

Thats pretty pimp Birdie, nice work.

what are metaballs?

-> Birdie
Hope you find it....nice work by the way!

Sveinung

DarkEagle, Apparently metaballs are representations of an isosurface in 3d space. (well it could be in 2d but who wants flat balls these days?) And its a bit mindblowing. Still you did ask so now you have to read this... http://www.olympus.net/personal/mortenson/preview/definitionsm/metaballs.html
and then this... http://www.siggraph.org/education/materials/HyperGraph/modeling/metaballs/metaballs.htm
and perhaps this... http://www.daimi.au.dk/~u950710/meta/metaball_eng.html
and some of this might be useful... http://www.unchainedgeometry.com/jbloom/papers/index.html
implementation... http://www.cfxweb.net/modules.php?name=News&file=article&sid=199
Paul Bourke again... http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/
http://astronomy.swin.edu.au/~pbourke/modelling/implicitsurf/index.html
http://astronomy.swin.edu.au/~pbourke/modelling/polytetra/
Or you might decide to just download birdies demo and see it in all in action (note the wireframe option). I guess the tricky bit is polygonizing the isosurface. Hence the marching cubes algorithm. There are apparently other ways. I expect its the case that Marching cubes is the best though (or easiest), which is why its copyrighted.

[edit]
Long discussion on the patent (not copyright) issue.
Marching Cubes Patents and You
An alternative algo
Multiresolution Isosurface Extraction with Adaptive Skeleton Climbing

How do you copyright a bloody algorythm anyway? If it is mathematically proven to be the most efficient algo, what then?

Not cpyrighted. PATENTED. Blame the US patent office. I wish people would start suing them for allowing unlawful patents.

All I will say is that is well documented and have most of (if not all)the variations of the same algorythm covered in the patent. Aparently they are pretty up on the taking peeps to court over use of the algo aswell. For that reason I decided to drop it lol.

Anyways heres the code I used, dont use it in any comercial projects for the above reasons ;)

If anyone finds another (legal) way of doing this I'd be intrested in hearing about it :)

Global MEtaPivot
Include "Constants.bb"
Const TargetValue#=.5
Const C_SPHERE	=1
Const C_CUBE	=2

Global TheStep#

Global GridSize
Global GridMapSize
Global HGridSize
Global GridBank			;this is to hold the computations

Function InitMetaGrid(size)
	MEtaPivot=CreateMesh()
	GridSize=size
	HGridSize=size/2
	GridMapSize=GridSize*GridSize
	GridBank=CreateBank(size*size*size)	; 1 byte to hold if its computed
End Function

Function ClearMetaGrid()
	For a=0 To BankSize(GridBank)-1 Step 4
		PokeInt GridBank,a,0
	Next
End Function

Function SetComputed(x#,y#,z#)
	pos=(GridMapSize*z)+((y*GridSize)+x)
	PokeByte GridBank,pos,1
End Function

Function IsComputed(x#,y#,z#)
	pos=(GridMapSize*z)+((y*GridSize)+x)
	If PeekByte(GridBank,pos)=1 Then Return True
	Return False
End Function 

Type mvec
	Field x#
	Field y#
	Field z#
End Type

Function GetNormal( n.mvec,x#,y#,z#)
	n\x=ComputeEnergy(x-0.01,y,z)-ComputeEnergy(x+0.01,y,z)
	n\y=ComputeEnergy(x,y-0.01,z)-ComputeEnergy(x,y+0.01,z)
	n\z=ComputeEnergy(x,y,z-0.01)-ComputeEnergy(x,y,z+0.01)
End Function

;------------------------------------------------------------------------------
;IntersectOnEdge finds the approximate point of intersection of the surface
;between two points with the values point1 and point2
Function IntersectOnEdge#(point1#,point2#,result#)
        difference# = point2 - point1
        If difference = 0.0
			Return 0.5;
        	EndIf
        Return (result - point1)/difference
End Function ;IntersectOnEdge

;Polygonise1() performs the Marching Cubes algorithm on a single cube
Function Polygonise(x#,y#,z#,surf)
        Local intersection#, ValueOfCube#[8];
        Local VertexOfEdge.mvec[12], NormalOfEdge.mvec[12]
        Local corner,vertex,edge,triangle,index,edgeFlags
        ;Make a Local copy of the values at the cube's corners
        For vertex = 0 To 7
			ValueOfCube[vertex] = ComputeEnergy#(x+CubeVertex(vertex,0)*TheStep,y + CubeVertex(vertex,1)*TheStep,z + CubeVertex(vertex,2)*TheStep);
        Next
        ;Find which vertices are inside of the surface And which are outside
        index = 0;
        For vertex = 0 To 7
			If ValueOfCube[vertex] <= TargetValue
				index = Index Or (1 Shl vertex)
			EndIf
		Next
		;Find which edges are intersected by the surface
        edgeFlags = CubeEdgeIntersect(index);
		;If the cube is entirely inside Or outside of the surface, Then there will be no intersections
        If edgeFlags = 0 Then Return
		;Find the point of intersection of the surface with Each edge
		;Then find the normal To the surface at those points
        For edge = 0 To 11
			;If there is an intersection on this edge
			If edgeFlags And (1 Shl edge)
				intersection=IntersectOnEdge(ValueOfCube[CubeEdge(edge,0)],ValueOfCube[CubeEdge(edge,1)],targetValue);
				VertexOfEdge[edge]=New mvec
				NormalOfEdge[edge]=New mvec
				VertexOfEdge[edge]\X=x+(CubeVertex(CubeEdge(edge,0),0)+intersection*EdgeDirection(edge,0))*TheStep;
				VertexOfEdge[edge]\Y=y+(CubeVertex(CubeEdge(edge,0),1)+intersection*EdgeDirection(edge,1))*TheStep;
				VertexOfEdge[edge]\Z=z+(CubeVertex(CubeEdge(edge,0),2)+intersection*EdgeDirection(edge,2))*TheStep;
                GetNormal NormalOfEdge[edge],VertexOfEdge[edge]\X, VertexOfEdge[edge]\Y, VertexOfEdge[edge]\Z
			EndIf
        Next
		;Draw the triangles that were found.  There can be up To 5 per cube
		c=CountVertices(surf)
        For triangle=0 To 4
			If CubeTriangles(index,3*triangle)>=0 Then
	            For corner=0 To 2
					vertex = CubeTriangles(index,3*triangle+corner)
					tv=AddVertex(surf,VertexOfEdge[vertex]\X, VertexOfEdge[vertex]\Y, VertexOfEdge[vertex]\z)
					c=c+1
					VertexNormal surf,tv,NormalOfEdge[vertex]\X, NormalOfEdge[vertex]\Y, NormalOfEdge[vertex]\Z
				Next
				AddTriangle surf,c-3,c-2,c-1
			EndIf
		Next
		Delete Each mvec
End Function ;Polyginise1()

Function Check_Corners(x#,y#,z#)
	For vertex = 0 To 7
 		If ComputeEnergy#(x+CubeVertex(vertex,0)*TheStep,y+CubeVertex(vertex,1)*TheStep,z+CubeVertex(vertex,2)*TheStep)>TargetValue
			Return True
		EndIf
	Next
	Return False
End Function

Function RenderMetaBalls(surf,stp)
	For be.Meta_Blob=Each meta_blob
		FindSetVoxel be\x,be\y,be\z,surf,stp
	Next
End Function


;WARNING RECURSIVE
Function FindSetVoxel(x,y,z,surf,stp)
	;if this one is computed then return
	If IsComputed(x/stp,y/stp,z/stp)=False Then
		;if none of the corners are within the surface return
		If Check_Corners(x,y,z)=False Then 
			SetComputed x,y,z
			Return
		Else
			SetComputed x/stp,y/stp,z/stp
			Polygonise(x,y,z,surf)
			;now check all the faces of the cube
			FindSetVoxel(x+stp,y,z,surf,stp)
			FindSetVoxel(x-stp,y,z,surf,stp)
			FindSetVoxel(x,y+stp,z,surf,stp)
			FindSetVoxel(x,y-stp,z,surf,stp)
			FindSetVoxel(x,y,z+stp,surf,stp)
			FindSetVoxel(x,y,z-stp,surf,stp)
		EndIf
	Else
		Return
	EndIf
End Function

Graphics3D 800,600,0,2
SetBuffer BackBuffer()
piv=CreatePivot()
PositionEntity piv,75,75,75
cam=CreateCamera(piv)
PositionEntity cam,0,0,-100
tex=LoadTexture("spheremap.jpg",65)
TheStep=8

m=CreateMesh()
EntityTexture m,tex
EntityFX m,1
FreeTexture tex
CameraClsColor cam,150,150,150

surf=CreateSurface(m)
l=CreateLight()

New_Metacube(75,75,75,20)
New_MetaSphere(50,45,75,10)
New_MetaSphere(50,45,75,10)

InitMetaGrid 200
w=1
While Not KeyDown(1)
ren=0
	tim=MilliSecs()
	If KeyDown(203) Then TurnEntity piv,0,6,0
	If KeyDown(205) Then TurnEntity piv,0,-6,0
	If KeyDown(200) Then TurnEntity piv,6,0,0
	If KeyDown(208) Then TurnEntity piv,-6,0,0
	If KeyHit(17) Then w=1-w
	WireFrame w
	t=MilliSecs()
	MoveBalls()	
	ClearSurface surf,True,True
	If KeyDown(57) =0 
		ClearMetaGrid
		RenderMetaBalls surf,TheStep
	EndIf
	RenderWorld
	
;	AppTitle "Meta Balls. David Bird. Press W for wireframe "+1000/(MilliSecs()-tim)+" FPS"
	If ren=1 Then Text 320,0,"High res Mesh Render.",1
	Flip 1
	If ren=1 Then WaitKey
Wend
End

Function MoveBalls()
	For b.Meta_Blob=Each Meta_Blob
		dx#=b\dx
		dy#=b\dy
		dz#=b\dz
		b\x=b\x+dx
		b\y=b\y+dy
		b\z=b\z+dz
		n=0
		If b\x<50 Or b\x>100 Then n=1
		If b\y<50 Or b\y>100 Then n=1
		If b\z<50 Or b\z>100 Then n=1
		If n=1 Then
			b\dx=-b\dx
			b\dy=-b\dy
			b\dz=-b\dz
		EndIf
		b\ax=b\ax+5
		b\ay=b\ay+5
		b\az=b\az+5
	Next
End Function

Type Meta_Blob
	Field typ					;
	Field mag#					;mass
	Field half_mag_inv_4th#		;
	Field mag_4th#				;
	Field rad#					;
	Field inner_rad#			;
	Field x#,y#,z#				;position
	Field ax#,ay#,az#			;rotation
	Field dx#,dy#,dz#
End Type

Function ComputeEnergy#(px#,py#,pz#)
	Local dist_in_xz#, dist_in_y#, dist_from_track_squared#;
	Local r_squared#,r_4th#,dx#,dy#,dz#
	Local q#,mag#
	For blob.Meta_Blob=Each Meta_Blob
		PositionEntity MEtaPivot,blob\x,blob\y,blob\z
		RotateEntity MEtaPivot,blob\ax,blob\ay,blob\az
		TFormPoint px,py,pz,0,MEtaPivot
		dx = TFormedX();px - blob\x;
		dy = TFormedY();py - blob\y;
		dz = TFormedZ();pz - blob\z;
		Select blob\typ
			Case C_SPHERE
				r_squared = dx*dx + dy*dy + dz*dz
				r_squared = blob\mag/r_squared
				q = q + r_squared
			Case C_CUBE
				dx = dx*dx*dx*dx
				dy = dy*dy*dy*dy
				dz = dz*dz*dz*dz
				r_4th = Abs(dx+dy+dz)
				r_4th = (blob\mag_4th/r_4th)
				q = q  + r_4th 
		End Select
	Next
	target=q
	Return q	;return the energy
End Function

Function UpdateMetaBlobs()
	For b.Meta_Blob=Each Meta_Blob
		Select b\typ
			Case C_SPHERE
				b\mag=b\rad*b\rad
			Case C_CUBE
				b\mag_4th=b\rad*b\rad*b\rad*b\rad
				b\half_mag_inv_4th=-b\mag_4th/2
		End Select
	Next
End Function 

Function New_MetaSphere.meta_blob(x#,y#,z#,rad#)
	b.meta_blob=New meta_blob
		b\typ=C_SPHERE
		b\x=x
		b\y=y
		b\z=z
		b\mag=(rad*rad)
		b\rad=rad
		b\dx=Rnd(-2,2)
		b\dy=Rnd(-2,2)
		b\dz=Rnd(-2,2)
	Return b
End Function

Function New_MetaCube.meta_blob(x#,y#,z#,rad#)
	b.meta_blob=New meta_blob
		b\typ=C_CUBE
		b\x=x
		b\y=y
		b\z=z
		b\rad=rad
		b\mag_4th=rad*rad*rad*rad
		b\half_mag_inv_4th=-b\mag_4th/2
		b\dx=Rnd(-2,2)
		b\dy=Rnd(-2,2)
		b\dz=Rnd(-2,2)
	Return b
End Function


and the constants.bb file

;------------------------------------------------------------------------------
;constants
Const DEG_TO_RAD = Pi / 180.0;
Const RAD_TO_DEG = 180.0 / Pi;
Const EPSILON = 0.000001
Const INFINITY = 1000000
;------------------------------------------------------------------------------
;These tables are used so that everything can be done in little loops that you can look at all at once
;rather than in pages and pages of unrolled code.

;CubeVertex lists the positions, relative to vertex0, of each of the 8 vertices of a cube
Dim CubeVertex#(8,3)
For a=0 To 7
	For b=0 To 2
		Read CubeVertex(a,b)
	Next
Next
Data 0.0, 0.0, 0.0 , 1.0, 0.0, 0.0 , 1.0, 1.0, 0.0 , 0.0, 1.0, 0.0
Data 0.0, 0.0, 1.0 , 1.0, 0.0, 1.0 , 1.0, 1.0, 1.0 , 0.0, 1.0, 1.0
;CubeEdge lists the index of the endpoint vertices For Each of the 12 edges of the cube
Dim CubeEdge(12,2)
For a=0 To 11
	For b=0 To 1
		Read CubeEdge(a,b)
	Next
Next
Data 0,1 , 1,2 , 2,3 , 3,0
Data 4,5 , 5,6 , 6,7 , 7,4
Data 0,4 , 1,5 , 2,6 , 3,7
;EdgeDirection lists the direction vector (vertex1-vertex0) For Each edge in the cube
Dim EdgeDirection#(12,3)
For a=0 To 11
	For b=0 To 2
		Read EdgeDirection(a,b)
	Next
Next
Data 1.0,0.0,0.0 , 0.0,1.0,0.0 , -1.0,0.0,0.0 , 0.0, -1.0,0.0
Data 1.0,0.0,0.0 , 0.0,1.0,0.0 , -1.0,0.0,0.0 , 0.0, -1.0,0.0
Data 0.0,0.0,1.0 , 0.0,0.0,1.0 ,  0.0,0.0,1.0 , 0.0,  0.0,1.0

;TetrahedronEdge lists the index of the endpoint vertices
;for each of the 6 edges of the tetrahedron
Dim TetrahedronEdge(6,2)
For a=0 To 5
	For b=0 To 1
		Read TetrahedronEdge(a,b)
	Next
Next
Data 0,1 , 1,2 , 2,0 , 0,3 , 1,3 , 2,3

;CubeTetrahedrons lists the index of vertices from a cube
;that made up each of the six tetrahedrons within the cube
Dim CubeTetrahedrons(6,4)
For a=0 To 5
	For b=0 To 3
		Read CubeTetrahedrons(a,b)
	Next
Next
Data  0,5,1,6 , 0,1,2,6 , 0,2,3,6 , 0,3,7,6 , 0,7,4,6 , 0,4,5,6 

Dim TetraEdgeIntersec(16)
For a=0 To 15
	Read TetraEdgeIntersec(a)
Next
Data $00,$0d,$13,$1e,$26,$2b,$35,$38,$38,$35,$2b,$26,$1e,$13,$0d,$00

;For each of the possible vertex states listed in TetraEdgeIntersec there is a specific triangulation
;of the edge intersection points.  TetrahedronTriangles lists all of them in the form of
;0-2 edge triples with the list terminated by the invalid value -1.
;I generated this table by hand

Dim TetrahedronTriangles(16,7)
For a=0 To 15
	For b=0 To 6
		Read TetrahedronTriangles(a,b)
	Next
Next
Data  -1, -1, -1, -1, -1, -1, -1
Data   0,  3,  2, -1, -1, -1, -1
Data   0,  1,  4, -1, -1, -1, -1
Data   1,  4,  2,  2,  4,  3, -1
Data   1,  2,  5, -1, -1, -1, -1
Data   0,  3,  5,  0,  5,  1, -1
Data   0,  2,  5,  0,  5,  4, -1
Data   5,  4,  3, -1, -1, -1, -1
Data   3,  4,  5, -1, -1, -1, -1
Data   4,  5,  0,  5,  2,  0, -1
Data   1,  5,  0,  5,  3,  0, -1
Data   5,  2,  1, -1, -1, -1, -1
Data   3,  4,  2,  2,  4,  1, -1
Data   4,  1,  0, -1, -1, -1, -1
Data   2,  3,  0, -1, -1, -1, -1
Data  -1, -1, -1, -1, -1, -1, -1

;// For any edge, if one vertex is inside of the surface and the other is outside of the surface
;//  then the edge intersects the surface
;// For each of the 8 vertices of the cube can be two possible states : either inside or outside of the surface
;// For any cube the are 2^8=256 possible sets of vertex states
;// This table lists the edges intersected by the surface for all 256 possible vertex states
;// There are 12 edges.  For each entry in the table, if edge #n is intersected, then bit #n is set to 1

Dim CubeEdgeIntersect(256)
For a=0 To 255
	Read CubeEdgeIntersect(a)
Next
Data $000, $109, $203, $30a, $406, $50f, $605, $70c, $80c, $905, $a0f, $b06, $c0a, $d03, $e09, $f00
Data $190, $099, $393, $29a, $596, $49f, $795, $69c, $99c, $895, $b9f, $a96, $d9a, $c93, $f99, $e90
Data $230, $339, $033, $13a, $636, $73f, $435, $53c, $a3c, $b35, $83f, $936, $e3a, $f33, $c39, $d30
Data $3a0, $2a9, $1a3, $0aa, $7a6, $6af, $5a5, $4ac, $bac, $aa5, $9af, $8a6, $faa, $ea3, $da9, $ca0
Data $460, $569, $663, $76a, $066, $16f, $265, $36c, $c6c, $d65, $e6f, $f66, $86a, $963, $a69, $b60
Data $5f0, $4f9, $7f3, $6fa, $1f6, $0ff, $3f5, $2fc, $dfc, $cf5, $fff, $ef6, $9fa, $8f3, $bf9, $af0
Data $650, $759, $453, $55a, $256, $35f, $055, $15c, $e5c, $f55, $c5f, $d56, $a5a, $b53, $859, $950
Data $7c0, $6c9, $5c3, $4ca, $3c6, $2cf, $1c5, $0cc, $fcc, $ec5, $dcf, $cc6, $bca, $ac3, $9c9, $8c0
Data $8c0, $9c9, $ac3, $bca, $cc6, $dcf, $ec5, $fcc, $0cc, $1c5, $2cf, $3c6, $4ca, $5c3, $6c9, $7c0
Data $950, $859, $b53, $a5a, $d56, $c5f, $f55, $e5c, $15c, $055, $35f, $256, $55a, $453, $759, $650
Data $af0, $bf9, $8f3, $9fa, $ef6, $fff, $cf5, $dfc, $2fc, $3f5, $0ff, $1f6, $6fa, $7f3, $4f9, $5f0
Data $b60, $a69, $963, $86a, $f66, $e6f, $d65, $c6c, $36c, $265, $16f, $066, $76a, $663, $569, $460
Data $ca0, $da9, $ea3, $faa, $8a6, $9af, $aa5, $bac, $4ac, $5a5, $6af, $7a6, $0aa, $1a3, $2a9, $3a0
Data $d30, $c39, $f33, $e3a, $936, $83f, $b35, $a3c, $53c, $435, $73f, $636, $13a, $033, $339, $230
Data $e90, $f99, $c93, $d9a, $a96, $b9f, $895, $99c, $69c, $795, $49f, $596, $29a, $393, $099, $190
Data $f00, $e09, $d03, $c0a, $b06, $a0f, $905, $80c, $70c, $605, $50f, $406, $30a, $203, $109, $000

;For each of the possible vertex states listed in CubeEdgeIntersec there is a specific triangulation
;of the edge intersection points.  a2iTriangleConnectionTable lists all of them in the form of
;0-5 edge triples with the list terminated by the invalid value -1.
;For example: a2iTriangleConnectionTable[3] list the 2 triangles formed when corner[0]
;and corner[1] are inside of the surface, but the rest of the cube is not.
;
;I found this table in an example program someone wrote long ago.  It was probably generated by hand

Dim CubeTriangles(256,16)
For a=0 To 255
	For b=0 To 15
		Read CubeTriangles(a,b)
	Next
Next
Data -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1
Data 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1
Data 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1
Data 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1
Data 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1
Data 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1
Data 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1
Data 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1
Data 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1
Data 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1
Data 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1
Data 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1
Data 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1
Data 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1
Data 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1
Data 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1
Data 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1
Data 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1
Data 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1
Data 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1
Data 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1
Data 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1
Data 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1
Data 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1
Data 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1
Data 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1
Data 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1
Data 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1
Data 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1
Data 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1
Data 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1
Data 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1
Data 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1
Data 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1
Data 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1
Data 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1
Data 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1
Data 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1
Data 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1
Data 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1
Data 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1
Data 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1
Data 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1
Data 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1
Data 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1
Data 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1
Data 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1
Data 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1
Data 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1
Data 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1
Data 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1
Data 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1
Data 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1
Data 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1
Data 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1
Data 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1
Data 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1
Data 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1
Data 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1
Data 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1
Data 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1
Data 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1
Data 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1
Data 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1
Data 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1
Data 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1
Data 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1
Data 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1
Data 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1
Data 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1
Data 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1
Data 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1
Data 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1
Data 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1
Data 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1
Data 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1
Data 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1
Data 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1
Data 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1
Data 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1
Data 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1
Data 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1
Data 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1
Data 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1
Data 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1
Data 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1
Data 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1
Data 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1
Data 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1
Data 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1
Data 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1
Data 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1
Data 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1
Data 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1
Data 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1
Data 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1
Data 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1
Data 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1
Data 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1
Data 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1
Data 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1
Data 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1
Data 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1
Data 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1
Data 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1
Data 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1
Data 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1
Data 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1
Data 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1
Data 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1
Data 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1
Data 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1
Data 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1
Data 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1
Data 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1
Data 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1
Data 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1
Data 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1
Data 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1
Data 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1
Data 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1
Data 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1
Data 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1
Data 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1
Data 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1
Data 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1
Data 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1
Data 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1
Data 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1
Data 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1
Data 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1
Data 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1
Data 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1
Data 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1
Data 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1
Data 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1
Data 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1
Data 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1
Data 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1
Data 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1
Data 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1
Data 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1
Data 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1
Data 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1
Data 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1
Data 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1
Data 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1
Data 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1
Data 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1
Data 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1
Data 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1
Data 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1
Data 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1
Data 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1
Data 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1
Data 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1
Data 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1
Data 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1
Data 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1
Data 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1
Data 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1
Data 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1
Data 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1
Data 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1
Data 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1
Data 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1
Data 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1
Data 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1
Data 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1
Data 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1
Data 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1
Data 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1
Data 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1
Data 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1
Data 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1
Data 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1
Data 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1
Data 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1
Data 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1
Data 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1
Data 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1
Data 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1
Data 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1
Data 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1
Data 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1
Data 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1
Data 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1
Data 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1
Data 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
Data -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1


Darkeagle, metaballs are used to represent a liquid/blobby surface like water (duh, I just said "liquid") or organic flesh. The idea is that a mesh surface is created by "melting" together a whole bunch of metaballs. Specifically, the closer together two metaballs are the more the resulting surface blends the two together. Compare metaballs to water droplets; when distant the droplets are distinct and separate but when moved close together they merge into a single blobby shape. If the balls move around the surface is updated, resulting in an undulating liquid.

People used to be interested in metaballs as a technique for organic modeling but eventually the extremely dense and unweildy meshes which result forced metaballs out of favor. Now metaballs are mostly used for representing water with a particle system (with metaballs for particles.)

I can't believe that the algo, and all obvious variations is patented. Insane. Most mathematicians would be up in arms about that I would imagine. Is that patent only good for the US, btw?


by Jeff Lander
Gamasutra
May, 23, 2000

The Marching Cubes Patent Question

As many of you who have met me and heard me rant on the topic know, I believe algorithmic software patents are totally wrong. I feel they completely halt continued development down interesting research pathways by shrouding a topic with legal pitfalls. Graphics researchers create progress by building on the work done by others before them. I like to imagine the state of the industry if Bresenham had patented his method for drawing a line on a graphic display and then charged a licensing fee for every line drawn.

The topic of volume rendering is an interesting case in point. As an obvious next step in the visualization of volume data, it was reported by researchers in several publications. However, General Electric apparently owns a patent on the technique via the Lorenson and Cline implementation (U.S. patent #4,710,876). As an actual apparatus to display medical imaging data, I can understand it. However, the patenting of a "method for displaying three-dimensional surface images" seems pretty broad to me.

I have been told by someone via e-mail that GE aggressively enforces this patent. However, it is not clear to me how this would apply to the rendering of an isosurface in a game. Does this mean that any modeling program using these techniques must pay a license to GE? If I create a game using a derivative of marching cubes and it is a big hit, am I going to receive a stealth patent letter in the mail demanding a percentage? How derivative does it need to be? The prior art on this topic seems limitless, but what can I use as a reference and still be safe?

With the record number of software patents being filed, this is going to become an increasingly difficult issue for game developers in the future. I am actively researching the issue and hope to report on the results in a later column. Anyone with information on the topic, please let me know. In the meantime, always document your research from public journals as best you can. Ignorance is not bliss in this situation.





I did read somewhere else that the patent doesn't just cover the US but its a global patent which in itself costs a fortune. So I cant see them letting anything go for free.

How can they tell? they cannot force you to reveal your sourcecode surely?

someone really needs to think up a marching hexagon formula.

Someone already came up with marching tetrahedrons.

I'm sure there's ways to do similar things as marching cubes, and get smoother results. Marching cubes isn't very good actually. It makes very blocky geometry. You actually need to then push the vertcies out or in a little so they lie on the actual surface, which then gives you nice round shapes.

Glad to hear I'm not the only one who is utterly disgusted by this. So much of current laws regarding intellectual property desperately need to be thrown on the furnace.

copy right laws are becoming stupid and are halting progress to no end. As noted above people need to sue the patent offices for allowing peopel to patent things that are unlawfull. HEck there was a guy who tried to sue the NFL for there was of drawing football allgorithyms, because he had a patent on it. I am not joking. Infact he woudl of won if the nfl did nto have so much money.

Click here if you want to use metaballs.

Btw: GE = j.p. Morgan.

Dear all

I am using blitz3d to visualise and interact with 3d medical models that I have created from 2d CT/MRI/fluoroscopic scans. I use a very narrow camera clip to 'move through' the structure, but as the structure is surface rendered, the object appears 'hollow'. I understand that metaballs are esentially objects volume rendered, so using the camera clip to move through this object, would the object appear 'solid'? Does anyone else have any experience with this? I am aware of the GE algorithm issue regarding patent, but does it apply to games or medical images?

Cheers Shawnus

No. Any metaballs generated with Blitz really just generate a 3D mesh, which is hollow.

If you want a 3D object you can move through, and view the inside of then what you want is voxels.

Voxels are basically little cubes, or quads that are rotated to face the camera. Each voxel represents what the color of the object is at that point in space.

Individual voxels will dissapear though if they pass beyond the camera. If you want volumes that appears totally solid, then you'll need to clip cubes against the near camera plane and reconstruct the surface there... I would reccomend having a specific surface just for capping polygons. You don't actually have to cut the cubes apart, just create new polygons inside them on a new surface that will lie flush with the camera view. But that won't let you view it from far away and slice a portion away, which seems like it would be much more useful.

There's a lot of ways to do what you want to do really, and none are particularly easy, and making it fast too is a challenge.

sswift,
Do you know of any examples of this interactive 'cube clipping' that have been done in Blitz? Is there a game engine that will support volume rendering, or is this limited to just medical workstations? I think this challenge is well beyond me...
Cheers Shawnus

You cant have a global patent if a country doesnt recognise software algorithm patents.

I wanna patent the use of crap patents to screw people for no particular good reason.

Lovelly example Birdie.

Are there other ways to do Metaballs?
If this ridiculous patent is implied.

can you use the stuff if you dont sell it at all?
like just make a tool to use?
...

Is there another way, with morphing the objects.
This is something I'd very much love to be able to do and espeically in B3D; as I've seen this in some top gfx demos. Any pointers, snippets etc would be grand.

Actually, I contacted GE about the patents this summer. One of the two patents was dropped earlier this year, the second is still being held. You have to contact one of their lawyers/businessmen to purchase a license to use the patent. If anyone wants one of their lawyer's e-mail addresses to contact them, let me know. They're very straight-forward, so don't expect a whole bunch of legal crap from them if you're just asking about the patents.

soooo can you use it just to make a tool that you arent selling?

soooo can you use it just to make a tool that you arent selling?


You have to contact one of their lawyers/businessmen to purchase a license to use the patent.


Stuff like is really annoying and the bad thing is that EU has a patent system for software and algorithm as well due to this US example :(

on the other hand this has it's good side: the 3D stuff won't progress much further, so I don't have to buy new hardware ;-)

So is "marching cubes" the only way possible to make metaballs?

No.

Among the others is one called marching triangles, but that isn't the only algorithm.

I like meatballs.

Cheers :)

What other ways are there then dude?