Schnelle Kollisionsroutinen

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8808
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Schnelle Kollisionsroutinen

Beitrag von NicTheQuick »

Ich bin schon ein paar Wochen an ein paar kleinen Kollisionsroutinen.
Weil wir vor ein paar Wochen auch mit der Vektorrechnung in Mathematik begonnen haben, faszinieren die Vektoren mich immer noch und ich hab gleich mal mehrere Kapitel weiter geschlagen und das wichtigste mitgenommen.

Das hier ist das Ergebnis der hauptsächlich in Musik und Geschichte entwickelten Kollisionsroutinen für 2D und 3D.

Die Kollison von Gerade mit Ebene, Parallelogramm oder Dreieck ist schon auf dem Blatt, aber noch nicht in PureBasic umgesetzt.
Daher wird sich von Zeit zu Zeit immer wieder mal was neues hier finden.

Achja: Wenn es Fehler gibt, dann bitte schnell melden. Ich habe die Procedures selbst noch nicht getestet. Ich weiß aber, dass [c]RayHitsSphere()[/c] auf jeden Fall funktioniert. Die wurde schon getestet.

Code: Alles auswählen

XIncludeFile "Structures.pbi"

;{- 2D LineHitsLine

;Errechnet den Schnittpunkt zweier Linie
; [in]  Line1p      : Stützvektor der 1. Linie
; [in]  Line1r      : Richtungs- und Längenvektor der 1. Linie
; [in]  Line2p      : Stützvektor der 2. Linie
; [in]  Line2r      : Richtungs- und Längenvektor der 2. Linie
; [out] pHit        : Schnittpunkt
; [out] RETURN      : #True bei Schnitt
Procedure.l LineHitsLine_2D_Vector(*Line1p.Vector2D, *Line1r.Vector2D, *Line2p.Vector2D, *Line2r.Vector2D, *pHit.Vector2D)
  Protected d.f, Ds.f, s.f, Dt.f, t.f
  
  ; Die Determinante d berechnen
  d = *Line1r\y * *Line2r\x - *Line1r\x * *Line2r\y
  
  ; Wenn d null ist, sind die Linien parallel
  If d < 0.0001 And d > -0.0001 : ProcedureReturn #False : EndIf
  
  ; Determinante Ds berechnen
  Ds = (*Line2p\y - *Line1p\y) * *Line2r\x - (*Line2p\x - *Line1p\x) * *Line2r\y
  
  ; s = Ds / d berechnen und prüfen, ob s in den Grenzen liegt
  s = Ds / d
  If s < 0.0 Or s > 1.0 : ProcedureReturn #False : EndIf
  
  ; Jetzt berechnen wir Dt und t
  Dt = (*Line2p\y - *Line1p\y) * *Line1r\x - (*Line2p\x - *Line1p\x) * *Line1r\y
  t = Dt / d
  If  t < 0.0 Or t > 1.0 : ProcedureReturn #False : EndIf
  
  ; Die Linien schneiden sich!
  ; Wir tragen den Schnittpunkt ein.
  If *pHit
    *pHit\x = *Line1p\x + s * *Line1r\x
    *pHit\y = *Line1p\y + s * *Line1r\y
  EndIf
  
  ProcedureReturn #True
EndProcedure

;Errechnet den Schnittpunkt zweier Linie
; [in]  Line1       : 1. Linie mit Line2D-Struktur
; [in]  Line2       : 2. Linie mit Line2D-Struktur
; [out] pHit        : Schnittpunkt
; [out] RETURN      : #True bei Schnitt
Procedure.l LineHitsLine_2D_Point(*Line1.Line2D, *Line2.Line2D, *pHit.Vector2D)
  Protected Line1p.Vector2D, Line1r.Vector2D, Line2p.Vector2D, Line2r.Vector2D
  
  Line1p\x = *Line1\x1
  Line1p\y = *Line1\y1
  Line1r\x = *Line1\x2 - *Line1\x1
  Line1r\y = *Line1\y2 - *Line1\y1
  
  Line2p\x = *Line2\x1
  Line2p\y = *Line2\y1
  Line2r\x = *Line2\x2 - *Line2\x1
  Line2r\y = *Line2\y2 - *Line2\y1
  
  ProcedureReturn LineHitsLine_2D_Vector(@Line1p, @Line1r, @Line2p, @Line2r, *pHit)
EndProcedure

;Errechnet den Schnittpunkt zweier Linie
; [in]  Line1x1     : x-Koordinate des Anfangspunktes der 1. Linie
; [in]  Line1y1     : y-Koordinate des Anfangspunktes der 1. Linie
; [in]  Line1x2     : x-Koordinate des Endpunktes der 1. Linie
; [in]  Line1y2     : y-Koordinate des Endpunktes der 1. Linie
; [in]  Line2x1     : x-Koordinate des Anfangspunktes der 2. Linie
; [in]  Line2y1     : y-Koordinate des Anfangspunktes der 2. Linie
; [in]  Line2x2     : x-Koordinate des Endpunktes der 2. Linie
; [in]  Line2y2     : y-Koordinate des Endpunktes der 2. Linie
; [out] pHit        : Schnittpunkt
; [out] RETURN      : #True bei Schnitt
Procedure.l LineHitsLine_2D_Koord(Line1x1.f, Line1y1.f, Line1x2.f, Line1y2.f, Line2x1.f, Line2y1.f, Line2x2.f, Line2y2.f, *pHit.Vector2D)
  Protected Line1p.Vector2D, Line1r.Vector2D, Line2p.Vector2D, Line2r.Vector2D
  
  Line1p\x = Line1x1
  Line1p\y = Line1y1
  Line1r\x = Line1x2 - Line1x1
  Line1r\y = Line1y2 - Line1y1
  
  Line2p\x = Line2x1
  Line2p\y = Line2y1
  Line2r\x = Line2x2 - Line2x1
  Line2r\y = Line2y2 - Line2y1
  
  ProcedureReturn LineHitsLine_2D_Vector(@Line1p, @Line1r, @Line2p, @Line2r, *pHit)
EndProcedure

;}

;{- 2D Lines and Points

;Errechnet den nächsten Punkt auf einer Linie zu einem äußeren Punkt
; [in]  a           : Stützverktor der Linie
; [in]  b           : Richtungs- und Längenvektor der Linie
; [in]  P           : äußerer Punkt
; [out] P_out       : nächster Punkt auf der Linie
; [out] RETURN      : #True, wenn der P_out-Pointer nicht Null
Procedure ClosestPointOnLine_2D_Vector(*a.Vector2D, *b.Vector2D, *P.Vector2D, *P_out.Vector2D)
  Protected PMinusA.Vector2D, b.Vector2D, numerator.f, demoninator.f, M.f
  
  PMinusA\x = *P\x - *a\x
  PMinusA\y = *P\y - *a\y
  
  numerator = PMinusA\x * b\x + PMinusA\y * *b\y
  
  denominator = b\x * b\x + b\y * b\y
  
  If denominator = 0
    M = 0.0
  Else
    M = numerator / denominator
  EndIf
  
  If M < 0.0 : M = 0.0 : EndIf
  If M > 1.0 : M = 1.0 : EndIf
  
  If *P_out
    *P_out\x = *a\x + M * b\x
    *P_out\y = *a\y + M * b\y
    ProcedureReturn #True
  EndIf
EndProcedure

;Errechnet den nächsten Punkt auf einer Linie zu einem äußeren Punkt
; [in]  L1          : Anfangspunkt der Linie
; [in]  L2          : Endpunkt der Linie
; [in]  P           : aüßerer Punkt
; [out] P_out       : nächster Punkt auf der Linie
; [out] RETURN      : #True, wenn der P_out-Pointer nicht Null
Procedure ClosestPointOnLine_2D_Point(*L1.Vector2D, *L2.Vector2D, *P.Vector2D, *P_out.Vector2D)
  Protected b.Vector2D
  
  b\x = *L2\x - *L1\x
  b\y = *L2\y - *L1\y
  
  ProcedureReturn ClosestPointOnLine_2D_Vector(*L1, @b, *P, *P_out)
EndProcedure

;Errechnet den nächsten Punkt auf einer Linie zu einem äußeren Punkt
; [in]  LX1         : x-Koordinate des Anfangspunktes der Linie
; [in]  LY1         : y-Koordinate des Anfangspunktes der Linie
; [in]  LX2         : x-Koordinate des Endpunktes der Linie
; [in]  LY2         : y-Koordinate des Endpunktes der Linie
; [in]  PX          : x-Koordinate des äußeren Punktes
; [in]  PY          : y-Koordinate des äußeren Punktes
; [out] P_out       : nächster Punkt auf der Linie
; [out] RETURN      : #True, wenn der P_out-Pointer nicht Null
Procedure ClosestPointOnLine_2D_Koord(LX1.f, LY1.f, LX2.f, LY2.f, PX.f, PY.f, *P_out.Vector2D)
  Protected a.Vector2D, b.Vector2D, P.Vector2D
  
  a\x = LX1
  a\y = LY1
  b\x = LX2 - LX1
  b\y = LY2 - LY1
  
  P\x = PX
  P\y = PY
  
  ProcedureReturn ClosestPointOnLine_2D_Vector(@a, @b, @P, *P_out)
EndProcedure

;}

