RotateNode <> RotateCamera bei Maussteuerung

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:

RotateNode <> RotateCamera bei Maussteuerung

Beitrag von Makke »

Hallo zusammen,

ich probiere immer noch die 3D Fähigkeiten von Purebasic (oder besser die von mir ;) ) aus. Dabei ist mir folgendes aufgefallen:

Wenn ich RotateCamera mit der Maus steuere und die Pitch- und Yaw-Achse ändere tut die Camera auch genau das und nicht mehr. Wenn ich jedoch RotateNode mit der Maus steuere und auch die Pitch- und Yaw-Achse bediene wird immer die Roll-Achse auch mit bedient.

Das ist jetzt schwierig zu erlklären, deswegen hier ein kleines Beispiel:

Code: Alles auswählen

EnableExplicit

If InitEngine3D()
  InitSprite()
  InitMouse()
  InitKeyboard()
Else
  MessageRequester("Error", "Can Not init 3D engine !")
  End
EndIf

Define.i TexFloor, MatFloor, MshFloor, EntFloor, MshCube, EntCube, Camera, Node, MouseX, MouseY, nodemode, quit, DebugFont, DebugSprite

If OpenWindow(0, 0, 0, 1024, 768, "3D Test", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
  If Not OpenWindowedScreen(WindowID(0), 0, 0, WindowWidth(0), WindowHeight(0))
    MessageRequester("Error", "Can not open windowed screen !")
    End
  EndIf  
Else
  MessageRequester("Error", "Can not open window !")
  End
EndIf

TexFloor = CreateTexture(#PB_Any, 128, 128)
StartDrawing(TextureOutput(TexFloor))
Box( 0, 0, 128, 128, RGB(225,225,225))
Box(63, 0,  64,  64, RGB(  0,  0,128))
Box( 0,63,  64,  64, RGB(  0,  0,128))
StopDrawing()

MatFloor = CreateMaterial(#PB_Any, TextureID(TexFloor))
SetMaterialColor(MatFloor, #PB_Material_AmbientColor, RGB(175, 238, 238))

MshFloor = CreatePlane(#PB_Any, 1000, 1000, 1, 1, 10, 10)
MshCube  = CreateCube(#PB_Any, 100)

EntFloor = CreateEntity(#PB_Any, MeshID(MshFloor), MaterialID(MatFloor), 0,   0,    0)
EntCube  = CreateEntity(#PB_Any, MeshID(MshCube),  MaterialID(MatFloor), 0, 100, -750)
RotateEntity(EntCube, 45, 45, 0)

Node = CreateNode(#PB_Any, 0, 64, 0)

Camera = CreateCamera(#PB_Any, 0, 0, 100, 100)
MoveCamera(Camera, 0, 64, 0)

AmbientColor(RGB(0,0,128))

DebugSprite = CreateSprite(#PB_Any, 500, 100)
DebugFont   = LoadFont(#PB_Any, "Courier New", 11)

Repeat
  
  If ExamineKeyboard()
    If KeyboardReleased(#PB_Key_F1)
      If nodemode
        nodemode = #False
        DetachNodeObject(Node, CameraID(Camera))
      Else
        nodemode = #True
        AttachNodeObject(Node, CameraID(Camera))
      EndIf
    ElseIf KeyboardReleased(#PB_Key_Escape)
      quit = 1
    EndIf
  EndIf
  
  If ExamineMouse()
    MouseX = -MouseDeltaX() / 10
    MouseY = -MouseDeltaY() / 10
  EndIf
  
  If nodemode
    RotateNode(Node, MouseY, MouseX, 0, #PB_Relative)
  Else
    RotateCamera(Camera, MouseY, MouseX, 0, #PB_Relative)
  EndIf
  
  RenderWorld()
  
  StartDrawing(SpriteOutput(DebugSprite))
  DrawingMode(#PB_2DDrawing_Transparent)
  DrawingFont(FontID(DebugFont))
  FrontColor(RGB(255,255,0))
  Box(0, 0, SpriteWidth(DebugSprite), SpriteHeight(DebugSprite), 0)
  DrawText( 5, 5, "Direction/Node  : x=" + StrF(NodePitch(Node),1) + ", y=" + StrF(NodeYaw(Node),1) + ", z=" + StrF(NodeRoll(Node),1))
  DrawText( 5,25, "Direction/Camera: x=" + StrF(CameraPitch(Camera),1) + ", y=" + StrF(CameraYaw(Camera),1) + ", z=" + StrF(CameraRoll(Camera),1))
  If nodemode
    DrawText(5,45, "Node Mode - hit F1 to switch")
  Else
    DrawText(5,45, "Camera Mode - hit F1 to switch")
  EndIf
  StopDrawing()
  
  DisplayTransparentSprite(DebugSprite, 0, 0)
  
  FlipBuffers()
  
Until quit = 1

End
Im Camera-Modus ist die Steuerung so wie sie sein soll, im Node-Modus verhält sie sich komisch. Soll das so sein ? Verstehe ich da etwas nicht ? Über ein paar erklärende Worte wäre ich dankbar.

Zur Info: Purebaisc 5.11 32bit, Windows 7 64bit
---
Windows 11 (64 bit)
Benutzeravatar
Chimorin
Beiträge: 451
Registriert: 30.01.2013 16:11
Computerausstattung: MSI GTX 660 OC mit TwinFrozr III
6Gb DDR 3 RAM
AMD Phenom II X4 B55 @ 3,6GHz
Windows 7 Home Premium 64-bit

Re: RotateNode <> RotateCamera bei Maussteuerung

Beitrag von Chimorin »

Ist mir damals, als ich das zum ersten Mal benutzt habe, auch aufgefallen, aber damals dachte ich noch nicht an Bugs in PB :D

Aus heutiger Sicht würde ich eindeutig auf Bug tendieren. Außer die Nodes hängen am Anfang schief im Raum... Aber das Einsetzen von RotateNode(..., #PB_Absolute) ändert auch nichts an der Sache.
Poste es mal in das englische Forum :)
Bild

- formerly known as Bananenfreak -
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: RotateNode <> RotateCamera bei Maussteuerung

Beitrag von STARGÅTE »

Das ist kein Bug, sondern hat etwas mit fixierter Yaw-Achse zu tun.

Bei Camera ist die Yaw-Achse standardmäßig auf den Horizont fixiert.
Bei Nodes gibts diese fixierung nicht, da ist die Yaw relativ zur aktuellen Richtung.

Ändern kannst du das mit CameraFixedYawAxis(#Camera, #True oder #False) oder mit
NodeFixedYawAxis(#Node, #True oder #False)
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
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:

Re: RotateNode <> RotateCamera bei Maussteuerung

Beitrag von Makke »

Hallo Ihr Zwei,

danke für die Antworten.

@Stargate: Ok, ich habe verstanden das es absichtlich so sein soll. Dann habe ich den Befehl nach Zeile 41 eingebaut:

Code: Alles auswählen

NodeFixedYawAxis(Node, #True, 0, 1, 0)
direkt eingebaut, es funktioniert aber trotzdem nicht. Ich habe auch ein wenig mit den Vektoren herumgespielt (also: y=-1, alle=0 usw.), aber kein Ergebnis.

Vielleicht kannst Du mir da nochmal weiter auf die Sprünge helfen.
---
Windows 11 (64 bit)
Benutzeravatar
Chimorin
Beiträge: 451
Registriert: 30.01.2013 16:11
Computerausstattung: MSI GTX 660 OC mit TwinFrozr III
6Gb DDR 3 RAM
AMD Phenom II X4 B55 @ 3,6GHz
Windows 7 Home Premium 64-bit

Re: RotateNode <> RotateCamera bei Maussteuerung

Beitrag von Chimorin »

Du könntest auch nach dem Setzen der Kamerawinkel sowas machen:

Code: Alles auswählen

RotateNode(Node, NodePitch(Node), NodeYaw(Node), 0, #PB_Absolute)
Aber wäre interessant zu erfahren, wie es richtig geht :D
Bild

- formerly known as Bananenfreak -
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:

Re: RotateNode <> RotateCamera bei Maussteuerung

Beitrag von Makke »

Bananenfreak hat geschrieben:

Code: Alles auswählen

RotateNode(Node, NodePitch(Node), NodeYaw(Node), 0, #PB_Absolute)
Funktioniert nicht, irgendwie witzig oder ?
---
Windows 11 (64 bit)
Benutzeravatar
Chimorin
Beiträge: 451
Registriert: 30.01.2013 16:11
Computerausstattung: MSI GTX 660 OC mit TwinFrozr III
6Gb DDR 3 RAM
AMD Phenom II X4 B55 @ 3,6GHz
Windows 7 Home Premium 64-bit

Re: RotateNode <> RotateCamera bei Maussteuerung

Beitrag von Chimorin »

Dieser Befehl kommt nach

Code: Alles auswählen

RotateNode(Node, MouseY, MouseX, 0, #PB_Relative)
Nach dem Drehen wird das Node absolut gedreht, nämlich die X- und Y-Drehung, die es eh schon hat und Z = 0. Somit sieht es für uns aus, als ob es sich nicht drehen würde, aber intern ist es für einen sehr kurzen Zeitraum gedreht.
Bild

- formerly known as Bananenfreak -
Benutzeravatar
Chimorin
Beiträge: 451
Registriert: 30.01.2013 16:11
Computerausstattung: MSI GTX 660 OC mit TwinFrozr III
6Gb DDR 3 RAM
AMD Phenom II X4 B55 @ 3,6GHz
Windows 7 Home Premium 64-bit

Re: RotateNode <> RotateCamera bei Maussteuerung

Beitrag von Chimorin »

Eine Frage: Wie funktioniert das jetzt? :mrgreen:
Meine Lösung möchte ich nicht benutzen, einfacher wäre das Fixen einer Achse. Dies geht aber irgendwie nicht.
Bild

- formerly known as Bananenfreak -
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:

Re: RotateNode <> RotateCamera bei Maussteuerung

Beitrag von Makke »

Hi,

tatsächlich funktioniert das mit Nodes und Entities gar nicht. "Schuld" daran ist der sog. Gimbal-Lock-Effekt. Die Möglichkeit den zu umgehen ist entweder das benutzen von Quaternions (aber da gibt es in PB leider keine eigene Math-Bibliothek für) oder das man Node-Bäume baut.

Ich habe z.B eine Flugzeugsteuerung versucht zu simulieren und raus gekommen ist mehr oder weniger eine Flug-Arcarde-Steuerung. Problem war hier, das die Roll Achse (Z) des Entity die Richtung (also eigentlich die Pitch (X) Achse) bedienen muss/soll. Das habe ich dann mit zwei Node-Bäumen gelöst.

Schön zu sehen um dem Gimbal-Lock zu entgehen ist dieses OGRE Tutorial: http://www.ogre3d.org/tikiwiki/tiki-ind ... =Tutorials aber folgende Zeile kann ich nicht umsetzen:

Code: Alles auswählen

this->cameraNode->translate(this->cameraYawNode->getOrientation() *
                             this->cameraPitchNode->getOrientation() *
                             this->mTranslateVector,
                             Ogre::SceneNode::TS_LOCAL);
Die Multiplikation der Quats schaffe ich noch (Code gibt es dazu hier und im Englischem Forum) aber die Multiplikation der Quats mit einem Vector raffe ich nicht. Schön wäre es, wenn es hier direkte PB-Befehle gäbe.
---
Windows 11 (64 bit)
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: RotateNode <> RotateCamera bei Maussteuerung

Beitrag von STARGÅTE »

Nun ja, dazu musst du den Quaternion in eine Matrix umwandeln.
Klar geht das auch ohne Matrix, aber die Berechungen laufen im Endeffekt auf das selbe hinaus, sodass du die Matrix aber zwischenspeichern kannst, was etwas Rechenzeit spart:

Hier mal ein Auszug meiner Math3D.pbi mit den wichtigen Funktionen für dich:

Code: Alles auswählen

Structure Quaternion
	W.f
	X.f
	Y.f
	Z.f
EndStructure

Structure Matrix3
	A11.f : A12.f : A13.f
	A21.f : A22.f : A23.f
	A31.f : A32.f : A33.f 
EndStructure

Structure Vector3
	X.f
	Y.f
	Z.f
EndStructure

; Set Quaternion
Procedure.i Q_Set(*Use.Quaternion, X.f, Y.f, Z.f, W.f)
	*Use\X = X
	*Use\Y = Y
	*Use\Z = Z
	*Use\W = W
	ProcedureReturn *Use
EndProcedure

; Multiply Quaternions
Procedure Q_Multiply(*Use.Quaternion, *Source.Quaternion)
	Protected Buffer.Quaternion
	CopyMemory(*Use, @Buffer, SizeOf(Quaternion))
	*Use\W = *Source\W*Buffer\W - *Source\X*Buffer\X - *Source\Y*Buffer\Y - *Source\Z*Buffer\Z
	*Use\X = *Source\X*Buffer\W + *Source\W*Buffer\X + *Source\Z*Buffer\Y - *Source\Y*Buffer\Z
	*Use\Y = *Source\Y*Buffer\W - *Source\Z*Buffer\X + *Source\W*Buffer\Y + *Source\X*Buffer\Z
	*Use\Z = *Source\Z*Buffer\W + *Source\Y*Buffer\X - *Source\X*Buffer\Y + *Source\W*Buffer\Z
	ProcedureReturn *Use
EndProcedure

; Quaternion to Matrix3
Procedure Q_ToMatrix(*Use.Matrix3, *Source.Quaternion)
	With *Source
		*Use\A11 = 1-2*(\Y*\Y+\Z*\Z)
		*Use\A12 = 2*\X*\Y-2*\W*\Z
		*Use\A13 = 2*\X*\Z+2*\W*\Y
		*Use\A21 = 2*\X*\Y+2*\W*\Z
		*Use\A22 = 1-2*(\X*\X+\Z*\Z)
		*Use\A23 = 2*\Y*\Z-2*\W*\X
		*Use\A31 = 2*\X*\Z-2*\W*\Y
		*Use\A32 = 2*\Y*\Z+2*\W*\X
		*Use\A33 = 1-2*(\X*\X+\Y*\Y)
	EndWith
	ProcedureReturn *Use
EndProcedure

; Rotate Vector3 with Matrix3
Procedure.i V3_Rotate(*Use.Vector3, *Source.Matrix3)
	Protected Buffer.Vector3 
	CopyMemory(*Use, @Buffer, SizeOf(Vector3)) 
	*Use\X = Buffer\X**Source\A11 + Buffer\Y**Source\A12 + Buffer\Z**Source\A13
	*Use\Y = Buffer\X**Source\A21 + Buffer\Y**Source\A22 + Buffer\Z**Source\A23
	*Use\Z = Buffer\X**Source\A31 + Buffer\Y**Source\A32 + Buffer\Z**Source\A33
	ProcedureReturn *Use
EndProcedure
Ich umgehe inzwischen die Rotationsbefehle von PB auch, und nutze meine eigenen.
Dank SetOrientation(ObjektID, x, y, z, w) und FetchOrientation(ObjektID) geht das ja inzwishcen zum glück in PB.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Antworten