Freie Bewegung im 3D-Raum -- isch raffs einfach net

Previous topic - Next topic

Quentin

jaja ich habs noch nicht ganz aufgegeben. Trotz rudimentärem Verständnis für Trigonometrie und ähnliche Schweinereien versuche ich mich immer noch mal in 3D durch den Weltraum zu bewegen, der ja bekanntlich keinen Boden hat. Somit sollte ich meine Kamera ja auch in alle Richtungen frei bewegen können.

Habe mir die Formeln, die hier im Forum dazu geschrieben wurden, immer wieder inhaliert und scheinbar doch nicht wirklich verstanden.

Im folgenden Beispiel ist die Kamera erst einmal auf 0,0,0 gesetzt. Um die Kamera hab ich willkürlich 50 Kuben verstreut (3Dprimitives.gbas aus Common-Ordner einbinden). Nun will ich mit den Cursortasten die Kamera frei bewegen können.

Links - rechts für Bewegung auf X-Z
Oben- unten für Bewegung auf Y-Z

bewege ich nach dem Programmstart die Kamera links-rechts, klappt das wunderbar. Bei oben-unten nur bis Winkel 90 (bzw. 270). dann wird dort die Bewegungsrichtung umgekehrt.

Weiterhin, wenn ich die Kamera z.B. ein wenig nach oben oder unten bewege und dann wieder links-rechts drehe, scheint die Bewegung einer Kurve zu folgen und nicht mehr einer Geraden.

Ich bin ehrlich verwirrt.
Helft einem armen Nicht-Mathematiker.

Code (glbasic) Select
TYPE t_vertex
  x; y; z
ENDTYPE


TYPE t_camera
  pos AS t_vertex
  delta AS t_vertex
  phi                  // angle x-z
  psi                  // angle y-z
ENDTYPE
GLOBAL cam AS t_camera

TYPE t_3dobj
  pos AS t_vertex
  object
  texture
  rotate AS t_vertex
  angle AS t_vertex
ENDTYPE
GLOBAL new3dobj AS t_3dobj
GLOBAL d3dobj[] AS t_3dobj

TYPE t_ship
  speed
  max_speed = 5
ENDTYPE
GLOBAL ship AS t_ship


LOADSPRITE "lava01.bmp", 0

FOR i = 0 TO 50
  CreateCube(i, RAND(20, 50), RGB(128, 128, 128))
  new3dobj.pos.x = RAND(-500, 500)
  new3dobj.pos.y = RAND(-400, 400)
  new3dobj.pos.z = RAND(-400, 500)
  new3dobj.object = i
  new3dobj.texture = 0
  new3dobj.rotate.x = RAND(-10, 10) / 10
  new3dobj.rotate.y = RAND(-10, 10) / 10
  new3dobj.rotate.z = RAND(-10, 10) / 10
  DIMPUSH d3dobj[], new3dobj
NEXT


GLOBAL KEY_LEFT = 203
GLOBAL KEY_RIGHT = 205
GLOBAL KEY_UP = 200
GLOBAL KEY_DOWN = 208
GLOBAL KEY_W = 17          //accellarate
GLOBAL KEY_S = 31          //break

needcalc = TRUE

WHILE TRUE

  WHILE cam.phi > 360; DEC cam.phi, 360; WEND
  WHILE cam.phi < 0; INC cam.phi, 360; WEND
  WHILE cam.psi > 360; DEC cam.psi, 360; WEND
  WHILE cam.psi < 0; INC cam.psi, 360; WEND

  IF KEY(KEY_LEFT)
    DEC cam.phi, 1
    needcalc = TRUE
  ENDIF

  IF KEY(KEY_RIGHT)
    INC cam.phi, 1
    needcalc = TRUE
  ENDIF

  IF KEY(KEY_UP)
    DEC cam.psi, 1
    needcalc = TRUE
  ENDIF

  IF KEY(KEY_DOWN)
    INC cam.psi, 1
    needcalc = TRUE
  ENDIF

  IF needcalc = TRUE
//    IF cam.psi >= 90 AND cam.psi < 270
//      cam.delta.x = COS(cam.phi) * -COS(cam.psi)
//      cam.delta.y = -SIN(cam.psi)
//      cam.delta.z = -SIN(cam.phi) * -COS(cam.psi)
//    ELSE
      cam.delta.x = COS(cam.phi) * COS(cam.psi)
      cam.delta.y = SIN(cam.psi)
      cam.delta.z = -SIN(cam.phi) * COS(cam.psi)