;{- 2D CircleHitsCircle (noch ohne Schnittpunkt)

; [in]  M1          : Mittelpunkt des 1. Kreises
; [in]  R1          : Radius des 1. Kreises
; [in]  M2          : Mittelpunkt des 2. Kreises
; [in]  R2          : Radius des 2. Kreises
; [out] RETURN      : #True bei Schnitt
Procedure.l CircleHitsCircle_2D_Point(*M1.Vector2D, R1.f, *M2.Vector2D, R2.f)
  Protected Radd.f, Mdiffx.f, Mdiffy.f, Mdiffqu.f
  
  ; Wir addieren beide Radien
  Radd.f = R1 + R2
  
  ; Wir berechnen den Abstand zwischen den Mittelpunkten im Quadrat
  Mdiffx = *M1\x - *M2\x
  Mdiffy = *M1\y - *M2\y
  Mdiffqu = Mdiffx * Mdiffx + Mdiffy * Mdiffy
  
  ; Wenn die Abstand der Mittelpunkte größer ist als die Radien zusammen, dann gibt es keine Kollision
  If Mdiffqu > Radd * Radd
    ProcedureReturn #False
  EndIf
  
  ProcedureReturn #True
EndProcedure

; [in]  M1x         : x-Koordinate des Mittelpunktes des 1. Kreises
; [in]  M1y         : y-Koordinate des Mittelpunktes des 1. Kreises
; [in]  R1          : Radius des 1. Kreises
; [in]  M2x         : x-Koordinate des Mittelpunktes des 2. Kreises
; [in]  M2y         : y-Koordinate des Mittelpunktes des 2. Kreises
; [in]  R2          : Radius des 2. Kreises
; [out] RETURN      : #True bei Schnitt
Procedure.l CircleHitsCircle_2D_Koord(M1x.f, M1y.f, R1.f, M2x.f, M2y.f, R2.f)
  Protected M1.Vector2D, M2.Vector2D
  
  M1\x = M1x
  M1\y = M1y
  
  M2\x = M2x
  M2\y = M2y
  
  ProcedureReturn CircleHitsCircle_2D_Point(@M1, R1, @M2, R2)
EndProcedure

;}

;{- 2D LineHitsCircle

; [in]  LineStart   : Startpunkt der Linie
; [in]  LineEnd     : Endpunkt der Linie
; [in]  M           : Mittelpunkt des Kreises
; [in]  Radius      : Radius des Kreises
; [out] pOut        : nächster Schnittpunkt vom Startpunkt der Linie
; [out] RETURN      : #True bei Schnitt
Procedure.l LineHitsCircle_2D_Point(*LineStart.Vector2D, *LineEnd.Vector2D, *M.Vector2D, Radius.f, *pOut.Vector2D)
  Protected RadiusSq.f, PMinusM.Vector2D, LineDir.Vector2D, UDotPMinusM.f
  Protected LineDirSq.f, d.f, s.f
  
  ; r² vorberechnen
  RadiusSq = Radius * Radius
  
  ; (p - m) vorberechnen
  PMinusM\x = *LineStart\x - *M\x
  PMinusM\y = *LineStart\y - *M\y
  
  ; Wenn der Startpunkt der Linie schon im Kreis liegt,
  ; dann brechen wir sofort ab.
  If PMinusM\x * PMinusM\x + PMinusM\y * PMinusM\y <= RadiusSq
    
    ; als Schnittpunkt nehmen wir einfach
    ; den Startpunkt der Linie
    If *pOut
      *pOut\x = *LineStart\x
      *pOut\y = *LineStart\y
    EndIf
    ProcedureReturn #True
  EndIf
  
  ; Richtungsvektor der Linie berechnen (u)
  LineDir\x = *LineEnd\x - *LineStart\x
  LineDir\y = *LineEnd\y - *LineStart\y
  
  ; u * (p - m) vorberechnen
  UDotPMinusM = LineDir\x * PMinusM\x + LineDir\y * PMinusM\y
  
  ; u² vorberechnen
  LineDirSq = LineDir\x * LineDir\x + LineDir\y * LineDir\y
  
  ; Die Diskriminante berechnen:
  ;  (u * (p - m))²
  ; -(u² * ((p - m)² - r²))
  d = UDotPMinusM * UDotPMinusM
  d = d - LineDirSq * (PMinusM\x * PMinusM\x + PMinusM\y * PMinusM\y - RadiusSq)
  
  ; ist die Diskriminante negativ, null oder positiv?
  If d < 0.0 : ProcedureReturn #False
  ElseIf d < 0.0001
    ; Die Diskriminante ist (ungefähr) null.
    ; DIe gesamte Wurzel entfällt und die Lösung ist:
    ; (-u * (p - m)) / u²
    ; wir müssen nur noch prüfen, ob der Wert
    ; im korrekten Bereich [0; 1] liegt.
    s = -UDotPMinusM / LineDirSq
    If s < 0 Or s > 1
      ProcedureReturn #False
    Else
      ; Berührpunkt!
      If *pOut
        *pOut\x = *LineStart\x + s * LineDir\x
        *pOut\y = *LineStart\y + s * LineDir\y
        ProcedureReturn #True
      EndIf
    EndIf
  Else
    ; Die Gerade schneidet den Kreis zweimal.
    ; Uns interessiert nur die kleinere Lösung s,
    ; denn das ist die Stelle, wo die Linie den Kreis
    ; "zum ersten Mal" schneidet.
    ; Diese Lösung berechnen wir nun.
    s = (-UDotPMinusM - Sqr(d)) / LineDirSq
    If s < 0 Or s > 1
      ProcedureReturn #False
    Else
      If *pOut
        *pOut\x = *LineStart\x + s * LineDir\x
        *pOut\y = *LineStart\y + s * LineDir\y
        ProcedureReturn #True
      EndIf
    EndIf
  EndIf
EndProcedure

; [in]  LineStartx  : x-Koordinate des Startpunktes der Linie
; [in]  LineStarty  : y-Koordinate des Startpunktes der Linie
; [in]  LineEndx    : x-Koordinate des Endpunktes der Linie
; [in]  LineEndy    : y-Koordinate des Endpunktes der Linie
; [in]  Mx          : x-Koordinate des Mittelpunktes des Kreises
; [in]  My          : y-Koordinate des Mittelpunktes des Kreises
; [in]  Radius      : Radius des Kreises
; [out] pOut        : nächster Schnittpunkt vom Startpunkt der Linie
; [out] RETURN      : #True bei Schnitt
Procedure.l LineHitsCircle_2D_Koord(LineStartx.f, LineStarty.f, LineEndx.f, LineEndy.f, Mx.f, My.f, Radius.f, *pOut.Vector2D)
  Protected LineStart.Vector2D, LineEnd.Vector2D, M.Vector2D
  
  LineStart\x = LineStartx
  LineStart\y = LineStarty
  LineEnd\x   = LineEndx
  LineEnd\y   = LineEndy
  
  M\x = Mx
  M\y = My
  
  ProcedureReturn LineHitsCircle_2D_Point(@LineStart, @LineEnd, @M, Radius, *pOut)
EndProcedure

;}

