Kollision Maus/Terrain berechnen [gelöst]

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
Benutzeravatar
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Beitrag von Scarabol »

Tausend Dank! :allright:
Genau das hab ich gesucht.

Gruß
Scarabol
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea

PB-V: 4
WinXP
Benutzeravatar
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Beitrag von Scarabol »

Hallo

Nur wie mach ich das jetzt mit der Cameradrehung egal wie, immer wenn ich die Camera Vektoren zur Laufzeit ändere geht die Zielberechnung in die Hose.

Gruß
Scarabol
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea

PB-V: 4
WinXP
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

genau die problematik hatte Froggerprogger ja angesprochen.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Beitrag von Scarabol »

Ja schon aber wie kommt es das ich im Code die Camera postieren kann wo ich will, dies im laufenden Programm aber nicht mehr ohne Probleme geht?

Gruß
Scarabol
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea

PB-V: 4
WinXP
Benutzeravatar
Froggerprogger
Badmin
Beiträge: 855
Registriert: 08.09.2004 20:02

Beitrag von Froggerprogger »

Du kannst die Kamera beliebig in den beiden Achsen drehen, die du schriebst, also quasi Himmelsrichtung und Rauf/Runter. Nicht jedoch die Rotation um die Sichtachse, also den Horizont schräg legen.
Du kannst also jederzeit die Kamera beliebig positionieren und dann LookAt player aufrufen.

Allerdings muss dann nach jeder Kameraänderung der Bereich, den ich im Source durch die

Code: Alles auswählen

If initialized = #False 
...
EndIf
ausgeklammert habe neu berechnet werden.
Am einfachsten schmeisst du einfach diese If / EndIfs raus und entfernst die nun unnötige erste Zeile

Code: Alles auswählen

Vec_Add(@playerPos, @camOffset, @camPos) ; needed by the following
Was geschieht in dem Block ? Es wird der Vektor CameraDir berechnet, also der Vektor der die Sichtlinie der Kamera angibt. Wenn deine Kamera um den Player herum rotiert, so muss daher camDir neuberechnet werden, was in meinem Beispiel unnötig war, da die Kamera nich rotiert hat.

Solltest du irgendwann doch mal auch wünschen, dass die Kamera um die Sichtlinie herum rotieren kann, dann musst du 'einfach' nur den up-Vektor, der derzeit auf (0,1,0) gesetzt ist entsprechend anpassen, was aber etwas leichter klingt, als getan ist.
!UD2
Benutzeravatar
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Beitrag von Scarabol »

So hab den Code mal erweitert.

Die Camera lässt sich jetzt mit Rechtsklick um das Mesh drehen.
Die Camera kann nicht unter das Terrain sehen.

Gibt es eine Möglichkeit das das Enitity immer genau senkrecht zum Boden ausgerichtet wird?

Code: Alles auswählen

; TerrainCollision.pb
;
; Example how to translate 2D-screencoordinates into a 3D-worldposition given by the first hit with the terrain
;
; If you want to use RotateCamera, you would have to change this example (setting up the up-vector again
; and recalculate some values supposed to be constant in this examples)
;
; To start this example copy it to the PureBasic\Examples\Sources - directory to let it reference the requested resources
;
; by Froggerprogger, 01.04.07

#CameraSpeed = 5

#Deg2Rad = #PI / 180.0
#Rad2Deg = 1.0 / #Deg2Rad

; declared as global to get them from within Screen3DRequester
Global ScreenWidth, ScreenHeight

IncludeFile "Screen3DRequester.pb"

Define.f KeyX, KeyY, MouseX, MouseY

; a structure for a 3D-float-vector
Structure Vec3D
  x.f
  y.f
  z.f
EndStructure

; some vector-math
Procedure.f Vec_ScalarProd(*v1.Vec3D, *v2.Vec3D) ; <v1, v2>
  ProcedureReturn *v1\x * *v2\x + *v1\y * *v2\y + *v1\z * *v2\z 
EndProcedure

