Meshes zerschneiden

Übersicht BlitzBasic Codearchiv

Neue Antwort erstellen

Noobody

Betreff: Meshes zerschneiden

BeitragFr, Apr 17, 2009 21:58
Antworten mit Zitat
Benutzer-Profile anzeigen
Dank einer Anregung von Steven04 habe ich mich daran gemacht, einen Algorithmus zu schreiben, der Meshes an einer Ebene in zwei Teile spaltet.
Die Funktion kann beliebig viele Surfaces verarbeiten und berechnet auch die Texturkoordinaten der neu gesetzten Vertices.

Leider mag sie es nicht, wenn die Trennebene perfekt durch einen Vertex hindurchgeht - das quittiert sie mit der Meldung 'Something wrong here'.
Die Funktion funktioniert mit allen Primitiven von Blitz, andere Meshes standen mir leider nicht zum Testen zur Verfügung. Daher wäre ich um Rückmeldung froh, wenn gewisse Meshes gehen oder auch nicht gehen.

Zum Trennen des Meshs muss "SplitMesh" aufgerufen werden. Sie verlangt als ersten Parameter das Mesh, das zerschnitten werden soll, dann die Ebene in Form eines Punktes und einer Richtung. Die Ebene geht dann durch diesen Punkt und steht senkrecht auf der angegebenen Richtung.
Zurückgegeben wird das Mesh, das abgespalten wurde.

Der Code: Code: [AUSKLAPPEN]
Graphics3D 800, 600, 0, 2
SetBuffer BackBuffer()

Local Mesh = CreateCylinder()   ; Hier kann man verschiedene Primitiven ausprobieren
;Local Mesh = CreateCube()
;Local Mesh = CreateCone()
;Local Mesh = CreateSphere()


Local Cam = CreateCamera()
PositionEntity Cam, 0, 0, -5

Local Pivot = CreatePivot()
EntityParent Cam, Pivot

Local MeshPivot = CreatePivot()

Local Light = CreateLight( 2 )
LightRange Light, 10
PositionEntity Light, 0, 5, -2

Local X# = 0      ; Mit diesen Werten rumspielen, um andere Schnittebenen zu erzeugen
Local Y# = 0
Local Z# = 0
Local NX# = 0.99   ; Würde hier 1 stehen, geht die Ebene beim Zylinder genau durch zwei Vertices, daher wird hier ein geringfügig kleinerer Wert genommen
Local NY# = 1
Local NZ# = 0

Timer = CreateTimer( 60 )