;{- 3D Ray, Lines and Spheres

; [in]  Start       : Startpunkt des Strahls
; [in]  Direction   : Richtungsvektor des Strahls
; [in]  M           : Mittelpunkt der Kugel
; [in]  Radius      : Radius der Kugel
; [out] pOut        : nächster Schnittpunkt vom Startpunkt aus
; [out] RETURN      : #True bei Schnitt
Procedure RayHitsSphere_3D_Vector(*Start.Vector3D, *Direction.Vector3D, *M.Vector3D, Radius.f, *pOut.Vector3D)
  Protected AMinusB.Vector3D, AMinusBDotU.f, USq.f, c.f, Det.f, d.f, AMinusBSq.f, P.f
  
  USq = *Direction\x * *Direction\x + *Direction\y * *Direction\y + *Direction\z * *Direction\z
  
  AMinusB\x = *M\x - *Start\x
  AMinusB\y = *M\y - *Start\y
  AMinusB\z = *M\z - *Start\z
  
  AMinusBDotU = AMinusB\x * *Direction\x + AMinusB\y * *Direction\y + AMinusB\z * *Direction\z
  
  c = AMinusBDotU / USq
  
  AMinusBSq = AMinusB\x * AMinusB\x + AMinusB\y * AMinusB\y + AMinusB\z * AMinusB\z
  
  d = (Radius * Radius - AMinusBSq) / USq
  
  Det = c * c + d
  
  If Det < 0.0
    ProcedureReturn #False
  ElseIf Det < 0.0001
    P = c
  Else
    P = c - Sqr(Det)
  EndIf
  
  If P < 0.0
    ProcedureReturn #False
  EndIf
  
  If *pOut
    *pOut\x = *Start\x + P * *Direction\x
    *pOut\y = *Start\y + P * *Direction\y
    *pOut\z = *Start\z + P * *Direction\z
  EndIf
  
  ProcedureReturn #True
EndProcedure

;Berechnung des nächsten Schnittpunktes eines Strahls mit einer Kugel und dessen Reflektion von dieser Stelle
; [in]  a           : Startpunkt des Strahls
; [in]  u           : Richtungs- und Längenvektor des Strahls
; [in]  M           : Mittelpunkt der Kugel
; [in]  Radius      : Radius der Kugel
; [out] a_out       : Schnittpunkt des Strahls mit der Kugel und Aufpunkt des Strahls oder unverändert, falls kein Schnitt
; [out] u_out       : Neuer Richtungsvektor des Strahls
; [out] RETURN      : #True bei Schnitt
Procedure RayHitsSphereMirrored_3D_Vector(*a.Vector3D, *u.Vector3D, *M.Vector3D, Radius.f, *a_out.Vector3D, *u_out.Vector3D)
  Protected s.Vector3D, n.Vector3D, NDotU.f, s2.Vector3D, numerator.f, lambda.f, NSq.f, a_mirror.Vector3D
  
  If RayHitsSphere_3D_Vector(*a, *u, *M, Radius, @s)
    
    ;Normale ausrechnen
    n\x = *M\x - s\x
    n\y = *M\y - s\y
    n\z = *M\z - s\z
    
    NDotU = n\x * *u\x + n\y * *u\y + n\z * *u\z
    
    If NDotU <> 0.0
      numerator = n\x * (s\x - *a\x) + n\y * (s\y - *a\y) + n\z * (s\z - *a\z)
      lambda = numerator / NDotU
      
      If lambda > 0.0
        s2\x = *a\x + lambda * *u\x
        s2\y = *a\y + lambda * *u\y
        s2\z = *a\z + lambda * *u\z
        
        NSq = n\x * n\x + n\y * n\y + n\z * n\z
        
        lambda = 2 * numerator / NSq
        
        a_mirror\x = *a\x + lambda * n\x
        a_mirror\y = *a\y + lambda * n\y
        a_mirror\z = *a\z + lambda * n\z
        
        If *u_out
          *u_out\x = s2\x - a_mirror\x
          *u_out\y = s2\y - a_mirror\y
          *u_out\z = s2\z - a_mirror\z
        EndIf
        If *a_out
          *a_out\x = s2\x
          *a_out\y = s2\y
          *a_out\z = s2\z
        EndIf
        
        ProcedureReturn #True
      EndIf
    EndIf
  EndIf
  
  If *u_out
    *u_out\x = *u\x
    *u_out\y = *u\y
    *u_out\z = *u\z
  EndIf
  If *a_out
    *a_out\x = *a\x
    *a_out\y = *a\y
    *a_out\z = *a\z
  EndIf
  
  ProcedureReturn #False
  
EndProcedure

;Berechnung des nächsten Schnittpunktes einer Linie mit einer Kugel
; [in]  Start       : Startpunkt der Linie
; [in]  Direction   : Richtungs- und Längenvektor der Linie
; [in]  M           : Mittelpunkt der Kugel
; [in]  Radius      : Radius der Kugel
; [out] pOut        : nächster Schnittpunkt vom Startpunkt aus
; [out] RETURN      : #True bei Schnitt
Procedure LineHitsSphere_3D_Vector(*Start.Vector3D, *Direction.Vector3D, *M.Vector3D, Radius.f, *pOut.Vector3D)
  Protected AMinusB.Vector3D, AMinusBDotU.f, USq.f, c.f, Det.f, d.f, AMinusBSq.f, P.f
  
  USq = *Direction\x * *Direction\x + *Direction\y * *Direction\y + *Direction\z * *Direction\z
  
  AMinusB\x = *M\x - *Start\x
  AMinusB\y = *M\y - *Start\y
  AMinusB\z = *M\z - *Start\z
  
  AMinusBDotU = AMinusB\x * *Direction\x + AMinusB\y * *Direction\y + AMinusB\z * *Direction\z
  
  c = AMinusBDotU / USq
  
  AMinusBSq = AMinusB\x * AMinusB\x + AMinusB\y * AMinusB\y + AMinusB\z * AMinusB\z
  
  d = (Radius * Radius - AMinusBSq) / USq
  
  Det = c * c + d
  
  If Det < 0.0
    If *pOut
      *pOut\x = *Start\x + *Direction\x
      *pOut\y = *Start\y + *Direction\y
      *pOut\z = *Start\z + *Direction\z
    EndIf
    ProcedureReturn #False
  ElseIf Det < 0.0001
    P = c
  Else
    P = c - Sqr(Det)
    If P < 0.0 Or P > 1.0
      If *pOut
        *pOut\x = *Start\x + *Direction\x
        *pOut\y = *Start\y + *Direction\y
        *pOut\z = *Start\z + *Direction\z
      EndIf
      ProcedureReturn #False
    EndIf
  EndIf
  
  If *pOut
    *pOut\x = *Start\x + P * *Direction\x
    *pOut\y = *Start\y + P * *Direction\y
    *pOut\z = *Start\z + P * *Direction\z
  EndIf
  
  ProcedureReturn #True
EndProcedure

;Berechnung des nächsten Schnittpunktes einer Linie mit einer Kugel
; [in]  Start       : Startpunkt der Linie
; [in]  Direction   : Ednpunkt der Linie
; [in]  M           : Mittelpunkt der Kugel
; [in]  Radius      : Radius der Kugel
; [out] pOut        : nächster Schnittpunkt vom Startpunkt aus
; [out] RETURN      : #True bei Schnitt
Procedure LineHitsSphere_3D_Point(*a1.Vector3D, *a2.Vector3D, *M.Vector3D, Radius.f, *pOut.Vector3D)
  Protected u.Vector3D
  
  u\x = *a2\x - *a1\x
  u\y = *a2\y - *a1\y
  u\z = *a2\z - *a1\z
  
  ProcedureReturn LineHitsSphere_3D_Vector(*a1, @u, *M, Radius, *pOut)
EndProcedure

;Berechnung des nächsten Schnittpunktes einer Linie mit einer Kugel und deren Reflektion von dieser Stelle
; [in]  a           : Startpunkt der Linie
; [in]  u           : Richtungs- und Längenvektor der Linie
; [in]  M           : Mittelpunkt der Kugel
; [in]  Radius      : Radius der Kugel
; [out] a_out       : Schnittpunkt der Linie mit der Kugel und Aufpunkt der Linie oder unverändert, falls kein Schnitt
; [out] u_out       : Neuer Richtungs- und Längenvektor der Linie
; [out] RETURN      : #True bei Schnitt
Procedure LineHitsSphereMirrored_3D_Vector(*a.Vector3D, *u.Vector3D, *M.Vector3D, Radius.f, *a_out.Vector3D, *u_out.Vector3D)
  Protected s.Vector3D, n.Vector3D, NDotU.f, s2.Vector3D, numerator.f, lambda.f, NSq.f, a_mirror.Vector3D, sigma.f
  
  If LineHitsSphere_3D_Vector(*a, *u, *M, Radius, @s)
  
    ;Normale ausrechnen
    n\x = *M\x - s\x
    n\y = *M\y - s\y
    n\z = *M\z - s\z
    
    NDotU = n\x * *u\x + n\y * *u\y + n\z * *u\z
    
    If NDotU <> 0.0
      numerator = n\x * (s\x - *a\x) + n\y * (s\y - *a\y) + n\z * (s\z - *a\z)
      lambda = numerator / NDotU
      
      If lambda > 0.0 And lambda <= 1.0
        s2\x = *a\x + lambda * *u\x
        s2\y = *a\y + lambda * *u\y
        s2\z = *a\z + lambda * *u\z
        
        NSq = n\x * n\x + n\y * n\y + n\z * n\z
        
        sigma = 2 * numerator / NSq
        
        a_mirror\x = *a\x + sigma * n\x
        a_mirror\y = *a\y + sigma * n\y
        a_mirror\z = *a\z + sigma * n\z
        
        lambda = 1 / lambda - 1
        
        If *u_out
          *u_out\x = lambda * (s2\x - a_mirror\x)
          *u_out\y = lambda * (s2\y - a_mirror\y)
          *u_out\z = lambda * (s2\z - a_mirror\z)
        EndIf
        If *a_out
          *a_out\x = s\x
          *a_out\y = s\y
          *a_out\z = s\z
        EndIf
        
        ProcedureReturn #True
      EndIf
    EndIf
  EndIf

  If *u_out
    *u_out\x = *u\x
    *u_out\y = *u\y
    *u_out\z = *u\z
  EndIf
  If *a_out
    *a_out\x = *a\x
    *a_out\y = *a\y
    *a_out\z = *a\z
  EndIf
  
  ProcedureReturn #False
  
EndProcedure

;Berechnung des nächsten Schnittpunktes einer Linie mit einer Kugel und deren Reflektion von dieser Stelle
; [in]  a           : Startpunkt der Linie
; [in]  u           : Endpunkt der Linie
; [in]  M           : Mittelpunkt der Kugel
; [in]  Radius      : Radius der Kugel
; [out] a_out       : Schnittpunkt der Linie mit der Kugel und Aufpunkt der Linie oder unverändert, falls kein Schnitt
; [out] u_out       : Neuer Richtungs- und Längenvektor der Linie
; [out] RETURN      : #True bei Schnitt
Procedure LineHitsSphereMirrored_3D_Point(*a1.Vector3D, *a2.Vector3D, *M.Vector3D, Radius.f, *a_out.Vector3D, *u_out.Vector3D)
  Protected u.Vector3D
  
  u\x = *a2\x - *a1\x
  u\y = *a2\y - *a1\y
  u\z = *a2\z - *a1\z
  
  ProcedureReturn LineHitsSphereMirrored_3D_Vector(*a1, @u, *M, Radius, *a_out, *u_out)
EndProcedure

;Berechnung des nächsten Schnittpunktes einer Linie mit einer Kugel und deren Reflektion von dieser Stelle
; [in]  a           : Startpunkt der Linie
; [in]  u           : Endpunkt der Linie
; [in]  M           : Mittelpunkt der Kugel
; [in]  Radius      : Radius der Kugel
; [out] a1_out      : Schnittpunkt der Linie mit der Kugel und Aufpunkt der Linie oder unverändert, falls kein Schnitt
; [out] a2_out      : Endpunkt der Linie nach Schnitt
; [out] RETURN      : #True bei Schnitt
Procedure LineHitsSphereMirrored_3D_PointEx(*a1.Vector3D, *a2.Vector3D, *M.Vector3D, Radius.f, *a1_out.Vector3D, *a2_out.Vector3D)
  Protected u.Vector3D, Result.l
  
  u\x = *a2\x - *a1\x
  u\y = *a2\y - *a1\y
  u\z = *a2\z - *a1\z
  
  Result = LineHitsSphereMirrored_3D_Vector(*a1, @u, *M, Radius, *a1_out, *a2_out)
  
  *a2_out\x + *a1_out\x
  *a2_out\y + *a1_out\y
  *a2_out\z + *a1_out\z
  
  ProcedureReturn Result
EndProcedure

;}