Procedure.f Vec_Abs(*v1.Vec3D) ; |v1|
  Protected z.f
  z = Sqr(*v1\x * *v1\x + *v1\y * *v1\y + *v1\z * *v1\z)
  ProcedureReturn z
EndProcedure

Procedure Vec_ScalarMul(*v1.Vec3D, f.f, *v.Vec3D = 0) ; v1 = f * v1
  If *v = 0
    *v = *v1
  EndIf
  *v\x = *v1\x * f
  *v\y = *v1\y * f
  *v\z = *v1\z * f
EndProcedure

Procedure Vec_VectorProd(*v1.Vec3D, *v2.Vec3D, *v.Vec3D) ; v = v1 x v2
  *v\x = *v1\y * *v2\z - *v1\z * *v2\y
  *v\y = *v1\z * *v2\x - *v1\x * *v2\z
  *v\z = *v1\x * *v2\y - *v1\y * *v2\x
EndProcedure

Procedure Vec_Add(*v1.Vec3D, *v2.Vec3D, *v.Vec3D) ; v = v1 + v2
  *v\x = *v1\x + *v2\x
  *v\y = *v1\y + *v2\y
  *v\z = *v1\z + *v2\z
EndProcedure

Procedure Vec_Sub(*v1.Vec3D, *v2.Vec3D, *v.Vec3D) ; v = v1 - v2
  *v\x = *v1\x - *v2\x
  *v\y = *v1\y - *v2\y
  *v\z = *v1\z - *v2\z
EndProcedure

Procedure Vec_Copy(*v1.Vec3D, *v.Vec3D) ; v = v1
  *v\x = *v1\x
  *v\y = *v1\y
  *v\z = *v1\z
EndProcedure

Procedure Vec_Set(x.f, y.f, z.f, *v.Vec3D) ; v = (x,y,z)
  *v\x = x
  *v\y = y
  *v\z = z
EndProcedure

Procedure.d Vec_Distance(*v1.Vec3D, *v2.Vec3D)
  ProcedureReturn Sqr(Pow(*v1\x - *v2\x, 2)+Pow(*v1\y - *v2\y, 2)+Pow(*v1\z - *v2\z, 2))
EndProcedure


