3D Kollisionen - Box und Punkt

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
Benutzeravatar
Makke
Beiträge: 156
Registriert: 24.08.2011 18:00
Computerausstattung: AMD Ryzen 7 5700X - AMD Radeon RX 6800 XT - 32 GB DDR4 SDRAM
Wohnort: Ruhrpott
Kontaktdaten:

3D Kollisionen - Box und Punkt

Beitrag von Makke »

Hallo zusammen,

ich beschäftige mich gerade mit dem 3D Part von Purebasic. Aktuell mit Kollisionen, ich habe folgendes Tutorial im Netz gefunden: http://www.neobrothers.de/oldpage1/tuto ... ision.html

Ich fand das ganz gut erklärt, die Funktionen die dort verwendet wurden findet man im MSDN erklärt (http://msdn.microsoft.com/en-us/library ... 85%29.aspx).

Bei der Umsetzung meinerseits hakt es aber gewaltig, anstatt das Ergebnis zu bekommen, das der Punkt in der Box liegt, bekomme ich den Rückgabewert vor welcher Seite er liegt, siehe hier:

Code: Alles auswählen

EnableExplicit

Structure fVector3D
  x.f
  y.f
  z.f
EndStructure

Structure Box3D
  Array p.fVector3D(7)
EndStructure

Structure Model3DHandle
  hTex.i
  hMat.i
  hMsh.i
  hEnt.i
EndStructure

Define.i hLine, hCam, WindowEvt, MouseMoveX, MouseMoveY, DoLoop = #True
Define.fVector3D p1, p2
Define.Model3DHandle plane1, plane2, plane3
Define.Box3D box

Macro Do(Status, Error, EndProgram = #True)
  If Not Status
    CompilerIf #PB_Compiler_Debugger
      Debug "ERROR: " + Error
    CompilerElse
      MessageRequester("ERROR", Error)
    CompilerEndIf
    CompilerIf EndProgram
      End
    CompilerEndIf
  EndIf
EndMacro

Macro PrintV(v)
  Debug "x="+StrF(v\x,1)+", y="+StrF(v\y,1)+", z="+StrF(v\z,1)
EndMacro

Procedure VectorSub(*v1.fVector3D, *v2.fVector3D, *result.fVector3D)
  *result\x = *v1\x - *v2\x
  *result\y = *v1\y - *v2\y
  *result\z = *v1\z - *v2\z
EndProcedure

Procedure VectorCross(*v1.fVector3D, *v2.fVector3D, *result.fVector3D)
  *result\x = (*v1\y * *v2\z) - (*v1\z * *v2\y)
  *result\y = (*v1\z * *v2\x) - (*v1\x * *v2\z)
  *result\z = (*v1\x * *v2\y) - (*v1\y * *v2\x)
EndProcedure

Procedure.f VectorDot(*v1.fVector3D, *v2.fVector3D)
  ProcedureReturn (*v1\x * *v2\x) + (*v1\y * *v2\y) + (*v1\z * *v2\z)
EndProcedure

Procedure VectorNormalize(*v1.fVector3D)
  Protected length.f = Sqr((*v1\x * *v1\x) + (*v1\y * *v1\y) + (*v1\x * *v1\z))
  *v1\x = *v1\x / length
  *v1\y = *v1\y / length
  *v1\z = *v1\z / length
EndProcedure

Procedure BallBlock_Collision(*box.Box3D, *point.fVector3D)
  
  Protected.i collide = 0
  Protected.fVector3D normal, result1, result2, result3
  
  ; bottom
  If collide = 0
    VectorSub(*box\p(1), *box\p(0), result1)
    VectorSub(*box\p(2), *box\p(0), result2)
    VectorCross(result1, result2, normal)
    VectorSub(*point, *box\p(0), result3)
    If VectorDot(normal, result3) <= 0
      collide = 1
    EndIf
  EndIf
  
  ; top
  If collide = 0
    VectorSub(*box\p(6), *box\p(4), result1)
    VectorSub(*box\p(5), *box\p(4), result2)
    VectorCross(result1, result2, normal)
    VectorSub(*point, *box\p(4), result3)
    If VectorDot(normal, result3) <= 0
      collide = 2
    EndIf
  EndIf
  
  ; front
  If collide = 0 
    VectorSub(*box\p(6), *box\p(2), result1)
    VectorSub(*box\p(3), *box\p(2), result2)
    VectorCross(result1, result2, normal)
    VectorSub(*point, *box\p(2), result3)
    If VectorDot(normal, result3) <= 0
      collide = 3
    EndIf
  EndIf
  
  ; rear
  If collide = 0
    VectorSub(*box\p(4), *box\p(0), result1)
    VectorSub(*box\p(1), *box\p(0), result2)
    VectorCross(result1, result2, normal)
    VectorSub(*point, *box\p(0), result3)
    If VectorDot(normal, result3) <= 0
      collide = 4
    EndIf
  EndIf

  ; right
  If collide = 0
    VectorSub(*box\p(5), *box\p(1), result1)
    VectorSub(*box\p(2), *box\p(1), result2)
    VectorCross(result1, result2, normal)
    VectorSub(*point, *box\p(1), result3)
    If VectorDot(normal, result3) <= 0
      collide = 5
    EndIf
  EndIf

  ; left
  If collide = 0
    VectorSub(*box\p(3), *box\p(0), result1)
    VectorSub(*box\p(4), *box\p(0), result2)
    VectorCross(result1, result2, normal)
    VectorSub(*point, *box\p(0), result3)
    If VectorDot(normal, result3) <= 0
      collide = 6
    EndIf
  EndIf
  
  Debug collide
  ProcedureReturn collide
  
EndProcedure

Procedure DrawBox()
  Shared box
  Protected.i n
  For n = 0 To 7 Step 2
    CreateLine3D(#PB_Any, box\p(n)\x, box\p(n)\y, box\p(n)\z, RGB(255,0,0), box\p(n+1)\x, box\p(n+1)\y, box\p(n+1)\z, RGB(255,0,0))
  Next
  CreateLine3D(#PB_Any, box\p(0)\x, box\p(0)\y, box\p(0)\z, RGB(255,0,0), box\p(3)\x, box\p(3)\y, box\p(3)\z, RGB(255,0,0))
  CreateLine3D(#PB_Any, box\p(1)\x, box\p(1)\y, box\p(1)\z, RGB(255,0,0), box\p(2)\x, box\p(2)\y, box\p(2)\z, RGB(255,0,0))
  CreateLine3D(#PB_Any, box\p(4)\x, box\p(4)\y, box\p(4)\z, RGB(255,0,0), box\p(7)\x, box\p(7)\y, box\p(7)\z, RGB(255,0,0))
  CreateLine3D(#PB_Any, box\p(5)\x, box\p(5)\y, box\p(5)\z, RGB(255,0,0), box\p(6)\x, box\p(6)\y, box\p(6)\z, RGB(255,0,0))
  CreateLine3D(#PB_Any, box\p(0)\x, box\p(0)\y, box\p(0)\z, RGB(255,0,0), box\p(4)\x, box\p(4)\y, box\p(4)\z, RGB(255,0,0))
  CreateLine3D(#PB_Any, box\p(1)\x, box\p(1)\y, box\p(1)\z, RGB(255,0,0), box\p(5)\x, box\p(5)\y, box\p(5)\z, RGB(255,0,0))
  CreateLine3D(#PB_Any, box\p(3)\x, box\p(3)\y, box\p(3)\z, RGB(255,0,0), box\p(7)\x, box\p(7)\y, box\p(7)\z, RGB(255,0,0))
  CreateLine3D(#PB_Any, box\p(2)\x, box\p(2)\y, box\p(2)\z, RGB(255,0,0), box\p(6)\x, box\p(6)\y, box\p(6)\z, RGB(255,0,0))
EndProcedure

Procedure DrawLine()
  Shared p1, p2
  Shared hLine, plane1, plane2
  If Not IsTexture(plane1\hTex)
    plane1\hTex = CreateTexture(#PB_Any, 64, 64)
    StartDrawing(TextureOutput(plane1\hTex))
    DrawText(32, 0, "p1", RGB(0,255,0))
    StopDrawing()
  EndIf
  If Not IsMaterial(plane1\hMat)
    plane1\hMat = CreateMaterial(#PB_Any, TextureID(plane1\hTex))
    MaterialBlendingMode(plane1\hMat, #PB_Material_Add)
  EndIf
  If Not IsMesh(plane1\hMsh)
    plane1\hMsh = CreatePlane(#PB_Any, 50, 50, 1, 1, 1, 1)
  EndIf
  If Not IsTexture(plane2\hTex)
    plane2\hTex = CreateTexture(#PB_Any, 64, 64)
    StartDrawing(TextureOutput(plane2\hTex))
    DrawText(16, 0, "p2", RGB(0,255,0))
    StopDrawing()
  EndIf
  If Not IsMaterial(plane2\hMat)
    plane2\hMat = CreateMaterial(#PB_Any, TextureID(plane2\hTex))
    MaterialBlendingMode(plane2\hMat, #PB_Material_Add)
  EndIf
  If Not IsMesh(plane2\hMsh)
    plane2\hMsh = CreatePlane(#PB_Any, 50, 50, 1, 1, 1, 1)
  EndIf
  If IsMesh(hLine) : FreeMesh(hLine) : EndIf
  hLine = CreateLine3D(#PB_Any, p1\x, p1\y, p1\z, RGB(0,255,0), p2\x, p2\y, p2\z, RGB(0,255,0))
  If Not IsEntity(plane1\hEnt)
    plane1\hEnt = CreateEntity(#PB_Any, MeshID(plane1\hMsh), MaterialID(plane1\hMat), p1\x, p1\y-35, p1\z)
    RotateEntity(plane1\hEnt, 90, 180, 0, #PB_Absolute)
  Else
    MoveEntity(plane1\hEnt, p1\x, p1\y-35, p1\z, #PB_Absolute)
  EndIf
  If Not IsEntity(plane2\hEnt)
    plane2\hEnt = CreateEntity(#PB_Any, MeshID(plane2\hMsh), MaterialID(plane2\hMat), p2\x, p2\y-35, p2\z)
    RotateEntity(plane2\hEnt, 90, 180, 0, #PB_Absolute)
  Else
    MoveEntity(plane2\hEnt, p2\x, p2\y-35, p2\z, #PB_Absolute)
  EndIf
EndProcedure

Procedure DrawInfo(Collision.i)
  Shared plane3
  Static.i lastCollision, done
  If done = 0
    plane3\hTex = CreateTexture(#PB_Any, 128, 64)
    StartDrawing(TextureOutput(plane3\hTex))
    DrawText(0, 0, "move Mouse", RGB(255,255,255))
    StopDrawing()
    plane3\hMat = CreateMaterial(#PB_Any, TextureID(plane3\hTex))
    MaterialBlendingMode(plane3\hMat, #PB_Material_Add)
    plane3\hMsh = CreatePlane(#PB_Any, 100, 50, 1, 1, 1, 1)
    plane3\hEnt = CreateEntity(#PB_Any, MeshID(plane3\hMsh), MaterialID(plane3\hMat), 0, 100, 0)
    RotateEntity(plane3\hEnt, 90, 180, 0, #PB_Absolute)
    done = 1
    lastCollision = -1
  EndIf
  If lastCollision <> Collision
    If IsTexture(plane3\hTex) : FreeTexture(plane3\hTex) : EndIf
    Select Collision
      Case 0
        plane3\hTex = CreateTexture(#PB_Any, 128, 64)
        StartDrawing(TextureOutput(plane3\hTex))
        DrawText(0, 0, "no Collision", RGB(255,255,255))
        StopDrawing()
      Case 1
        plane3\hTex = CreateTexture(#PB_Any, 128, 64)
        StartDrawing(TextureOutput(plane3\hTex))
        DrawText(0, 0, "p1 Collide", RGB(255,255,255))
        StopDrawing()
      Case 2
        plane3\hTex = CreateTexture(#PB_Any, 128, 64)
        StartDrawing(TextureOutput(plane3\hTex))
        DrawText(0, 0, "p2 Collide", RGB(255,255,255))
        StopDrawing()
    EndSelect
    If IsMaterial(plane3\hMat)
      FreeMaterial(plane3\hMat)
      plane3\hMat = CreateMaterial(#PB_Any, TextureID(plane3\hTex))
      MaterialBlendingMode(plane3\hMat, #PB_Material_Add)
    EndIf
    SetEntityMaterial(plane3\hEnt, MaterialID(plane3\hMat))
    lastCollision = Collision
  EndIf
EndProcedure

; init
Do(InitEngine3D(), "Can not init 3D Engine")
Do(InitSprite(), "Can not init Sprite")
Do(InitKeyboard(), "Can not init Keyboard")
Do(InitMouse(), "Can not init Mouse")
Do(ExamineDesktops(), "Can not find Desktops")
Do(OpenWindow(0, 0, 0, DesktopWidth(0)/1.5, DesktopHeight(0)/1.5, "Collision", #PB_Window_ScreenCentered|#PB_Window_SystemMenu), "Can Not open window")
Do(OpenWindowedScreen(WindowID(0), 0, 0, WindowWidth(0), WindowHeight(0), 0, 0, 0, #PB_Screen_SmartSynchronization), "Can not open screen")

; build box
;   7--------6
;   /|      /
;  / |     /|
; /  |    / |
;4--------5 |
; |  |   |  |
; | 3|---|--/2
; | /    | /
; |/     |/
;0--------1    
; center is 0,0,0
box\p(0)\x = -50
box\p(0)\y = -50
box\p(0)\z = 50
box\p(1)\x = 50
box\p(1)\y = -50
box\p(1)\z = 50
box\p(2)\x = 50
box\p(2)\y = -50
box\p(2)\z = -50
box\p(3)\x = -50
box\p(3)\y = -50
box\p(3)\z = -50
box\p(4)\x = -50
box\p(4)\y = 50
box\p(4)\z = 50
box\p(5)\x = 50
box\p(5)\y = 50
box\p(5)\z = 50
box\p(6)\x = 50
box\p(6)\y = 50
box\p(6)\z = -50
box\p(7)\x = -50
box\p(7)\y = 50
box\p(7)\z = -50

; build points
p1\x = 200
p1\y = 0
p1\z = 0
p2\x = 400
p2\y = 0
p2\z = 0

DrawBox()

DrawLine()

DrawInfo(0)

hCam = CreateCamera(#PB_Any, 0, 0, 100, 100)
MoveCamera(hCam, 0, 0, 500, #PB_Absolute)

Repeat
  ; catch all window events
  Repeat
  
    WindowEvt = WindowEvent()
    
    Select WindowEvt
    
      Case #PB_Event_CloseWindow
        DoLoop = #False
        
    EndSelect
       
  Until WindowEvt = 0
  
  ; catch keystrokes
  If ExamineKeyboard()
    
    If KeyboardPushed(#PB_Key_Escape)
      DoLoop = #False
    EndIf

  EndIf
  
  ; catch mouse and move line3d
  If ExamineMouse()
    
    MouseMoveX = MouseDeltaX()
    MouseMoveY = MouseDeltaY()
    p1\x = p1\x + MouseMoveX * 0.5
    p1\y = p1\y - MouseMoveY * 0.5
    p2\x = p2\x + MouseMoveX * 0.5
    DrawLine()
    
    ; check collision
    If BallBlock_Collision(box, p1)
      DrawInfo(1)
    Else
      DrawInfo(0)
    EndIf
;     If BallBlock_Collision(box, p2)
;       DrawInfo(2)
;     Else
;       DrawInfo(0)
;     EndIf
    
  EndIf
  
  ; render world
  RenderWorld()
  FlipBuffers() 

Until DoLoop = #False
End
Ich bin ratlos, kann hier jemand einen Tip geben was ich falsch mache ?

Sollte das gelöst werden, vielleicht hat auch noch jemand einen Tip wie ich die Kollision eine Kugel mit einer Box errechne ?

Vielen Dank im voraus.
---
Windows 11 (64 bit)