;{- 3D GetNormal

;Normale: Ein Normalenvektor steht immer senkrecht zu zwei anderen Vektoren
;
;            ->   ->   ->
;Berechnung: n  = u  x v    (Vektorprodukt)
;
;             ->   ->              ->   ->
;Später gilt: u  * n  = 0    und   v  * n  = 0

;Gibt die Normale zu zwei Vektoren aus
; [in]  a           : 1. Richtungsvektor
; [in]  b           : 2. Richtungsvektor
; [out] n           : Normale der beiden Richtunsgvektoren
; [out] RETURN      : Immer #True
Procedure GetNormal_3D(*a.Vector3D, *b.Vector3D, *n.Vector3D)
  *n\x = *a\y * *b\z - *a\z * *b\y
  *n\y = *a\z * *b\x - *a\x * *b\z
  *n\z = *a\x * *b\y - *a\y * *b\x
  ProcedureReturn #True
EndProcedure

;}

;{- 3D Planes

;      ->   ->            ->        ->
; PRG: x  = a  + lambda * u  + mü * v
;
;      ->    ->   ->             ->   ->     ->   ->
; PNG: n  * (x  - a ) = 0   <=> (u  x v ) * (x  - a ) = 0
;
;      ->   ->                      ->   ->
; ANG: n  * x  - c = 0      mit c = n  * a

;'Punkt-Richtungs-Gleichung' zur 'Punkt-Normalen-Gleichung'
; [in]  u           : 1. Richtungsvektor der Ebene
; [in]  v           : 2. Richtungsvektor der Ebene
; [out] n           : Normalenvektor der Ebene
; [out] RETURN      : #True, wenn *u und *v nicht parallel
Procedure PRGToPNG_3D(*u.Vector3D, *v.Vector3D, *n.Vector3D) ; --> n*(x-a)=0
  *n\x = *u\y * *v\z - *u\z * *v\y
  *n\y = *u\z * *v\x - *u\x * *v\z
  *n\z = *u\x * *v\y - *u\y * *v\x
  If *n\x = 0 And *n\y = 0 And *n\z = 0 : ProcedureReturn #False : EndIf
  ProcedureReturn #True
EndProcedure

;'Punkt-Richtungs-Gleichung' zur 'Allgemeinen Normalengleichung'
; [in]  a           : Aufpunkt der Ebene
; [in]  u           : 1. Richtungsvektor der Ebene
; [in]  v           : 2. Richtungsvektor der Ebene
; [out] n           : Normalenvektor der Ebene
; [out] c           : Parameter der Ebene in der ANG
; [out] RETURN      : #True, wenn *u und *v nicht parallel
Procedure PRGToANG_3D(*a.Vector3D, *u.Vector3D, *v.Vector3D, *n.Vector3D, *c.FLOAT) ; --> n*x-c=0
  *n\x = *u\y * *v\z - *u\z * *v\y
  *n\y = *u\z * *v\x - *u\x * *v\z
  *n\z = *u\x * *v\y - *u\y * *v\x
  If *n\x = 0 And *n\y = 0 And *n\z = 0 : ProcedureReturn #False : EndIf
  
  *c\f = *n\x * *a\x + *n\y * *a\y + *n\z * *a\z
  
  ProcedureReturn #True
EndProcedure

;'Punkt-Normalen-Gleichung' zur 'Allgemeinen Normalengleichung'
; [in]  a           : Aufpunkt der Ebene
; [in]  n           : Normale der Ebene
; [out] c           : Parameter der Ebene in der ANG
; [out] RETURN      : Immer #True
Procedure PNGToANG_3D(*a.Vector3D, *n.Vector3D, *c.FLOAT) ; n*(x-a)=0 --> n*x-c=0
  *c\f = *n\x * *a\x + *n\y * *a\y + *n\z * *a\z
  ProcedureReturn #True
EndProcedure

;Errechnung der PRG aus drei Punkten
; [in]  a           : 1. Punkt und Aufpunkt der Ebene
; [in]  b           : 2. Punkt
; [in]  c           : 3. Punkt
; [out] u           : 1. Richtungsvektor der Ebene
; [out] v           : 2. Richtungsvektor der Ebene
; [out] RETURN      : #True, wenn Punkte nicht auf eine Linie liegen
Procedure PointsToPRG_3D(*a.Vector3D, *b.Vector3D, *c.Vector3D, *u.Vector3D, *v.Vector3D) ; ABC --> x=a+.u+.v
  Protected n.Vector3D
  
  *u\x = *b\x - *a\x
  *u\y = *b\y - *a\y
  *u\z = *b\z - *a\z
  
  *v\x = *c\x - *a\x
  *v\y = *c\y - *a\y
  *v\z = *c\z - *a\z
  
  n\x = *u\y * *v\z - *u\z * *v\y
  n\y = *u\z * *v\x - *u\x * *v\z
  n\z = *u\x * *v\y - *u\y * *v\x
  
  If n\x = 0 And n\y = 0 And n\z = 0 : ProcedureReturn #False : EndIf
  
  ProcedureReturn #True
EndProcedure

;Errechnung der PNG aus dreu Punkten
; [in]  p1          : 1. Punkt und Aufpunkt der Ebene
; [in]  p2          : 2. Punkt
; [in]  p3          : 3. Punkt
; [out] n           : Normalenvektor
; [out] RETURN      : #True, wenn Punkte nicht auf einer Linie liegen
Procedure PointsToPNG_3D(*p1.Vector3D, *p2.Vector3D, *p3.Vector3D, *n.Vector3D) ; ABC --> n*(x-a)=0
  Protected u.Vector3D, v.Vector3D
  
  u\x = *p2\x - *p1\x
  u\y = *p2\y - *p1\y
  u\z = *p2\z - *p1\z
  
  v\x = *p3\x - *p1\x
  v\y = *p3\y - *p1\y
  v\z = *p3\z - *p1\z
  
  *n\x = u\y * v\z - u\z * v\y
  *n\y = u\z * v\x - u\x * v\z
  *n\z = u\x * v\y - u\y * v\x
  
  If *n\x = 0 And *n\y = 0 And *n\z = 0 : ProcedureReturn #False : EndIf
  
  ProcedureReturn #True
EndProcedure

;Errechnung der ANG aus dreu Punkten
; [in]  p1          : 1. Punkt und Aufpunkt der Ebene
; [in]  p2          : 2. Punkt
; [in]  p3          : 3. Punkt
; [out] n           : Normalenvektor
; [out] c           : Parameter der Ebene in der ANG
; [out] RETURN      : #True, wenn Punkte nicht auf einer Linie liegen
Procedure PointsToANG_3D(*p1.Vector3D, *p2.Vector3D, *p3.Vector3D, *n.Vector3D, *c.FLOAT) ; ABC --> n*x-c=0
  Protected u.Vector3D, v.Vector3D
  
  u\x = *p2\x - *p1\x
  u\y = *p2\y - *p1\y
  u\z = *p2\z - *p1\z
  
  v\x = *p3\x - *p1\x
  v\y = *p3\y - *p1\y
  v\z = *p3\z - *p1\z
  
  *n\x = u\y * v\z - u\z * v\y
  *n\y = u\z * v\x - u\x * v\z
  *n\z = u\x * v\y - u\y * v\x
  
  If *n\x = 0 And *n\y = 0 And *n\z = 0 : ProcedureReturn #False : EndIf
  
  *c\f = *n\x * *p1\x + *n\y * *p1\y + *n\z * *p1\z
  
  ProcedureReturn #True
EndProcedure

;Abstand der Ebene zum Ursprung
; [in]  a           : Aufpunkt der Ebene
; [in]  n           : Normale der Ebene
; [out] RETURN      : Abstand
Procedure.f PlaneDistanceToOrigin_3D(*a.Vector3D, *n.Vector3D)
  Protected d.f, l.f
  
  l = Sqr(*n\x * *n\x + *n\y * *n\y + *n\z * *n\z)
  
  d = (*a\x * *n\x + *a\y * *n\y + *a\z * *n\z) / l
  
  ProcedureReturn d
EndProcedure

;Sind zwei Ebenen parallel?
; [in]  n1          : Normalenvektor der 1. Ebene
; [in]  n2          : Normalenvektor der 2. Ebene
; [out] RETURN      : #True, wenn Ebenen parallel
Procedure PlaneToPlaneParallel_3D(*n1.Vector3D, *n2.Vector3D)
  Protected quotient.f
  
  quotient = *n1\x / *n2\x
  
  If quotient = *n1\y / *n2\y And quotient = *n1\z / *n2\z
    ProcedureReturn #True
  EndIf
  
  ProcedureReturn #False
EndProcedure

;Sind zwei Ebenen gleich?
; [in]  a1          : Aufpunkt der 1. Ebene
; [in]  n1          : Normalenvektor der 1. Ebene
; [in]  a2          : Aufpunkt der 2. Ebene
; [in]  n2          : Normalenvektor der 2. Ebene
; [out] RETURN      : #True, wenn Ebenen gleich
Procedure PlaneToPlaneSame_3D(*a1.Vector3D, *n1.Vector3D, *a2.Vector3D, *n2.Vector3D)
  Protected XMinusA.Vector3D, quotient.f
  
  XMinusA\x = *a2\x - *a1\x
  XMinusA\y = *a2\y - *a1\y
  XMinusA\z = *a2\z - *a1\z
  
  If XMinusA\x * *n1\x + XMinusA\y * *n1\y + XMinusA\z * *n1\z = 0
    quotient = *n1\x / *n2\x
    If quotient = *n1\y / *n2\y And quotient = *n1\z / *n2\z
      ProcedureReturn #True
    EndIf
  EndIf
  
  ProcedureReturn #False
EndProcedure

;}