While Not KeyHit( 1 )
   Cls
   
   If KeyHit( 57 ) Then
      If NewMesh Then Y# = Y# + 0.3
      
      Counter = MilliSecs()
      NewMesh = SplitMesh( Mesh, X#, Y#, Z#, NX#, NY#, NZ# )
      TimeSpan = MilliSecs() - Counter
      
      EntityParent NewMesh, MeshPivot
      MoveEntity MeshPivot, 0, -0.3, 0
   EndIf
   
   TurnEntity Pivot, 0, KeyDown( 205 ) - KeyDown( 203 ), 0
   
   Wireframe MouseDown( 1 )
   
   RenderWorld
   
   RenderVertices( Mesh, Cam )
   
   If NewMesh Then
      For i = 1 To CountChildren( MeshPivot )
         RenderVertices( GetChild( MeshPivot, i ), Cam )
      Next
      
      Text 0, 0, "Verbrauchte Zeit: " + TimeSpan + "ms"
   EndIf
   
   Flip 0
   WaitTimer Timer
Wend
End

Function RenderVertices( Mesh, Cam )
   For SurfIndex = 1 To CountSurfaces( Mesh )
      Surface = GetSurface( Mesh, SurfIndex )
      
      For VertIndex = 0 To CountVertices( Surface ) - 1
         TFormPoint VertexX( Surface, VertIndex ), VertexY( Surface, VertIndex ), VertexZ( Surface, VertIndex ), Mesh, 0
         CameraProject Cam, TFormedX(), TFormedY(), TFormedZ()
         
         WritePixel ProjectedX(), ProjectedY(), $FFFFFF
      Next
   Next
End Function

;-----------------------------------------------------------Include-------------------------------------------------------------------

Type TSplitTriangle
   Field Surface
   
   Field V1
   Field V2
   Field V3
   
   Field D1#
   Field D2#
   Field D3#
End Type

Type TTriangle
   Field SurfIndex
   Field Surface
   
   Field V1
   Field V2
   Field V3
   
   Field Vertex1.TVertex
   Field Vertex2.TVertex
   Field Vertex3.TVertex
End Type

Type TVertex
   Field X#
   Field Y#
   Field Z#
   Field U#
   Field V#
   
   Field ID
   Field Used
End Type

Global IntersectionX#, IntersectionY#, IntersectionZ#, IntersectionT#

Function SplitMesh( Mesh, X#, Y#, Z#, NX#, NY#, NZ# )
   TFormNormal NX#, NY#, NZ#, 0, Mesh
   NX# = TFormedX()
   NY# = TFormedY()
   NZ# = TFormedZ()
   
   TFormPoint X#, Y#, Z#, 0, Mesh
   X# = TFormedX()
   Y# = TFormedY()
   Z# = TFormedZ()
   
   C# = -( X#*NX# + Y#*NY# + Z#*NZ# )
   
   For SurfIndex = 1 To CountSurfaces( Mesh )
      Surface = GetSurface( Mesh, SurfIndex )
      
      For TriIndex = 0 To CountTriangles( Surface ) - 1
         V1 = TriangleVertex( Surface, TriIndex, 0 )
         V2 = TriangleVertex( Surface, TriIndex, 1 )
         V3 = TriangleVertex( Surface, TriIndex, 2 )
         
         D1# = VertexX( Surface, V1 )*NX# + VertexY( Surface, V1 )*NY# + VertexZ( Surface, V1 )*NZ# + C#
         D2# = VertexX( Surface, V2 )*NX# + VertexY( Surface, V2 )*NY# + VertexZ( Surface, V2 )*NZ# + C#
         D3# = VertexX( Surface, V3 )*NX# + VertexY( Surface, V3 )*NY# + VertexZ( Surface, V3 )*NZ# + C#
         
         If Sgn( D1# ) <> Sgn( D2# ) Or Sgn( D1# ) <> Sgn( D3# ) Or Sgn( D2# ) <> Sgn( D3# ) Then
            SplitTriangle.TSplitTriangle = New TSplitTriangle
               SplitTriangle\Surface = Surface
               SplitTriangle\V1 = V1
               SplitTriangle\V2 = V2
               SplitTriangle\V3 = V3
               SplitTriangle\D1# = D1#
               SplitTriangle\D2# = D2#
               SplitTriangle\D3# = D3#
         Else
            Triangle.TTriangle = New TTriangle
               Triangle\Surface = Surface
               Triangle\V1 = V1
               Triangle\V2 = V2
               Triangle\V3 = V3
         EndIf
      Next
      
      ClearSurface Surface, False, True
   Next
   
   For SplitTriangle = Each TSplitTriangle
      SplitTriangle( SplitTriangle, X#, Y#, Z#, NX#, NY#, NZ# )
   Next
   
   For Triangle.TTriangle = Each TTriangle
      AddTriangle Triangle\Surface, Triangle\V1, Triangle\V2, Triangle\V3
   Next
   
   Delete Each TTriangle
   
   For SurfIndex = 1 To CountSurfaces( Mesh )
      Surface = GetSurface( Mesh, SurfIndex )
      
      For TriIndex = 0 To CountTriangles( Surface ) - 1
         Triangle.TTriangle = New TTriangle
            Triangle\SurfIndex = SurfIndex
            Triangle\Surface = Surface
            Triangle\V1 = TriangleVertex( Surface, TriIndex, 0 )
            Triangle\V2 = TriangleVertex( Surface, TriIndex, 1 )
            Triangle\V3 = TriangleVertex( Surface, TriIndex, 2 )
      Next
      
      ClearSurface Surface, False, True
   Next
   
   NewMesh = CopyMeshEx( Mesh )
   
   For Triangle.TTriangle = Each TTriangle
      D1# = VertexX( Triangle\Surface, Triangle\V1 )*NX# + VertexY( Triangle\Surface, Triangle\V1 )*NY# + VertexZ( Triangle\Surface, Triangle\V1 )*NZ# + C#
      D2# = VertexX( Triangle\Surface, Triangle\V2 )*NX# + VertexY( Triangle\Surface, Triangle\V2 )*NY# + VertexZ( Triangle\Surface, Triangle\V2 )*NZ# + C#
      D3# = VertexX( Triangle\Surface, Triangle\V3 )*NX# + VertexY( Triangle\Surface, Triangle\V3 )*NY# + VertexZ( Triangle\Surface, Triangle\V3 )*NZ# + C#
      
      D1# = Floor( D1#*50 )
      D2# = Floor( D2#*50 )
      D3# = Floor( D3#*50 )
      
      If Sgn( D1# ) = 1 Or Sgn( D2# ) = 1 Or Sgn( D3# ) = 1 Then
         AddTriangle Triangle\Surface, Triangle\V1, Triangle\V2, Triangle\V3
      Else
         NewSurface = GetSurface( NewMesh, Triangle\SurfIndex )
         
         AddTriangle NewSurface, Triangle\V1, Triangle\V2, Triangle\V3
      EndIf
   Next
   
   Delete Each TTriangle
   Delete Each TSplitTriangle
   
   CleanMesh( Mesh )
   CleanMesh( NewMesh )
   
   UpdateNormals Mesh
   UpdateNormals NewMesh
   
   Return NewMesh
End Function

Function CopyMeshEx( Mesh )
   NewMesh = CreateMesh()
   Brush = GetEntityBrush( Mesh )
   
   For SurfIndex = 1 To CountSurfaces( Mesh )
      Surface = GetSurface( Mesh, SurfIndex )
      NewSurface = CreateSurface( NewMesh )
      
      PaintSurface NewSurface, GetSurfaceBrush( Surface )
      
      For VertIndex = 0 To CountVertices( Surface ) - 1
         V = AddVertex( NewSurface, VertexX( Surface, VertIndex ), VertexY( Surface, VertIndex ), VertexZ( Surface, VertIndex ) )
         VertexTexCoords NewSurface, V, VertexU( Surface, VertIndex ), VertexV( Surface, VertIndex )
      Next
      
      For TriIndex = 0 To CountTriangles( Surface ) - 1
         AddTriangle NewSurface, TriangleVertex( Surface, TriIndex, 0 ), TriangleVertex( Surface, TriIndex, 1 ), TriangleVertex( Surface, TriIndex, 2 )
      Next
   Next
   
   PaintEntity NewMesh, Brush
   
   Return NewMesh
End Function

Function CleanMesh( Mesh )
   For SurfIndex = 1 To CountSurfaces( Mesh )
      Surface = GetSurface( Mesh, SurfIndex )
      
      For VertIndex = 0 To CountVertices( Surface ) - 1
         Vertex.TVertex = New TVertex
            Vertex\X# = VertexX( Surface, VertIndex )
            Vertex\Y# = VertexY( Surface, VertIndex )
            Vertex\Z# = VertexZ( Surface, VertIndex )
            Vertex\U# = VertexU( Surface, VertIndex )
            Vertex\V# = VertexV( Surface, VertIndex )
            Vertex\ID = VertIndex
      Next
      
      For TriIndex = 0 To CountTriangles( Surface ) - 1
         Triangle.TTriangle = New TTriangle
         
         For i = 0 To 2
            VertIndex = TriangleVertex( Surface, TriIndex, i )
            
            For Vertex.TVertex = Each TVertex
               If Vertex\ID = VertIndex Then
                  Vertex\Used = True
                  
                  If i = 0 Then Triangle\Vertex1 = Vertex ElseIf i = 1 Then Triangle\Vertex2 = Vertex Else Triangle\Vertex3 = Vertex
                  
                  Exit
               EndIf
            Next
         Next
      Next
      
      ClearSurface Surface
      
      For Vertex.TVertex = Each TVertex
         If Not Vertex\Used Then
            Delete Vertex
         Else
            Vertex\ID = AddVertex( Surface, Vertex\X#, Vertex\Y#, Vertex\Z#, Vertex\U#, Vertex\V# )
         EndIf
      Next
      
      For Triangle.TTriangle = Each TTriangle
         AddTriangle Surface, Triangle\Vertex1\ID, Triangle\Vertex2\ID, Triangle\Vertex3\ID
      Next
      
      Delete Each TVertex
      Delete Each TTriangle
   Next
End Function

Function SplitTriangle( Triangle.TSplitTriangle, X#, Y#, Z#, NX#, NY#, NZ# )
   Surface = Triangle\Surface
   
   C# = -( X#*NX# + Y#*NY# + Z#*NZ# )
   
   V1 = Triangle\V1
   V2 = Triangle\V2
   V3 = Triangle\V3
   
   D1# = VertexX( Surface, V1 )*NX# + VertexY( Surface, V1 )*NY# + VertexZ( Surface, V1 )*NZ# + C#
   D2# = VertexX( Surface, V2 )*NX# + VertexY( Surface, V2 )*NY# + VertexZ( Surface, V2 )*NZ# + C#
   D3# = VertexX( Surface, V3 )*NX# + VertexY( Surface, V3 )*NY# + VertexZ( Surface, V3 )*NZ# + C#
   
   If Sgn( D1# ) <> Sgn( D2# ) Then
      NewV1 = SplitEdge( Surface, V1, V2, X#, Y#, Z#, NX#, NY#, NZ# )
      NewV2 = NewV1 + 1
      
      If Sgn( D1# ) <> Sgn( D3# ) Then
         NewV3 = SplitEdge( Surface, V1, V3, X#, Y#, Z#, NX#, NY#, NZ# )
         NewV4 = NewV3 + 1
         
         AddTriangle Surface, V1, NewV1, NewV3
         AddTriangle Surface, V2, V3, NewV2
         AddTriangle Surface, NewV2, V3, NewV4
      ElseIf Sgn( D2# ) <> Sgn( D3# ) Then
         NewV3 = SplitEdge( Surface, V2, V3, X#, Y#, Z#, NX#, NY#, NZ# )
         NewV4 = NewV3 + 1
         
         AddTriangle Surface, V2, NewV3, NewV2
         AddTriangle Surface, V1, NewV4, V3
         AddTriangle Surface, V1, NewV1, NewV4
      EndIf
   ElseIf Sgn( D1# ) <> Sgn( D3# ) Then
      NewV1 = SplitEdge( Surface, V1, V3, X#, Y#, Z#, NX#, NY#, NZ# )
      NewV2 = NewV1 + 1
      
      NewV3 = SplitEdge( Surface, V2, V3, X#, Y#, Z#, NX#, NY#, NZ# )
      NewV4 = NewV3 + 1
      
      AddTriangle Surface, V3, NewV1, NewV3
      AddTriangle Surface, V1, V2, NewV2
      AddTriangle Surface, V2, NewV4, NewV2
   EndIf
End Function

Function SplitEdge( Surface, V1, V2, X#, Y#, Z#, NX#, NY#, NZ# )
   V1X# = VertexX( Surface, V1 )
   V1Y# = VertexY( Surface, V1 )
   V1Z# = VertexZ( Surface, V1 )
   V1U# = VertexU( Surface, V1 )
   V1V# = VertexV( Surface, V1 )
   
   V2X# = VertexX( Surface, V2 )
   V2Y# = VertexY( Surface, V2 )
   V2Z# = VertexZ( Surface, V2 )
   V2U# = VertexU( Surface, V2 )
   V2V# = VertexV( Surface, V2 )
   
   If LinePlaneIntersection( V1X#, V1Y#, V1Z#, V2X# - V1X#, V2Y# - V1Y#, V2Z# - V1Z#, X#, Y#, Z#, NX#, NY#, NZ# ) Then
      U# = IntersectionT#*V2U# + ( 1 - IntersectionT# )*V1U#
      V# = IntersectionT#*V2V# + ( 1 - IntersectionT# )*V1V#
      
      V1 = AddVertex( Surface, IntersectionX#, IntersectionY#, IntersectionZ#, U#, V# )
      V2 = AddVertex( Surface, IntersectionX#, IntersectionY#, IntersectionZ#, U#, V# )
      
      Return V1
   Else
      RuntimeError "Something wrong here."
   EndIf
End Function

Function LinePlaneIntersection( X#, Y#, Z#, VX#, VY#, VZ#, PX#, PY#, PZ#, NX#, NY#, NZ# )
   T# = -( NX#*X# + NY#*Y# + NZ#*Z# - NX#*PX# - NY#*PY# - NZ#*PZ# )/( NX#*VX# + NY#*VY# + NZ#*VZ# )
   
   T# = Floor( T#*100 )/100.
   
   If T# >= 0 And T# <= 1 Then
      IntersectionX# = X# + VX#*T#
      IntersectionY# = Y# + VY#*T#
      IntersectionZ# = Z# + VZ#*T#
      IntersectionT# = T#
      
      Return True
   Else
      Return False
   EndIf
End Function


Mit Pfeiltasten links/rechts kann man die Kamera drehen und mit Leertaste zerschneiden. Wenn man mehrmals Leertaste drückt, wird das Mesh regelrecht in Scheiben geschnitten, sieht lustig aus Razz

Die Funktion kann leider die entstandenen Schnittflächen nicht selbstständig mit Dreiecken füllen. Es entstehen also 'Löcher', durch die man ins Mesh hineinsehen kann. Daran arbeite ich aber noch - falls es funktioniert, kann man Crysis - like Bäume zerschneiden gehn Razz

Bei Bugs und Anregungen kann man sich jederzeit per PN oder hier im Thread melden.
  • Zuletzt bearbeitet von Noobody am Di, Apr 21, 2009 14:53, insgesamt 6-mal bearbeitet

Xaymar

ehemals "Cgamer"

BeitragFr, Apr 17, 2009 22:15
Antworten mit Zitat
Benutzer-Profile anzeigen
kannst du auch sowas wie eine substract und add funktion bauen? die letzten beiden codes waren ja schon nice:)

zb sowas:
https://www.blitzforum.de/upload/file.php?id=5328

mesh in mesh
funktion add beide meshes
endmesh(addiert und ohne unnütze vertexe/triangles)
Warbseite

FireballFlame

BeitragFr, Apr 17, 2009 22:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Beeindruckend!
Ich habe mal einige Meshes getestet; das Zerteilen an sich funktioniert wunderbar, die Texturen gehen dabei allerdings verloren.
PC: Intel Core i7 @ 4x2.93GHz | 6 GB RAM | Nvidia GeForce GT 440 | Desktop 2x1280x1024px | Windows 7 Professional 64bit
Laptop: Intel Core i7 @ 4x2.00GHz | 8 GB RAM | Nvidia GeForce GT 540M | Desktop 1366x768px | Windows 7 Home Premium 64bit

Noobody

BeitragFr, Apr 17, 2009 22:37
Antworten mit Zitat
Benutzer-Profile anzeigen
Naja, das wäre dann Contructive Solid Geometry und geht leider über mein Wissen hinaus Razz

Es existiert aber ein Code im englischen Codearchiv dazu. Ist zwar ein wenig buggy, aber funktioniert trotzdem nicht schlecht.

Die Sache mit den Texturen ist mir jetzt peinlich Razz
Da hatte ich gleich vergessen, in CleanMesh die UV - Koordinaten mit zu übertragen. Ist jetzt gefixt.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

Chrise

BeitragFr, Apr 17, 2009 23:29
Antworten mit Zitat
Benutzer-Profile anzeigen
rein theoretisch könnte man doch das Vertex das direkt durch die Eben verläuft verdopllen? Oder ist der "Fehler" so gewollt?

Sonst ist das ein wirklich schönes Ergebnis!
Llama 1 Llama 2 Llama 3
Vielen Dank an Pummelie, der mir auf seinem Server einen Platz für LlamaNet bietet.

Noobody

BeitragFr, Apr 17, 2009 23:33
Antworten mit Zitat
Benutzer-Profile anzeigen
Das würde die Funktion jetzt schon erledigen, nur besteht das Problem, dass der Vertex, wenn er direkt auf der Ebene liegt, von der Hesseschen Normalform zu der 'Zerschneiden' - Liste hinzugefügt wird, die LinePlaneCollision aber aufgrund kleinster Rundungsfehler den Schnittpunkt des Dreiecks nicht bestimmen kann. Ich versuche, das noch zu beheben, aber da muss ich noch eine Weile rumgrübeln.

Aber danke für das Lob Razz
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

FireballFlame

BeitragSa, Apr 18, 2009 0:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Irgendwie scheinen 2 Schnitte hintereinander generell nicht zu gehen... aber die Texturen funktionieren jetzt Smile
PC: Intel Core i7 @ 4x2.93GHz | 6 GB RAM | Nvidia GeForce GT 440 | Desktop 2x1280x1024px | Windows 7 Professional 64bit
Laptop: Intel Core i7 @ 4x2.00GHz | 8 GB RAM | Nvidia GeForce GT 540M | Desktop 1366x768px | Windows 7 Home Premium 64bit

Noobody

BeitragDi, Apr 21, 2009 14:28
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich habe die Funktion nochmal verbessert und einen Bug behoben, der die Funktion nach einmaliger Benutzung unbrauchbar machte - ich habe vergessen, nach der Funktion wieder aufzuräumen Razz
Ausserdem hatte ich gar nicht darauf geachtet, dass VertexX etc. ja unverändert sind, egal, wie das Objekt positioniert, gedreht und skaliert ist, daher wurde dann die Schnittebene falsch angesetzt. Ein einfaches TFormPoint und TFormNormal schufen da Abhilfe.

Der Code ist im ersten Post nacheditiert. Wenn man nun mehrmals Leertaste drückt, wird das Mesh in Scheiben geschnitten.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

Chrise

BeitragDi, Apr 21, 2009 14:38
Antworten mit Zitat
Benutzer-Profile anzeigen
Bei mir kommt da etwas von wegen illegal Type conversation Wink
Übrigens ein sehr großes Lob an YellowRider mit dem Syntax Highlightning ^^
Ist echt spitze, vorallem mit den automatischen Hilfe-links
Llama 1 Llama 2 Llama 3
Vielen Dank an Pummelie, der mir auf seinem Server einen Platz für LlamaNet bietet.

Noobody

BeitragDi, Apr 21, 2009 14:54
Antworten mit Zitat
Benutzer-Profile anzeigen
Ja, die Syntaxbox hat aus irgendeinem Grund alle Backslashes rausgeschnitten.
Ich habe nun wieder auf die Codebox umgestellt, sollte jetzt gehen.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

Chrise

BeitragDi, Apr 21, 2009 15:22
Antworten mit Zitat
Benutzer-Profile anzeigen
sehr schön, funktioniert gut! Ist bestimmt nützlich wie Spiele wo man mit Mausgesten irgendwas zerschneiden muss, was den Weg blockiert Wink
Llama 1 Llama 2 Llama 3
Vielen Dank an Pummelie, der mir auf seinem Server einen Platz für LlamaNet bietet.

Neue Antwort erstellen


Übersicht BlitzBasic Codearchiv

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group