//    ENDIF
    needcalc = FALSE
  ENDIF

  IF KEY(KEY_W)
    INC ship.speed, 0.01
    IF ship.speed > ship.max_speed THEN ship.speed = ship.max_speed
  ENDIF

  IF KEY(KEY_S)
    DEC ship.speed, 0.01
    IF ship.speed < 0 THEN ship.speed = 0
  ENDIF

  INC cam.pos.x, cam.delta.x * ship.speed
  INC cam.pos.y, cam.delta.y * ship.speed
  INC cam.pos.z, cam.delta.z * ship.speed

  X_MAKE3D 1, 1000, 45
  X_CAMERA cam.pos.x, cam.pos.y, cam.pos.z, cam.pos.x+cam.delta.x, cam.pos.y+cam.delta.y, cam.pos.z+cam.delta.z

  FOREACH obj IN d3dobj[]
    X_MOVEMENT obj.pos.x, obj.pos.y, obj.pos.z
    X_ROTATION obj.angle.x, 1, 0, 0
    INC obj.angle.x, obj.rotate.x
    X_ROTATION obj.angle.y, 0, 1, 0
    INC obj.angle.y, obj.rotate.y
    X_ROTATION obj.angle.z, 0, 0, 1
    INC obj.angle.z, obj.rotate.z
    X_SETTEXTURE obj.texture, -1
    X_DRAWOBJ obj.object, 0
  NEXT
  //X_DRAWAXES 0, 0, 0
  X_MAKE2D
  PRINT "Speed: " + (INTEGER(ship.speed * 100)), 0, 0
  PRINT "PHI:   " + cam.phi, 0, 20
  PRINT "PSI:   " + cam.psi, 0, 40
  SHOWSCREEN

WEND


// ------------------------------------------------------------- //
// ---  RAND  ---
// ------------------------------------------------------------- //
FUNCTION RAND: minimum, maximum
  RETURN minimum + RND(-minimum + maximum)
ENDFUNCTION // RAND

Schranz0r

I <3 DGArray's :D

PC:
AMD Ryzen 7 3800X 16@4.5GHz, 16GB Corsair Vengeance LPX DDR4-3200 RAM, ASUS Dual GeForce RTX™ 3060 OC Edition 12GB GDDR6, Windows 11 Pro 64Bit, MSi Tomahawk B350 Mainboard

Tenorm

Ich weis es zwar nicht mehr wo, aber schranzor hat mal (ich glaub bei codeschnipsel) den code nur für die Bewegung und drehung einer camera reingestellt (inklusive Trigonometrie). Such mal, findest man bestimmt schnell.

Quentin

ja ich weiß, damit funktionierts ja auch. Problem ist ja auch eher daß ich das ganze verstehen will, daher ist auch das Entity-System erst einmal keine Alternative. naja ich probiers halt weiter ;)

Schranz0r

Was willste den machen, das Rad neu erfinden?
I <3 DGArray's :D

PC:
AMD Ryzen 7 3800X 16@4.5GHz, 16GB Corsair Vengeance LPX DDR4-3200 RAM, ASUS Dual GeForce RTX™ 3060 OC Edition 12GB GDDR6, Windows 11 Pro 64Bit, MSi Tomahawk B350 Mainboard

Tenorm

Also wenn du´s nicht anhant eines beispiels erlernen willst, wie denn dann?

Quentin

nein Schranzor, nichts neu erfinden, lediglich das Prinzip verstehen.

Also, habe mir Tenorms Rat zu Herzen genommen und Schranzors Beispiel nochmals inhaliert. Korrigier mich bitte, Schranzor, wenn ich was falsches sage, aber mit deinem Beispiel kann man sich zwar in x-z-Richtung im Kreis drehen, nicht jedoch in y-z-Richtung, da hier die Bewegung in deinem Beispiel auf 90° limitiert ist. Und genau das will ich ja nicht, auch in dieser Richtung soll man sich frei im Kreis bewegen können.

Wenn ich die Abfrage nach updownlimit herausnehme habe ich genau den Effekt, den ich oben beschrieben habe, nämlich daß sich die Bewegungsrichtung ab einem bestimmten Winkel umkehrt. Ist ja auch logisch, da dann sin(winkel) negativ wird.