;{- 3D Planes, Lines and Rays

;Berechnung, ob Linie parallel zu einer Ebene ist
; [in]  u           : Richtungsvektor der Gerade
; [in]  n           : Normalenvektor der Ebene
; [out] RETURN      : #True, wenn Ebene und Linie parallel
;                     #False, wenn Linie Ebene schneidet
Procedure LineToPlaneParallel_3D_Vektor(*u.Vector3D, *n.Vector3D)
  If *u\x * *n\x + *u\y * *n\y + *u\z * *n\z = 0
    ProcedureReturn #True
  EndIf
  ProcedureReturn #False
EndProcedure

;Berechnung, ob Linie parallel zu einer Ebene ist
; [in]  a1          : Startpunkt der Linie
; [in]  a2          : Endpunkt der Linie
; [in]  n           : Normalenvektor der Ebene
; [out] RETURN      : #True, wenn Ebene und Linie parallel
;                     #False, wenn Linie Ebene schneidet
Procedure LineToPlaneParallel_3D_Point(*a1.Vector3D, *a2.Vector3D, *n.Vector3D)
  Protected u.Vector3D
  
  u\x = *a2\x - *a1\x
  u\y = *a2\y - *a1\y
  u\z = *a2\z - *a1\z
  
  ProcedureReturn LineToPlaneParallel_3D_Vektor(@u, *n)
EndProcedure

;Berechnung, ob Linie in einer Ebene liegt
; [in]  a           : Aufpunkt der Linie
; [in]  u           : Richtungsvektor der Linie
; [in]  b           : Aufpunkt der Ebene
; [in]  n           : Normalenvektor der Ebene
; [out] RETURN      : #True, wenn Linie in Ebene liegt
Procedure LineInPlane_3D_Vector(*a.Vector3D, *u.Vector3D, *b.Vector3D, *n.Vector3D)
  Protected diff.Vector3D
  If *u\x * *n\x + *u\y * *n\y + *u\z * *n\z = 0
    diff\x = *a\x - *b\x
    diff\y = *a\y - *b\y
    diff\z = *a\z - *b\z
    
    If diff\x * *n\x + diff\y * *n\y + diff\z * *n\z = 0
      ProcedureReturn #True
    EndIf
  EndIf
  
  ProcedureReturn #False
EndProcedure

;Berechnung, ob Linie in einer Ebene liegt
; [in]  a1          : Startpunkt der Linie
; [in]  a2          : Endpunkt der Linie
; [in]  b           : Aufpunkt der Ebene
; [in]  n           : Normalenvektor der Ebene
; [out] RETURN      : #True, wenn Linie in Ebene liegt
Procedure LineInPlane_3D_Point(*a1.Vector3D, *a2.Vector3D, *b.Vector3D, *n.Vector3D)
  Protected u.Vector3D
  
  u\x = *a2\x - *a1\x
  u\y = *a2\y - *a1\y
  u\z = *a2\z - *a1\z
  
  ProcedureReturn LineInPlane_3D_Vector(*a1, @u, *b, *n)
EndProcedure

;Berechnung des Schnittpunktes einer Linie mit einer Ebene
; [in]  a           : Aufpunkt der Linie
; [in]  u           : Richtungs- und Längenvektor der Linie
; [in]  b           : Aufpunkt der Ebene
; [in]  n           : Normalenvektor der Ebene
; [out] pHit        : Schnittpunkt
; [out] RETURN      : #True, wenn Linie Ebene schneidet
Procedure LineHitsPlane_3D_Vector(*a.Vector3D, *u.Vector3D, *b.Vector3D, *n.Vector3D, *pHit.Vector3D)
  Protected NDotU.f, numerator.f, lambda.f
  
  NDotU = *n\x * *u\x + *n\y * *u\y + *n\z * *u\z
  
  If NDotU <> 0.0
    numerator = *n\x * (*b\x - *a\x) + *n\y * (*b\y - *a\y) + *n\z * (*b\z - *a\z)
    lambda = numerator / NDotU
    
    If lambda => 0.0 And lambda <= 1.0
      If *pHit
        *pHit\x = *a\x + lambda * *u\x
        *pHit\y = *a\y + lambda * *u\y
        *pHit\z = *a\z + lambda * *u\z
      EndIf
      ProcedureReturn #True
    EndIf
  EndIf
  
  ProcedureReturn #False
EndProcedure

;Berechnung des Schnittpunktes eines Strahls mit einer Ebene
; [in]  a           : Aufpunkt des Strahls
; [in]  u           : Richtungsvektor des Strahls
; [in]  b           : Aufpunkt der Ebene
; [in]  n           : Normalenvektor der Ebene
; [out] pHit        : Schnittpunkt
; [out] RETURN      : #True, wenn Strahl Ebene schneidet
Procedure RayHitsPlane_3D_Vector(*a.Vector3D, *u.Vector3D, *b.Vector3D, *n.Vector3D, *pHit.Vector3D)
  Protected NDotU.f, numerator.f, lambda.f
  
  NDotU = *n\x * *u\x + *n\y * *u\y + *n\z * *u\z
  
  If NDotU <> 0.0
    numerator = *n\x * (*b\x - *a\x) + *n\y * (*b\y - *a\y) + *n\z * (*b\z - *a\z)
    lambda = numerator / NDotU
    
    If lambda => 0.0
      If *pHit
        *pHit\x = *a\x + lambda * *u\x
        *pHit\y = *a\y + lambda * *u\y
        *pHit\z = *a\z + lambda * *u\z
      EndIf
      ProcedureReturn #True
    EndIf
  EndIf
  
  ProcedureReturn #False
EndProcedure

;Berechnung des Schnittpunktes einer Linie mit einer Ebene
; [in]  a1          : Startpunkt der Linie
; [in]  a2          : Endpunkt der Linie
; [in]  b           : Aufpunkt der Ebene
; [in]  n           : Normalenvektor der Ebene
; [out] pHit        : Schnittpunkt
; [out] RETURN      : #True, wenn Gerade Ebene schneidet
Procedure LineHitsPlane_3D_PointPNG(*a1.Vector3D, *a2.Vector3D, *b.Vector3D, *n.Vector3D, *pHit.Vector3D)
  Protected u.Vector3D
  
  u\x = *a2\x - *a1\x
  u\y = *a2\y - *a1\y
  u\z = *a2\z - *a1\z
  
  ProcedureReturn LineHitsPlane_3D_Vector(*a1, @u, *b, *n, *pHit)
EndProcedure

;Berechnung des Schnittpunktes einer Linie mit einer Ebene
; [in]  p1          : 1. Punkt für Ebene
; [in]  p2          : 2. Punkt für Ebene
; [in]  p3          : 3. Punkt für Ebene
; [in]  a1          : Startpunkt der Linie
; [in]  a2          : Endpunkt der Linie
; [out] pHit        : Schnittpunkt
; [out] RETURN      : #True, wenn Gerade Dreieck schneidet
Procedure LineHitsPlane_3D_Point(*p1.Vector3D, *p2.Vector3D, *p3.Vector3D, *a1.Vector3D, *a2.Vector3D, *pHit.Vector3D)
  Protected n.Vector3D, w.Vector3D, u.Vector3D, v.Vector3D
  
  w\x = *a2\x - *a1\x
  w\y = *a2\y - *a1\y
  w\z = *a2\z - *a1\z
  
  u\x = *p2\x - *p1\x
  u\y = *p2\y - *p1\y
  u\z = *p2\z - *p1\z
  
  v\x = *p3\x - *p1\x
  v\y = *p3\y - *p1\y
  v\z = *p3\z - *p1\z
  
  n\x = u\y * v\z - u\z * v\y
  n\y = u\z * v\x - u\x * v\z
  n\z = u\x * v\y - u\y * v\x
  
  ProcedureReturn LineHitsPlane_3D_Vector(*a1, @w, *p1, @n, *pHit)
EndProcedure

;Strahl trifft auf eine Ebene und wird von ihr gespiegelt
; [in]  a           : Anfangspunkt des Strahls
; [in]  u           : Richtunsgvektor des Strahls
; [in]  b           : Aufpunkt der Ebene
; [in]  n           : Normalenvektor der Ebene
; [out] a_out       : Schnittpunkt des Strahls mit der Ebene und Aufpunkt des Strahls
; [out] u_out       : Neuer Richtungsvektor des Strahls
; [out] RETURN      : #True, wenn Schnitt
Procedure RayHitsPlaneMirrored_3D_Vector(*a.Vector3D, *u.Vector3D, *b.Vector3D, *n.Vector3D, *a_out.Vector3D, *u_out.Vector3D)
  Protected NDotU.f, numerator.f, lambda.f, s.Vector3D, NSq.f, a_mirror.Vector3D
  
  NDotU = *n\x * *u\x + *n\y * *u\y + *n\z * *u\z
  
  If NDotU <> 0.0
    numerator = *n\x * (*b\x - *a\x) + *n\y * (*b\y - *a\y) + *n\z * (*b\z - *a\z)
    lambda = numerator / NDotU
    
    If lambda > 0.0
      s\x = *a\x + lambda * *u\x
      s\y = *a\y + lambda * *u\y
      s\z = *a\z + lambda * *u\z
      
      NSq = *n\x * *n\x + *n\y * *n\y + *n\z * *n\z
      
      lambda = 2 * numerator / NSq
      
      a_mirror\x = *a\x + lambda * *n\x
      a_mirror\y = *a\y + lambda * *n\y
      a_mirror\z = *a\z + lambda * *n\z
      
      If *u_out
        *u_out\x = s\x - a_mirror\x
        *u_out\y = s\y - a_mirror\y
        *u_out\z = s\z - a_mirror\z
      EndIf
      If *a_out
        *a_out\x = s\x
        *a_out\y = s\y
        *a_out\z = s\z
      EndIf
      
      ProcedureReturn #True
    EndIf
  EndIf
  
  If *u_out
    *u_out\x = *u\x
    *u_out\y = *u\y
    *u_out\z = *u\z
  EndIf
  If *a_out
    *a_out\x = *a\x
    *a_out\y = *a\y
    *a_out\z = *a\z
  EndIf
  
  ProcedureReturn #False
EndProcedure

;Linie trifft auf eine Ebene und wird von ihr gespiegelt
; [in]  a           : Aufpunkt der Linie
; [in]  u           : Richtunsgs- und Längenvektor der Linie
; [in]  b           : Aufpunkt der Ebene
; [in]  n           : Normalenvektor der Ebene
; [out] a_out       : Schnittpunkt der Linie mit der Ebene und Aufpunkt der Linie oder unverändert, falls kein Schnitt
; [out] u_out       : Neuer Richtungs- und Längenvektor der Linie
; [out] RETURN      : #True, wenn Schnitt
Procedure LineHitsPlaneMirrored_3D_Vector(*a.Vector3D, *u.Vector3D, *b.Vector3D, *n.Vector3D, *a_out.Vector3D, *u_out.Vector3D)
  Protected NDotU.f, numerator.f, lambda.f, s.Vector3D, NSq.f, a_mirror.Vector3D, sigma.f
  
  NDotU = *n\x * *u\x + *n\y * *u\y + *n\z * *u\z
  
  If NDotU <> 0.0
    numerator = *n\x * (*b\x - *a\x) + *n\y * (*b\y - *a\y) + *n\z * (*b\z - *a\z)
    lambda = numerator / NDotU
    
    If lambda > 0.0 And lambda <= 1.0
      s\x = *a\x + lambda * *u\x
      s\y = *a\y + lambda * *u\y
      s\z = *a\z + lambda * *u\z
      
      NSq = *n\x * *n\x + *n\y * *n\y + *n\z * *n\z
      
      sigma = 2.0 * numerator / NSq
      
      a_mirror\x = *a\x + sigma * *n\x
      a_mirror\y = *a\y + sigma * *n\y
      a_mirror\z = *a\z + sigma * *n\z
      
      lambda = 1 / lambda - 1
      
      If *u_out
        *u_out\x = lambda * (s\x - a_mirror\x)
        *u_out\y = lambda * (s\y - a_mirror\y)
        *u_out\z = lambda * (s\z - a_mirror\z)
      EndIf
      If *a_out
        *a_out\x = s\x
        *a_out\y = s\y
        *a_out\z = s\z
      EndIf
      ProcedureReturn #True
    Else
      If *u_out
        *u_out\x = *u\x
        *u_out\y = *u\y
        *u_out\z = *u\z
      EndIf
      If *pHit
        *a_out\x = *a\x
        *a_out\y = *a\y
        *a_out\z = *a\z
      EndIf 
    EndIf
  Else
    If *u_out
      *u_out\x = *u\x
      *u_out\y = *u\y
      *u_out\z = *u\z
    EndIf
    If *a_out
      *a_out\x = *a\x
      *a_out\y = *a\y
      *a_out\z = *a\z
    EndIf
    ProcedureReturn #False
  EndIf
  
  ProcedureReturn #False
EndProcedure

;Linie trifft auf eine Ebene und wird von ihr gespiegelt
; [in]  a1          : Anfangspunkt der Linie
; [in]  a2          : Endpunkt der Linie
; [in]  b           : Aufpunkt der Ebene
; [in]  n           : Normalenvektor der Ebene
; [out] a_out       : Schnittpunkt der Linie mit der Ebene und Aufpunkt der Linie
; [out] u_out       : Neuer Richtungs- und Längenvektor der Linie
; [out] RETURN      : #True, wenn Schnitt
Procedure LineHitsPlaneMirrored_3D_Point(*a1.Vector3D, *a2.Vector3D, *b.Vector3D, *n.Vector3D, *a_out.Vector3D, *u_out.Vector3D)
  Protected u.Vector3D
  
  u\x = *a2\x - *a1\x
  u\y = *a2\y - *a1\y
  u\z = *a2\z - *a1\z
  
  ProcedureReturn LineHitsPlaneMirrored_3D_Vector(*a1, @u, *b, *n, *a_out, *u_out)
EndProcedure

;Linie trifft auf eine Ebene und wird von ihr gespiegelt
; [in]  a1          : Anfangspunkt der Linie
; [in]  a2          : Endpunkt der Linie
; [in]  b           : Aufpunkt der Ebene
; [in]  n           : Normalenvektor der Ebene
; [out] a1_out      : Schnittpunkt der Linie mit der Ebene und Aufpunkt der Linie
; [out] a2_out      : Endpunkt der Linie nach Schnitt
; [out] RETURN      : #True, wenn Schnitt
Procedure LineHitsPlaneMirrored_3D_PointEx(*a1.Vector3D, *a2.Vector3D, *b.Vector3D, *n.Vector3D, *a1_out.Vector3D, *a2_out.Vector3D)
  Protected u.Vector3D, Result.l
  
  u\x = *a2\x - *a1\x
  u\y = *a2\y - *a1\y
  u\z = *a2\z - *a1\z
  
  Result = LineHitsPlaneMirrored_3D_Vector(*a1, @u, *b, *n, *a1_out, *a2_out)
  
  *a2_out\x + *a1_out\x
  *a2_out\y + *a1_out\y
  *a2_out\z + *a1_out\z
  
  ProcedureReturn #False
EndProcedure

;}