Procedure.f GSin(winkel.f)
  ProcedureReturn Sin(winkel*#PI/180)
EndProcedure

Procedure.f GCos(winkel.f)
  ProcedureReturn Cos(winkel*#PI/180)
EndProcedure

Procedure.f Distance3D(x1, y1, z1, x2, y2, z2)
  ProcedureReturn Sqr(Pow(x1-x2,2)+Pow(y1-y2,2)+Pow(z1-z2,2))
EndProcedure

playerPos.Vec3D   ; player's position (same as lookAt)
startPos.Vec3D    ; player's startposition when automoving
targetPos.Vec3D   ; player' targetposition when automoving
camOffset.Vec3D   ; the camera's offset from which to look at the player
camPos.Vec3D      ; the cameras position (playerPos + camOffset)
camDir.Vec3D      ; the direction of the camera (playerPos - camPos)
up.Vec3D          ; the camera's up-position
Vec_Set(0, 1, 0, @up)
pointerDir.Vec3D  ; the line from camPos through the mousecursor
lVector.Vec3D     ; (normalized) vector showing to the screen's left side orthogonal on camDir
tVector.Vec3D     ; (normalized) vector showing to the screen's top orthogonal on camDir
screenHit.Vec3D   ; the point where the surface given by lVector and tVector through playerPos is hit

scalar_lVectorCamDir.f        ; <lVector, camDir> (precalculated for speed-up)
scalar_tVectorCamDir.f        ; <tVector, camDir> (precalculated for speed-up)
vecprod_lVectorCamDir.Vec3D   ; lVector x camDir (precalculated for speed-up)
vecprod_tVectorCamDir.Vec3D   ; tVector x camDir (precalculated for speed-up)
factorPerPixel.f              ; the factor for lVector and tVector for each screen-pixel
searchDepth.f                 ; searching for terrain-collision up to searchDepth times the player-distance
searchStep.f                  ; searching through depth with this stepsize

Vec_Set(20, 30, 0, @camOffset)
fov.f = 80 * #Deg2Rad         ; the field of view to use
searchDepth = 4.0
searchStep  = 0.01

animationSpeed.l  ; ms for player to reach target
animationSpeed = 2000

targetReachtime.l ; time when to reach target
initialized.l = #False

CameraAngleX = 240
CameraAngleY = 45

If InitEngine3D()
  Add3DArchive("Data\"          , #PB_3DArchive_FileSystem)
 
  InitSprite()
  InitKeyboard()
  InitMouse()
 
  If Screen3DRequester()
    
    AmbientColor(RGB(255,255,255))
    
    CreateMaterial  (0, LoadTexture(0, "Terrain_Texture.jpg"))
    AddMaterialLayer(0, LoadTexture(1, "Terrain_Detail.jpg"), 1)
    
    CreateTerrain("Terrain.png", MaterialID(0), 1, 1, 1, 4)
    
    CreateCamera(0, 0, 0, 100, 100)
    CameraLocate(0, 128, 10, 128)
    
    CameraFOV(0, fov)
    
    SkyDome("Clouds.jpg",10)
    
    ; load player-entity
    LoadMesh   (0, "Robot.mesh")
    CreateMaterial(1, LoadTexture(1, "r2skin.jpg"))
    CreateEntity(0, MeshID(0), MaterialID(1), 0, 0, 0)
    ResizeEntity(0, 0.2, 0.2, 0.2)
    
    ; set the initial playerposition
    playerPos\x = 100
    playerPos\z = 100
    playerPos\y = TerrainHeight(playerPos\x, playerPos\z)
    
    CameraDistance = 40
    
    MouseLocate(ScreenWidth / 2, ScreenHeight / 2)
    MouseX = ScreenWidth / 2
    MouseY = ScreenHeight / 2
    
    ; start
    Repeat
      Screen3DEvents()
           
      If ExamineKeyboard()
       
        If KeyboardPushed(#PB_Key_Left)
          KeyX = -#CameraSpeed
        ElseIf KeyboardPushed(#PB_Key_Right)
          KeyX = #CameraSpeed
        Else
          KeyX = 0
        EndIf
                 
        If KeyboardPushed(#PB_Key_Up)
          KeyY = -#CameraSpeed
        ElseIf KeyboardPushed(#PB_Key_Down)
          KeyY = #CameraSpeed
        Else
          KeyY = 0
        EndIf

      EndIf
     
      If ExamineMouse()
        MouseDeltaX = MouseDeltaX()
        MouseDeltaY = MouseDeltaY()
        MouseX + MouseDeltaX
        If MouseX > ScreenWidth
          MouseX = ScreenWidth
        ElseIf MouseX < 0
          MouseX = 0
        EndIf
        MouseY + MouseDeltaY
        If MouseY > ScreenHeight
          MouseY = ScreenHeight
        ElseIf MouseY < 0
          MouseY = 0
        EndIf
      EndIf
      
      ; set the cameraDir
      Vec_Sub(@playerPos, @camPos, @camDir)
     
      ; set the lVector = norm(up x camDir)
      Vec_VectorProd(@up, @camDir, @lVector)
      abs.f = Vec_Abs(@lVector)
      Vec_ScalarMul(@lVector, 1.0/abs, @lVector)
     
      ; set the tVector = camDir x lVector
      Vec_VectorProd(@camDir, @lVector, @tVector)
      abs.f = Vec_Abs(@tVector)
      Vec_ScalarMul(@tVector, 1/abs)
     
      ; get the distance of cam to entity
      dist.f = Vec_Abs(@camDir)
     
      ; set the factor per pixel
      factorPerPixel = Tan(fov/2) * dist * 2.0 / ScreenHeight
     
      ; set the horizontal/vertical ranges
      vRange.f = factorPerPixel * ScreenHeight/2.0
      hRange.f = factorPerPixel * ScreenWidth/2.0
      
      If MouseButton(#PB_MouseButton_Left)
        
        ; get the horizontal ratio
        hRatio.f = (MouseX - ScreenWidth/2.0) / (ScreenWidth / 2.0)
        
        ; get the vertical ratio
        vRatio.f = (MouseY - ScreenHeight/2.0) / (ScreenHeight / 2.0)
        
        ; build screenHit = playerPos - hRange * hRatio * lVector - vRange * vRatio * tVector
        t1.Vec3D
        Vec_ScalarMul(@lVector, hRange * hRatio, @t1)
        
        t2.Vec3D
        Vec_ScalarMul(@tVector, vRange * vRatio, @t2)
        
        Vec_Sub(@playerPos, @t1, @screenHit)
        Vec_Sub(@screenHit, @t2, @screenHit)
        
        ; pointerDir = screenHit - camPos
        Vec_Sub(@screenHit, @camPos, @pointerDir)
        
        ; set pointerDir's length to dist
        abs.f = Vec_Abs(@pointerDir)
        Vec_ScalarMul(@pointerDir, dist/abs)
        
        ; scan the line until hit terrain
        t.f = 0
        While t < searchDepth
          ; get x and y along line: camPos + t * pointerDir
          x.f = camPos\x + t*pointerDir\x
          y.f = camPos\y + t*pointerDir\y
          z.f = camPos\z + t*pointerDir\z
          
          If y < TerrainHeight(x, z) Or y < 0
            targetPos\x = x - searchStep * pointerDir\x
            targetPos\y = y - searchStep * pointerDir\y
            targetPos\z = z - searchStep * pointerDir\z
           
            Vec_Copy(@playerPos, @startPos)
            targetReachtime = ElapsedMilliseconds() + animationSpeed
           
            Break
          EndIf
          t + searchStep
        Wend
      ElseIf MouseButton(#PB_MouseButton_Right)
        CameraAngleX + MouseDeltaX
        CameraAngleY + MouseDeltaY
      EndIf
      
      CameraDistance - MouseWheel()*2
      
      If targetReachtime > ElapsedMilliseconds()
        playerPos\x = targetPos\x - (targetReachtime - ElapsedMilliseconds()) * (targetPos\x - startPos\x) / animationSpeed
        playerPos\z = targetPos\z - (targetReachtime - ElapsedMilliseconds()) * (targetPos\z - startPos\z) / animationSpeed
      Else
        playerPos\x + KeyX
        playerPos\z + KeyY
      EndIf
      playerPos\y = TerrainHeight(playerPos\x, playerPos\z)
      EntityLocate(0, playerPos\x, playerPos\y, playerPos\z)
      
      ; place the camera relative to the entity and look at player
      If CameraAngleX > 360
        CameraAngleX - 360
      ElseIf CameraAngleX < 0
        CameraAngleX + 360
      EndIf
      If CameraAngleY < 5
        CameraAngleY = 5
      ElseIf CameraAngleY > 85
        CameraAngleY = 85
      EndIf
      camOffset\x = GSin(CameraAngleX)*CameraDistance
      camOffset\y = GSin(CameraAngleY)*CameraDistance
      camOffset\z = GCos(CameraAngleX)*CameraDistance
      Vec_Add(@playerPos, @camOffset, @camPos)
      If camPos\y < TerrainHeight(camPos\x, camPos\z)+10
        camPos\y = TerrainHeight(camPos\x, camPos\z)+10
      EndIf
      CameraLocate(0, camPos\x, camPos\y, camPos\z)
      CameraLookAt(0, playerPos\x, playerPos\y, playerPos\z)
      
      StartDrawing(TextureOutput(0))
        Circle(targetPos\x+3, targetPos\z+3, 5, #Red)
      StopDrawing()
      
      RenderWorld()
      Screen3DStats()
       
      StartDrawing(ScreenOutput())
        Circle(MouseX, MouseY, 5, $0000FF)
        DrawingMode(#PB_2DDrawing_Transparent)
        DrawText(0, 0, "CameraAngleX : " + StrF(CameraAngleX) + "  CameraAngleY : " + StrF(CameraAngleY, 2))
        DrawText(0, 20, "camPos (x y z): " + StrF(camPos\x) + "/" + StrF(camPos\y) + "/" + StrF(camPos\z))
        DrawText(0, 40, "camDir (x y z): " + StrF(camDir\x) + "/" + StrF(camDir\y) + "/" + StrF(camDir\z))
        DrawText(0, 60, "lVector (x y z): " + StrF(lVector\x) + "/" + StrF(lVector\y) + "/" + StrF(lVector\z))
        DrawText(0, 80, "tVector (x y z): " + StrF(tVector\x) + "/" + StrF(tVector\y) + "/" + StrF(tVector\z))
        DrawText(0, 100, "pointerDir (x y z): " + StrF(pointerDir\x) + "/" + StrF(pointerDir\y) + "/" + StrF(pointerDir\z))
        DrawText(0, 120, "t1 (x y z): " + StrF(t1\x) + "/" + StrF(t1\y) + "/" + StrF(t1\z))
        DrawText(0, 140, "screenHit (x y z): " + StrF(screenHit\x) + "/" + StrF(screenHit\y) + "/" + StrF(screenHit\z))
        DrawText(0, 160, "hRange/vRange: " + StrF(hRange) + "/" + StrF(vRange, 2))
;        DrawText(0, 180, "EntityPos (x y z) : " + StrF(EntityX(1)) + "/" + StrF(EntityY(1)) + "/" + StrF(EntityZ(1)))
      StopDrawing()
     
     
      FlipBuffers()
    Until KeyboardPushed(#PB_Key_Escape) Or Quit = 1
  EndIf
   
Else
  MessageRequester("Error", "The 3D Engine can't be initialized",0)
EndIf
 
End
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea

PB-V: 4
WinXP
Benutzeravatar
Froggerprogger
Badmin
Beiträge: 855
Registriert: 08.09.2004 20:02

Beitrag von Froggerprogger »

Dafür musst du eine Normale auf dem Terrainboden an der Stelle des Spielers berechnen. Ohne auf Polygondaten zurückzugreifen könntest du das auch so regeln, dass du einfach an 3 Eckpunkten eines Dreiecks z.B. um die Playerposition herum die Höhenwerte ermittelst, und dann daraus einen auf diesem Dreieck senkrecht stehenden Vektor (per 2 mal Vektorprodukt). Für den kannst du dann wieder die Winkel mit den Koordinatenachsen bestimmen, und gäbe es einen Befehl 'SetEntityRotation' könntest du diesen Winkel dann setzen. Es gibt aber nur 'RotateEntity', welcher die Rotations relativ zur vorherigen ausführt. Du müsstest also die gegenwärtigen Rotationen immer mitspeichern. Vielleicht reicht das erstmal so als Leitfaden ? Meine Zeit ist bis zum 16.04 wegen Arbeits- und Prüfungsstress knapp bemessen, daher werde ich in diesen Tagen mein Freizeitproggen einschränken müssen.

Übrigens ist bei deiner Version etwas seltsam, dass der Rote Punkt, obwohl er an dieselben x/y-Koordinaten wie das target gesetzt wird, nicht genau dort gemalt wird. Der Fehler wird sogar schlimmer, je weiter man zum Rand des Terrains geht. Das ist seltsam, da ja bei Scale 1,1,1 der Terrain x/y-Wert derselbe sein sollte, wie die x/y-Weltkoordinaten. Oder checke ich da bzgl. 3D-Zeug etwas nicht?
Zuletzt geändert von Froggerprogger am 04.04.2007 08:53, insgesamt 1-mal geändert.
!UD2
Benutzeravatar
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Beitrag von Scarabol »

Bezüglich deines letzten Punktes hast du komplett recht, aber das ist PB eben, denke sowieso das ich der Einfachheit halber ein kleines Kreis-Mesh erstelle, dass wird genau positioniert und hinterlässt keine Spuren.

Nochmals vielen Dank für die tolle Hilfe
Scarabol
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea

PB-V: 4
WinXP
Antworten