Konkrete Frage also: Wie kann ich das umgehen?

Hier noch mal Schranzors Codeschnipsel:

http://www.glbasic.com/forum/viewtopic.php?id=1147

Schranz0r

Ist garnet mal so einfach da sich ja alles umdreht wenn man über einen gewissen Punkt dreht :)
I <3 DGArray's :D

PC:
AMD Ryzen 7 3800X 16@4.5GHz, 16GB Corsair Vengeance LPX DDR4-3200 RAM, ASUS Dual GeForce RTX™ 3060 OC Edition 12GB GDDR6, Windows 11 Pro 64Bit, MSi Tomahawk B350 Mainboard

Quentin

ebend ;)


ahh ich glaube des Rätsels Lösung liegt bei X_CAMERAUP

Bigsofty hatte das gleiche Problem ;)

http://www.glbasic.com/forum/viewtopic.php?id=804


[edit]
tja, das Problem ist schon mehrfach beschrieben, immer mit Hinweis auf X_CAMERAUP, aber leider nie mit einem Beispiel. Hat jemand das vielleicht schon mal genutzt.

[edit]
ahhh jetzt hab ich einen ersten Teilerfolg.
bei der Berechnung der y-Koordinate einfach mit X_CAMERAUP die y-Richtung umkehren
also

Code (glbasic) Select
 IF cam.psi > 90 AND cam.psi <= 270
    X_CAMERAUP 0, -1, 0
  ENDIF
  X_CAMERA cam.pos.x, cam.pos.y, cam.pos.z, cam.delta.x, cam.delta.y, cam.delta.z
nach jedem X_MAKE3D wird X_CAMERAUP wieder auf 0, 1, 0 gesetzt. Jetzt kann ich mich zumindest in y-Richtung im Kreis drehen, solange ich mit der Kamera an Position 0,0,0 stehen bleibe. Bewege ich mich davon weg, springt die Ansicht wüst umher, also weiter probieren.

Quentin

ahhh ich habs. Schranzor, sorry für den Doppelpost, aber das passt jetzt inhaltlich wirklich nicht mehr in den alten ;)

So jetzt kann ich mich endlich frei in alle Richtungen drehen und dabei mit den Tasten W (beschleunigen) und S (bremsen) auch noch die Kamera bewegen. Mit Textur sehen die Würfel natürlich chicer aus. Als Beispiel kann man das hier mal nehmen:

http://www.gallerie1.de/iron02.jpg

Code (glbasic) Select
// --------------------------------- //
// Project: 3D-Rookie
// Start: Saturday, January 05, 2008
// IDE Version: 5.110


TYPE t_vertex
  x; y; z
ENDTYPE


TYPE t_camera
  pos AS t_vertex
  delta AS t_vertex
  phi                  // angle x-z
  psi                  // angle y-z
ENDTYPE
GLOBAL cam AS t_camera


TYPE t_3dobj
  pos AS t_vertex
  object
  texture
  rotate AS t_vertex
  angle AS t_vertex
ENDTYPE
GLOBAL new3dobj AS t_3dobj
GLOBAL d3dobj[] AS t_3dobj

TYPE t_ship
  speed
  max_speed = 5
ENDTYPE
GLOBAL ship AS t_ship


LOADSPRITE "iron02.png", 0

FOR i = 0 TO 360 STEP 10
  CreateCube(i, RAND(20, 50), RGB(128, 128, 128))
  new3dobj.pos.x = RAND(-500, 500)
  new3dobj.pos.y = RAND(-400, 400)
  new3dobj.pos.z = RAND(-400, 500)
  new3dobj.object = i
  new3dobj.texture = 0
  new3dobj.rotate.x = RAND(-10, 10) / 10
  new3dobj.rotate.y = RAND(-10, 10) / 10
  new3dobj.rotate.z = RAND(-10, 10) / 10
  DIMPUSH d3dobj[], new3dobj
NEXT


GLOBAL KEY_LEFT = 203
GLOBAL KEY_RIGHT = 205
GLOBAL KEY_UP = 200
GLOBAL KEY_DOWN = 208
GLOBAL KEY_W = 17          //accellarate
GLOBAL KEY_S = 31          //break

needcalc = TRUE
//cam.phi = 90