;{- 3D Triangles and Lines

; [in]  p1          : 1. Punkt des Dreiecks
; [in]  p2          : 2. Punkt des Dreiecks
; [in]  p3          : 3. Punkt des Dreiecks
; [in]  a           : Aufpunkt der Linie
; [in]  w           : Richtungs- und Längenvektor der Linie
; [out] pHit        : Schnittpunkt oder falls kein Schnitt Endpunkt der Linie
; [out] RETURN      : #True, wenn Gerade Dreieck schneidet
Procedure LineHitsTriangle_3D_Vector(*p1.Vector3D, *p2.Vector3D, *p3.Vector3D, *a.Vector3D, *w.Vector3D, *pHit.Vector3D)
  Protected sigma.f, lambda.f, mue.f, n.Vector3D, u.Vector3D, v.Vector3D, NDotU.f, a.f
  
  u\x = *p2\x - *p1\x
  u\y = *p2\y - *p1\y
  u\z = *p2\z - *p1\z
  
  v\x = *p3\x - *p1\x
  v\y = *p3\y - *p1\y
  v\z = *p3\z - *p1\z
  
  n\x = u\y * v\z - u\z * v\y
  n\y = u\z * v\x - u\x * v\z
  n\z = u\x * v\y - u\y * v\x
  
  NDotU = n\x * *w\x + n\y * *w\y + n\z * *w\z
  
  If NDotU <> 0.0
    numerator = n\x * (*p1\x - *a\x) + n\y * (*p1\y - *a\y) + n\z * (*p1\z - *a\z)
    sigma = numerator / NDotU
    
    If sigma => 0.0 And sigma <= 1.0
      
      a = u\x * v\y - u\y * v\x
      
      If a <> 0
        lambda = (u\x * (*a\y - *p1\y) - u\y * (*a\x - *p1\x) + sigma * (*w\y * u\x - *w\x * u\y)) / a
      Else
        a = u\x * v\z - u\z * v\x
        If a <> 0
          lambda = (u\x * (*a\z - *p1\z) - u\z * (*a\x - *p1\x) + sigma * (*w\z * u\x - *w\x * u\z)) / a
        Else
          a = u\y * v\z - u\z * v\y
          If a <> 0
            lambda = (u\y * (*a\z - *p1\z) - u\z * (*a\y - *p1\y) + sigma * (*w\z * u\y - *w\y * u\z)) / a
          EndIf
        EndIf
      EndIf
      
      If lambda >= 0.0 And lambda <= 1.0
        If u\x <> 0
          mue = ((*a\x - *p1\x) - lambda * v\x + sigma * *w\x) / u\x
        ElseIf u\y <> 0
          mue = ((*a\y - *p1\y) - lambda * v\y + sigma * *w\y) / u\y
        ElseIf u\z <> 0
          mue = ((*a\z - *p1\z) - lambda * v\z + sigma * *w\z) / u\z
        EndIf
        
        If mue >= 0.0 And mue <= 1.0
          If mue + lambda <= 1
            If *pHit
              *pHit\x = *a\x + sigma * *w\x
              *pHit\y = *a\y + sigma * *w\y
              *pHit\z = *a\z + sigma * *w\z
            EndIf
            
            ProcedureReturn #True
          EndIf
        EndIf
        
      EndIf
      
    EndIf
    
  EndIf
  
  *pHit\x = *a\x + *w\x
  *pHit\y = *a\y + *w\y
  *pHit\z = *a\z + *w\z
  
  ProcedureReturn #False
EndProcedure

Procedure LineHitsTriangle_3D_Point(*p1.Vector3D, *p2.Vector3D, *p3.Vector3D, *a1.Vector3D, *a2.Vector3D, *pHit.Vector3D)
  Protected w.Vector3D
  
  w\x = *a2\x - *a1\x
  w\y = *a2\y - *a1\y
  w\z = *a2\z - *a1\z
  
  ProcedureReturn LineHitsTriangle_3D_Vector(*p1, *p2, *p3, *a1, @w, *pHit)
EndProcedure

;}

