Seite 1 von 2

RotateNode <> RotateCamera bei Maussteuerung

Verfasst: 30.06.2013 08:58
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

Re: RotateNode <> RotateCamera bei Maussteuerung

Verfasst: 01.07.2013 12:48
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 :)

Re: RotateNode <> RotateCamera bei Maussteuerung

Verfasst: 01.07.2013 13:20
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)

Re: RotateNode <> RotateCamera bei Maussteuerung

Verfasst: 02.07.2013 09:36
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.

Re: RotateNode <> RotateCamera bei Maussteuerung

Verfasst: 02.07.2013 11:58
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

Re: RotateNode <> RotateCamera bei Maussteuerung

Verfasst: 09.07.2013 20:35
von Makke
Bananenfreak hat geschrieben:

Code: Alles auswählen

RotateNode(Node, NodePitch(Node), NodeYaw(Node), 0, #PB_Absolute)
Funktioniert nicht, irgendwie witzig oder ?

Re: RotateNode <> RotateCamera bei Maussteuerung

Verfasst: 10.07.2013 10:45
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.

Re: RotateNode <> RotateCamera bei Maussteuerung

Verfasst: 29.09.2013 18:06
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.

Re: RotateNode <> RotateCamera bei Maussteuerung

Verfasst: 19.10.2013 08:59
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.

Re: RotateNode <> RotateCamera bei Maussteuerung

Verfasst: 19.10.2013 14:13
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.