Code archives/3D Graphics - Mesh/Polygon Reduction

This code has been declared by its author to be Public Domain code.

Download source code

Polygon Reduction by John J.2005
This polygon reduction function is based on the Blitz3D example at "examples\birdie\lodmesh" by David Bird.

Using the reduction function is extremely simple. Just call the MeshPolygonsReduce function, with the mesh and reduction amount.

Example:
MeshPolygonsReduce(ent,500) ;Reduce 500 polygons from 'ent'

For example code and media, download PolygonReduction.zip (11KB)
;=========================================================================
;Polygon Reduction Function - Based on the Blitz3D example at "examples\birdie\lodmesh" by David Bird
;-------------------------------------------------------------------------
;
;Using the reduction function is extremely simple. Just call the
;MeshPolygonsReduce Function, with the mesh and reduction amount. Example:
;
;MeshPolygonsReduce(ent,500) ;Reduce 500 polygons from 'ent'
;
;=========================================================================

;**** Internal data ****
Const MAXTRIS=100000

Dim PR_TriVisible(MAXTRIS)
Dim PR_TriCost#(MAXTRIS)
Dim PR_TriVert(MAXTRIS,3)
Dim PR_TriConnect(MAXTRIS,2)

Global PR_TriangleCount=0,PR_VertexCount=0
Global PR_CurrentSurface



;============================== Main Function ============================
;MeshPolygonsReduce (mesh, n)
;  inputmesh: The mesh to reduce
;  n: The amount of polygons to reduce from the inputmesh
Function MeshPolygonsReduce(mesh,n)
	;Make sure "mesh" is really a mesh
	If EntityClass$(mesh)<>"Mesh" Then
		RuntimeError "Can't reduce polygons of a "+Lower$(EntityClass$(mesh))
		Return
	End If
	
	If n<=0 Then Return ;Don't need to do anything
	
	;Divide n by the surface count
	n=n/CountSurfaces(mesh)
	If n<1 Then n=1 ;Don't do nothing

	;For every surface
	For surf=1 To CountSurfaces(mesh)
		;Get surface
		PR_CurrentSurface=GetSurface(mesh,surf)

		;Calculate surface data
		CalculateMeshData(mesh)
	
		;Remove n lowest cost polys from mesh
		For i=1 To n
			tri=LeastNeededTriangle()
			If tri<>-1 Then RemoveTriangle(tri)
		Next
	
		;Clear the surface's triangles
		ClearSurface PR_CurrentSurface,False,True

		;Regenerate the mesh with the new level of detail
		For i=0 To PR_TriangleCount
			If PR_TriVisible(i) Then
				AddTriangle PR_CurrentSurface,PR_TriVert(i,0),PR_TriVert(i,1),PR_TriVert(i,2)
			End If
		Next
	Next

	;Update the new mesh's normals
	UpdateNormals mesh
End Function
;-------------------------------------------------------------------------



;********* Internal Functions *********
Function CalculateMeshData(mesh)
	;Clear data
	PR_TriangleCount=0
	PR_VertexCount=0
	
	;Get vertex count
	PR_VertexCount=CountVertices(PR_CurrentSurface)
	
	;Initialise triangles
	PR_TriangleCount=CountTriangles(PR_CurrentSurface)-1
	For triindex=0 To PR_TriangleCount
		For i=0 To 2
			PR_TriVert(triindex,i)=TriangleVertex(PR_CurrentSurface,triindex,i)
		Next
		PR_TriVisible(triindex)=True
	Next
	
	;Process triangles
	For triindex=0 To PR_TriangleCount
		CalculateTriangleCost#(triindex) ;Calculate the triangle's importance
	Next
End Function

Function LeastNeededTriangle()
	;Find minimum cost
	minimumcost#=1000000
	triindex=-1
	For i=0 To PR_TriangleCount
		If PR_TriVisible(i) Then
			If PR_TriCost(i)<minimumcost Then 
				triindex=i
				minimumcost=PR_TriCost(i)
			End If
		End If
	Next
	;Return lowest triangle
	Return triindex
End Function

Function RemoveTriangle(tri)
	PR_TriVisible(tri)=False
	
	;Re-attach vertices
	oldvert=PR_TriVert(tri,PR_TriConnect(tri,0))
	newvert=PR_TriVert(tri,PR_TriConnect(tri,1))
	For i=0 To PR_TriangleCount
		changed=False
		If PR_TriVert(i,0)=oldvert Then PR_TriVert(i,0)=newvert:changed=True
		If PR_TriVert(i,1)=oldvert Then PR_TriVert(i,1)=newvert:changed=True
		If PR_TriVert(i,2)=oldvert Then PR_TriVert(i,2)=newvert:changed=True
		If changed Then ;Recalculate triangle cost if the triangle has been re-attached
			CalculateTriangleCost(i)
		End If
	Next
End Function

Function CalculateTriangleCost#(tri)
	;Calculate the edge sizes of the triangle
	x0#=VertexX(PR_CurrentSurface,PR_TriVert(tri,0)):y0#=VertexY(PR_CurrentSurface,PR_TriVert(tri,0)):z0#=VertexZ(PR_CurrentSurface,PR_TriVert(tri,0))
	x1#=VertexX(PR_CurrentSurface,PR_TriVert(tri,1)):y1#=VertexY(PR_CurrentSurface,PR_TriVert(tri,1)):z1#=VertexZ(PR_CurrentSurface,PR_TriVert(tri,1))
	x2#=VertexX(PR_CurrentSurface,PR_TriVert(tri,2)):y2#=VertexY(PR_CurrentSurface,PR_TriVert(tri,2)):z2#=VertexZ(PR_CurrentSurface,PR_TriVert(tri,2))
	coord0#=Sqr((x0-x1)^2+(y0-y1)^2+(z0-z1)^2)
	coord1#=Sqr((x1-x2)^2+(y1-y2)^2+(z1-z2)^2)
	coord2#=Sqr((x2-x0)^2+(y2-y0)^2+(z2-z0)^2)

	;Pick the best vertice to use when removing the triangle	
	If coord0<coord1 And coord0<coord2 Then n=1
	If coord1<coord0 And coord1<coord2 Then n=2
	If coord2<coord0 And coord2<coord1 Then n=3
	
	Select n
		Case 0
			PR_TriConnect(tri,0)=1:PR_TriConnect(tri,1)=0
		Case 1
			PR_TriConnect(tri,0)=1:PR_TriConnect(tri,1)=0
		Case 2
			PR_TriConnect(tri,0)=2:PR_TriConnect(tri,1)=1
		Case 3
			PR_TriConnect(tri,0)=0:PR_TriConnect(tri,1)=2
	End Select

	;Set the cost to the sum of the triangle's edges
	PR_TriCost#(tri)=coord0+coord1+coord2
End Function

Comments

jfk EO-111102005
this is cool.


Barliesque2005
Superb! Thanks for posting. :)


BlitzSupport2005
Excellent.


Panno2005
wow....


WildStorm2005
so cool


Neochrome2005
Perfect 10


slenkar2007
nice,
I tried it with a mesh of a man, it took the head off and removed the front of the chest,
I wonder if there is a way to fix this.. it could be a great tool.


Code Archives Forum