Code: Alles auswählen

Structure Vector2D
  x.f
  y.f
EndStructure

Structure Line2D
  x1.f
  y1.f
  x2.f
  y2.f
EndStructure

Structure Vector3d
  x.f
  y.f
  z.f
EndStructure

Structure Line3D
  x1.f
  y1.f
  z1.f
  x2.f
  y2.f
  z2.f
EndStructure
Zuletzt geändert von NicTheQuick am 28.05.2005 21:15, insgesamt 6-mal geändert.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8808
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

Ich hatte die [c]Structures.pbi[/c] vergessen. Ist jetzt im obigen Post drin.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8808
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

Ich habe noch ein paar neue Funktionen für Ebenen und Linien eingefügt.

So langsam hab ich alles zusammen und dann kommt wohl noch eine kleine Hilfe dazu mit dem Hintergrund der Theorie und für den Verwendungszweck.

PureFan ist übrigens gerade dabei die jetzt schon so schnellen und genauen Routinen in handoptimiertes ASM umzusetzen.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8808
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

So, das letzte Update für heut Nacht.

Und hier eine kleine Funktionsübersicht:
  1. 2D-Ebene
    1. Berechnung des Schnittpunktes zweier Linien
    2. Berechnung, ob sich zwei Kreise schneiden (Schnittpunkte fehlen noch)
    3. Berechnung des nächsten Schnittpunktes von Linie und Kreis (auf Wunsch kann ich auch beide Schnittpunkte berechnen lassen)
  2. 3D-Raum
    1. Berechnung des nächsten Schnittpunktes von Strahl und Kugel (auf Wunsch auch beide)
    2. Berechnung des nächsten Schnittpunktes von Linie und Kugel (auf Wunsch auch beide)
    3. Errechnung der Normalen aus zwei Vektoren
    4. Umrechnung der Ebenendarstellungen aus zwei Richtungsvektoren und einem Aufpunkt zur Punkt- und Allgemeinen-Normalengleichung
    5. Errechnung aller Ebenengleichungen aus drei Punkten
    6. Berechnung des Abstandes eine Ebene zum Ursprung
    7. Prüfung, ob zwei Ebenen parallel liegen
    8. Prüfung, ob zwei Ebenen aufeinandern liegen (gleich sind)
    9. Prüfung, ob eine Linie zur Ebene parallel ist
    10. Prüfung, ob eine Linie in einer Ebene liegt
    11. Berechnung des Schnittpunktes einer Linie mit einer Ebene
    12. Berechnung des Schnittpunktes einer Linie mit einem Dreieck
  3. ToDo
    1. Berechnung der Schnittpunkte zweier Kreise
    2. Berechnung des Schnittkreises zweier Kugeln als Ebene, Mittelpunkt und Radius
    3. Berechnung des Treffpunktes und des Ausfallvektors bei Kollision einer Kugel mit einer Ebene
    4. Berechnung der Tangenten, die man von einem beliebigen Punkt außerhalb eines Kreises an diesen legen kann
    5. und noch vieles mehr... :)