WHILE TRUE

  WHILE cam.phi > 360; DEC cam.phi, 360; WEND
  WHILE cam.phi < 0; INC cam.phi, 360; WEND
  WHILE cam.psi > 360; DEC cam.psi, 360; WEND
  WHILE cam.psi < 0; INC cam.psi, 360; WEND

  IF KEY(KEY_LEFT)
    DEC cam.phi, 1
    needcalc = TRUE
  ENDIF

  IF KEY(KEY_RIGHT)
    INC cam.phi, 1
    needcalc = TRUE
  ENDIF

  IF KEY(KEY_UP)
    DEC cam.psi, 1
    needcalc = TRUE
  ENDIF

  IF KEY(KEY_DOWN)
    INC cam.psi, 1
    needcalc = TRUE
  ENDIF

  IF needcalc = TRUE
    cam.delta.x = COS(cam.phi) * COS(cam.psi)
    cam.delta.z = -SIN(cam.phi) * COS(cam.psi)
    cam.delta.y = SIN(cam.psi)
    needcalc = FALSE
  ENDIF

  IF KEY(KEY_W)
    INC ship.speed, 0.01
    IF ship.speed > ship.max_speed THEN ship.speed = ship.max_speed
  ENDIF

  IF KEY(KEY_S)
    DEC ship.speed, 0.01
    IF ship.speed < 0 THEN ship.speed = 0
  ENDIF

  INC cam.pos.x, cam.delta.x * ship.speed
  INC cam.pos.y, cam.delta.y * ship.speed
  INC cam.pos.z, cam.delta.z * ship.speed

  X_MAKE3D 1, 1000, 45


  IF cam.psi > 90 AND cam.psi <= 270
    X_CAMERAUP 0, -1, 0
  ENDIF
  X_CAMERA cam.pos.x, cam.pos.y, cam.pos.z, cam.pos.x + cam.delta.x, cam.pos.y + cam.delta.y, cam.pos.z + cam.delta.z

  FOREACH obj IN d3dobj[]
    X_MOVEMENT obj.pos.x, obj.pos.y, obj.pos.z
    X_ROTATION obj.angle.x, 1, 0, 0
    INC obj.angle.x, obj.rotate.x
    X_ROTATION obj.angle.y, 0, 1, 0
    INC obj.angle.y, obj.rotate.y
    X_ROTATION obj.angle.z, 0, 0, 1
    INC obj.angle.z, obj.rotate.z
    X_SETTEXTURE obj.texture, -1
    X_DRAWOBJ obj.object, 0
  NEXT
  X_DRAWAXES 0, 0, 100

  X_MAKE2D
  PRINT "Speed: " + (INTEGER(ship.speed * 100)), 0, 0
  PRINT "PHI:   " + cam.phi, 0, 20
  PRINT "PSI:   " + cam.psi, 0, 40
  PRINT "cam.delta.x: " + cam.delta.x, 0, 60
  PRINT "cam.delta.y: " + cam.delta.y, 0, 80
  PRINT "cam.delta.z: " + cam.delta.z, 0, 100
  PRINT "cam.pos.x:   " + cam.pos.x, 0, 120
  PRINT "cam.pos.y:   " + cam.pos.y, 0, 140
  PRINT "cam.pos.x:   " + cam.pos.x, 0, 160
  SHOWSCREEN

WEND


// ------------------------------------------------------------- //
// ---  RAND  ---
// ------------------------------------------------------------- //
FUNCTION RAND: minimum, maximum
  RETURN minimum + RND(-minimum + maximum)
ENDFUNCTION // RAND

Tenorm

Du kannst das ganze ja auch einfach doppelt machen, etwa so:
Code (glbasic) Select
IF rotation>0 AND rotation<=180 THEN ...
IF rotation>180 AND rotation<=360 THEN ...
IF rotation>360 THEN rotation=rotation-360
IF rotation<0 THEN rotation=rotation+360
Nicht schön, aber eigendlich sollts das tun...

Quentin

Ich stehe hier gewaltig auf dem Schlauch.

folgendes kleine Beispiel soll das verdeutlichen. Der Richtungsvektor der Kamera wird hier durch eine rote Linie dargestellt. Cursortaste rechts - links und oben - unten zur Bewegung der Kamera. (bzw. des Vektors). Solange ich mich nur in der Ebene x-z bewege, ist das auch in Ordnung. Auch in y-z-Richtung is ok

