This code divides meshes up into surfaces by triangle normals. It creates a list of all triangle normals, merging faces that have normals within a specified limit, then rebuilds the mesh so that each surface contains only triangles within a certain range of normals. The same routine can be used to split a single-surface mesh up into coplanar surfaces (for lightmapping, BSP, and CSG), or it can merge a mesh into a single surface.
Graphics3D 800,600,16,2 cam=CreateCamera() CameraClsColor cam,255,255,255 TurnEntity cam,45,45,0 MoveEntity cam,0,0,-15 m=LoadMesh("box.3ds") ScaleMesh m,.1,.1,.1 os=CountSurfaces(m) EntityColor m,255,0,0 result=WeldMesh(m,0.1) FreeEntity m While Not KeyHit(1) TurnEntity result,0,1,1 RenderWorld Color 0,0,0 Text 0,0,os+" surfaces split into "+CountSurfaces(result)+" surfaces." Flip Wend End Function WeldMesh(mesh,limit#=0.1) facebank=CreateBank() result=CreateMesh() For s=1 To CountSurfaces(mesh) surf=GetSurface(mesh,s) For t=0 To CountTriangles(surf)-1 A=TriangleVertex(surf,t,0) B=TriangleVertex(surf,t,1) C=TriangleVertex(surf,t,2) TriangleNormal VertexX(surf,A),VertexY(surf,A),VertexZ(surf,A),VertexX(surf,B),VertexY(surf,B),VertexZ(surf,B),VertexX(surf,C),VertexY(surf,C),VertexZ(surf,C) nx#=VectorX() ny#=VectorY() nz#=VectorZ() face=FaceExists(facebank,nx,ny,nz,limit) If face>-1 trislist=PeekInt(facebank,16*face+12) appendint trislist,surf appendint trislist,t Else appendfloat facebank,nx appendfloat facebank,ny appendfloat facebank,nz trislist=CreateBank() appendint facebank,trislist appendint trislist,surf appendint trislist,t EndIf Next Next For n=0 To BankSize(facebank)/16-1 newsurf=CreateSurface(result) b=CreateBrush() BrushColor b,Rand(255),Rand(255),Rand(255) PaintSurface newsurf,b FreeBrush b trislist=PeekInt(facebank,16*n+12) For t=0 To BankSize(trislist)/8-1 surf=PeekInt(trislist,t*8) ti=PeekInt(trislist,t*8+4) A=TriangleVertex(surf,ti,0) B=TriangleVertex(surf,ti,1) C=TriangleVertex(surf,ti,2) A=VertexExists(newsurf,VertexX(surf,A),VertexY(surf,A),VertexZ(surf,A)) B=VertexExists(newsurf,VertexX(surf,B),VertexY(surf,B),VertexZ(surf,B)) C=VertexExists(newsurf,VertexX(surf,C),VertexY(surf,C),VertexZ(surf,C)) AddTriangle newsurf,A,B,C Next Next FreeBank facebank Return result End Function Function VertexExists(surf,x#,y#,z#,accuracy#=0.00001) For v=0 To CountVertices(surf)-1 If PointDistance(x,y,z,VertexX(surf,v),VertexY(surf,v),VertexZ(surf,v))<=accuracy Return v Next Return AddVertex(surf,x,y,z) End Function Function FaceExists(bank,x#,y#,z#,limit#) For n=0 To BankSize(bank)/16-1 nx#=PeekFloat(bank,n*16) ny#=PeekFloat(bank,n*16+4) nz#=PeekFloat(bank,n*16+8) SubVector x,y,z,nx,ny,nz If Magnitude(VectorX(),VectorY(),VectorZ())<=limit Return n Next Return -1 End Function Function appendint(buffer,value) ResizeBank buffer,BankSize(buffer)+4 PokeInt buffer,BankSize(buffer)-4,value End Function Function appendfloat(buffer,value#) ResizeBank buffer,BankSize(buffer)+4 PokeFloat buffer,BankSize(buffer)-4,value End Function