PS.: Jemand da, der die Funktionen mal testen will? Vielleicht hab ich ja noch ein paar Fehler drin. Aber ein bisschen getestet habe ich auch schon. Dank DarkDragons Hilfe ging das auch recht schnell. :allright:
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8808
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

Und wieder ein paar neue Funktionen.

Und dann noch ein kleines Beispiel-Programm, das zeigt, was man schon alles so berechnen kann.

Test.exe
Umschauen mit der Maus.
Bewegen mit den Cursortasten.
Mit A, S, D und W kann man den Startpunkt der Linie ändern.
Mit F, G, H und T kann man den Endpunkt der Linie ändern.

Man sieht ein Dreieck im Raum und eine Linie, die das Dreieck schneidet. Fliegt man um das Dreieck herum sieht man den blinkenden Restteil der Linie. Wenn man die Linie jetzt so verschiebt, dass sie das Dreieck nicht mehr schneidet, blinkt sie nicht mehr und die reflektierte Linie ist auch nicht mehr da.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8808
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

Kleines weiteres Beispiel mit dem Spiegeln einer Linie an einer imaginären Kugel. Imaginär deswegen, weil ich nicht weiß, wie ich mit OpenGL so leicht eine Kugel darstellen kann. :lol:

Test2.exe
Es ist alles wie vorher, bloß muss man sich jetzt zwischen den beiden grauen Platten eine Kugel vorstellen. Wenn man daneben geflogen ist und mit W, S oder A, D ein bisschen rumspielt, sollte man merken, was ich mit dem spiegeln an der Kugel meine.

Demnächst kommt dann wohl noch ein Beispiel, wo man sieht, wie eine Linie zwischen mehreren Dreiecken und vielleicht dann sichtbaren Kugeln rumgespiegelt wird.
Zuletzt geändert von NicTheQuick am 28.05.2005 02:56, insgesamt 1-mal geändert.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8808
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

So, das gleiche dann nochmal, bloß etwas spektakulärer mit 16 Linien. :wink:

Test3.exe

Man schaue und staune, was damit alles möglich wäre. :allright:
Benutzeravatar
ChristianK
Beiträge: 77
Registriert: 13.12.2004 14:55

Beitrag von ChristianK »

Ich verstehe gar nichts von deinen routinen!liegt daran daß zu viele pointer benutzt werden
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8808
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

Was soll dieses unnötige Kommentar jetzt? :angry:
Ich werde dir hier wohl keine Pointer erklären. Und mit weniger Pointern gehts eben nicht.
Du musst es ja nicht verstehen, wenn du es bloß anwenden willst. Außerdem kommt die Hilfe erst zum Schluss. /:->
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8808
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag von NicTheQuick »

So sieht es bisher aus mit mehrfachen Kollisionen:
Bild
Bild
Antworten