AAAAAAAAABBBER.
je mehr der Vektor in Richtung y-Achse zeigt, umso kleiner werden die Kreisbewegungen, bis schließlich bei (0, 1, 0) als wenn der Richtungsvektor gleich der y-Achse ist, die Bewegung ganz aufhört, wenn ich die Cursortasten rechts-links betätige. Ok, ist anhand der Formeln auch klar.

Wie bekomme ich es hin, daß der beschriebene Kreis immer gleich groß ist (bei rechts-links), auch wenn sich der Winkel zur y-Achse ändert. Bei (0, 1, 0) müsste das dann z.B. eine Rotation um die Z-Achse sein.

Tip? Denkanstoss?


Code (glbasic) Select
// --------------------------------- //
// Project: 3D-Rookie2
// Start: Friday, April 18, 2008
// IDE Version: 5.204

TYPE t_vertex
  x; y; z
ENDTYPE

TYPE t_camera
  pos AS t_vertex      // camera position
  delta AS t_vertex    // lookat vector
  up AS t_vertex       // vector for X_CAMERAUP
  phi                  // angle x-z
  psi                  // angle y-z
ENDTYPE
GLOBAL cam AS t_camera

GLOBAL KEY_LEFT = 203
GLOBAL KEY_RIGHT = 205
GLOBAL KEY_UP = 200
GLOBAL KEY_DOWN = 208

needcalc = TRUE
cam.phi = 90

WHILE TRUE

  WHILE cam.phi > 360; DEC cam.phi, 360; WEND
  WHILE cam.phi < 0; INC cam.phi, 360; WEND
  WHILE cam.psi > 360; DEC cam.psi, 360; WEND
  WHILE cam.psi < 0; INC cam.psi, 360; WEND

  IF KEY(KEY_LEFT)
    INC cam.phi, 1
    needcalc = TRUE
  ENDIF
  IF KEY(KEY_RIGHT)
    DEC cam.phi, 1
    needcalc = TRUE
  ENDIF
  IF KEY(KEY_UP)
    INC cam.psi, 1
    needcalc = TRUE
  ENDIF
  IF KEY(KEY_DOWN)
    DEC cam.psi, 1
    needcalc = TRUE
  ENDIF

  IF needcalc = TRUE
    cam.delta.x = COS(cam.phi) * COS(cam.psi)
    cam.delta.y = SIN(cam.psi)
    cam.delta.z = -SIN(cam.phi) * COS(cam.psi)
  ENDIF

  X_MAKE3D 1, 2000, 45
  X_CAMERA 20, 20, -100, 0, 0, 0

  X_LINE cam.pos.x, cam.pos.y, cam.pos.z, cam.pos.x+cam.delta.x*10, cam.pos.y+cam.delta.y*10, cam.pos.z+cam.delta.z*10, 3, RGB(255, 0, 0)
  X_PRINT "Lookat-vector", cam.delta.x*10, cam.delta.y*10, cam.delta.z*10, 0
  X_DRAWAXES 0, 0, 0

  X_MAKE2D
  PRINT "PHI:   " + cam.phi, 0, 20
  PRINT "PSI:   " + cam.psi, 0, 40
  PRINT "cam.pos.x:   " + cam.pos.x, 0, 60
  PRINT "cam.pos.y:   " + cam.pos.y, 0, 80
  PRINT "cam.pos.x:   " + cam.pos.x, 0, 100
  PRINT "lookat x:    " + FORMAT$(4, 2, cam.pos.x + cam.delta.x), 0, 120
  PRINT "lookat y:    " + FORMAT$(4, 2, cam.pos.y + cam.delta.y), 0, 140
  PRINT "lookat z:    " + FORMAT$(4, 2,cam.pos.z + cam.delta.z), 0, 160
  PRINT "Upvector x:  " + FORMAT$(4, 2, cam.pos.x + cam.up.x), 0, 180
  PRINT "Upvector y:  " + FORMAT$(4, 2, cam.pos.y + cam.up.y), 0, 200
  PRINT "Upvector z:  " + FORMAT$(4, 2, cam.pos.z + cam.up.z), 0, 220
  SHOWSCREEN

WEND

Tenorm

Warum nimmst du nich schranzor´s bsp?

Tenorm