Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

13.03.2006, 10:18

Kamera für Flugsimulator

Ich versuche derzeit, einen kleinen Flugsimulator zu porgrammieren, verzweifle aber etwas an der Kamera ( Ich programmiere mit C++ / Direct3D) ...
Bei dieser bereitet mir die Rotation Kopfzerbrechen:

Nase neigen funktioniert wunderbar, Drehung um die Y-Achse soweit ich beurteilen kann auch, doch das Rollen geschieht nicht um die Achse der Kamera, sondern um die Weltachse, sprich, im Steig- oder Sinkflug führt die Kamera eine alles andere als zufriedenstellende Rotation um eine waagerechte Z-Achse, anstatt um seine eigene Achse, durch.

Bei der Programmierung der Kamera bin ich wie folgt vorgegangen:
Modifiziert wird jeweils die View-Matrix, mein erster ( naiver ) Versuch:

- Rotation der Kamera durch Multiplikation mit jeweils einer Matrix für X-, Y- und Z- Rotation .

Zweiter Versuch:
- Berechnung der rotierten Achsen "von Hand" ( Code 1 )

Dritter Versuch:
- Über D3DXMatrixRotationYawPitchRoll ( Code 2 )

Die Funktionen aus Code 1 und 2 liefern jeweils die neu berechnete View-Matrix als Ergebniswert zurück.

Das Ergebnis war jedesmal das selbe: Die Kamera rotiert zwar brav um die entsprechenden Achsen, jedoch nicht um die eigenen, sondern um die stets unmodifizierten Welt-Achsen.

Hat jemand vielleicht einen Tip, was ich falsch mache?

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
 / * CODE 1 */
D3DXMATRIX* cGraphicsCore::rotateCam( cWorldObject* cam) {
    
    D3DXMATRIX yawMat, pitchMat, rollMat;
    D3DXVECTOR3 camRotation = *(cam->getRotation());
    D3DXVECTOR3 camPosition = *(cam->getPosition());

    // Identitätsmatrix und Ausgangsvektoren initialisieren

    
    D3DXVECTOR3 m_up = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
    D3DXVECTOR3 m_look = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
    D3DXVECTOR3 m_right = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );


    // Rotation um Z-Achse

    D3DXMatrixRotationAxis( &rollMat, &m_look, camRotation.z );

    D3DXVec3TransformCoord( &m_right, &m_right, &rollMat );
    D3DXVec3TransformCoord( &m_up, &m_up, &rollMat );

    // Rotation um X-Achse

    D3DXMatrixRotationAxis( &pitchMat, &m_right, camRotation.x );

    D3DXVec3TransformCoord( &m_look, &m_look, &pitchMat );
    D3DXVec3TransformCoord( &m_up, &m_up, &pitchMat );

    // Rotation um Y-Achse

    D3DXMatrixRotationAxis( &yawMat, &m_up, camRotation.y );

    D3DXVec3TransformCoord( &m_look, &m_look, &yawMat );
    D3DXVec3TransformCoord( &m_right, &m_right, &yawMat );

    // Berechnung der viewMatrix


    D3DXMATRIX viewMat;
    D3DXMatrixIdentity( &viewMat );

    // Rotationsachsen festlegen

    viewMat._11 = m_right.x; viewMat._21 = m_right.y; viewMat._31 = m_right.z ;
    viewMat._12 = m_up.x; viewMat._22 = m_up.y; viewMat._32 = m_up.z ;
    viewMat._13 = m_look.x; viewMat._23 = m_look.y; viewMat._33 = m_look.z ;

    // Position berechnen


    viewMat._41 = - D3DXVec3Dot( &camPosition, &m_right);
    viewMat._42 = - D3DXVec3Dot( &camPosition, &m_up);
    viewMat._43 = - D3DXVec3Dot( &camPosition, &m_look);

    return &viewMat;


}


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 /* Code 2 * / 

D3DXMATRIX* cGraphicsCore::rotateCam( cWorldObject* cam ) {

    D3DXMATRIX matView, matTrans, matRot;
    D3DXVECTOR3 camRotation = *(cam->getRotation() );
    D3DXVECTOR3 camPos = *(cam->getPosition() );
    
    D3DXMatrixTranslation( &matTrans, -camPos.x, -camPos.y, -camPos.z); 

    D3DXMatrixIdentity( &matView );
    
    D3DXMatrixRotationYawPitchRoll( &matRot, -camRotation.y, -camRotation.x, -camRotation.z );

    D3DXMatrixMultiply( &matView, &matView, &matTrans);
    D3DXMatrixMultiply( &matView, &matView, &matRot);


    return &matView;
}

Steven77

Alter Hase

Beiträge: 515

Wohnort: Münster - Gievenbeach

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

2

13.03.2006, 11:59

Vertausche einfach mal die Reihenfolge der drei Rotationen...

3

13.03.2006, 14:07

Hab ich schon gemacht und weitere Versuche diesbezüglich haben ergeben, dass stets um irgendeine Achse falsch rotiert wird, abhängig von der Reihenflge der Rotation. Mit dem Code, den ich hier gepostet habe, sieht es noch am wenigsten schlecht aus ;)

Mal ne andere Idee: Die Viewmatrix ist ja keine "wirkliche" Kamera, sondern verändert doch eigentlich nur die Position und Rotation der Objekte relativ zum Betrachter, wenn ich das richtig verstanden habe.

Sprich: Könnte ein Problem in einer eventuellen falschen Anwendung meiner View- und Weltmatrizen liegen?

Zu Beginn der Szene berechne ich meine Viewmatrix mit der oben beschriebenen Funktion, setze diese per Direct3dDevice->SetTransform( D3DTS_VIEW, &viewMatrix ) und anschließend beim Zeichnen jedes 3D-Objektes ( insbesondere natürlich auch der Landschafts-Meshes ) die Weltmatrix für das entsprechende Objekt per SetTransform( D3DTS_WORLD, &worldMatrix ) .

Geht das überhaupt so "naiv", oder muss ich die Matrizen noch irgendwie zu einer bestimmten Matrix kombinieren?[/i]

Anonymous

unregistriert

4

13.03.2006, 14:44

Hi!

Deine Rotationen würden funktionieren, wenn die Rotationen jeweils im
Bezugssystem der davor getätigten Rotation ablaufen würden...

Das heißt:

1. Dein Flieger schaut nach vorn
2. Du drehst ihn nun um 90 Grad nach rechts um die Y-Achse
3. Nun drehst du ihn um 45 Grad um die X-Achse

Erwartest du nun, dass er waagerecht liegt und die Nase um 45 Grad
nach unten gerichtet hat? Nix da - er liegt um 45 Grad gedreht auf der Seite ;)
Und zwar weil die Drehung um die X-Achse um die Welt-X-Achse ging -
durch die Drehung in Punkt 2 wurde aber die X-Achse des Fliegers
verändert und damit müsste korrekterweise die Drehung in Punkt 3 um
die veränderte X-Achse durchgeführt werden.

Es gibt bestimmt eine bessere Lösung, aber mir fällt gerade keine ein:

Du könntest Quaternionen verwenden um den Flieger bequem um eine
beliebige Achse(!) zu drehen. Dann gehst du so vor:
xachse=(1,0,0)
yachse=(0,1,0)
zachse=(0,0,1)

Nun drehst du den Flieger und die drei Achsen um den Vector xachse.
Danach alles um yachse und danach um zachse.

Die drei Achsenvektoren werden durch die Drehungen jeweils mitgedreht
und damit verwendest du dann in den folgenden Drehungen das korrekte,
relative Koordinatensystem.

Quaternionen kann man auch bequem in eine Rotationsmatrix konvertieren
so dass am bestehenden Quelltext nicht so viel geändert werden muss.

Wie gesagt - es geht bestimmt einfacher. Aber ne besser Idee hab ich
grad nicht.

Grüße
Stefan

5

13.03.2006, 14:50

Hm, schein ich um Quaternionen nich rumzukommen ^^ - Auf die bin ich bei meinen Recherchen schon gestoßen, wusste aber noch nich wirklich viel mit anzufangen.
Werd ich mich mal schlau machen :)

Vielen Dank für eure Antworten!

Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

6

13.03.2006, 15:15

Habe mal ein Codeausschnitt hier:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
    myVektor a(0,0,1), u(0,1,0), s(1,0,0);

    rotation = myMatrixRotation(r.x, r.y, r.z) * rotation;
    physikdata.Ausrichtung  = a * rotation;
    physikdata.up          = u * rotation;
    physikdata.side      = s * rotation;

    World = rotation * myMatrixMove(physikdata.Position);

Damit geht es auf jedenfall, wobei die var "rotation" die Rotationsmatrix des Objektes ist.
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

baba_melone

Frischling

Beiträge: 62

Wohnort: 66879 Obermohr

Beruf: Schüler

  • Private Nachricht senden

7

13.03.2006, 20:57

Du musst die Kamera um ihre relativen Achsen drehen(Rotation X: um Kreuzprodukt aus Y-Achse der Kamera und normalisierten relativen Blickpunkt(genauer: Blickpunkt - Position)
Rotation Y um Y-Achse der Kamera
Rotation Z um den normalisierten relativen Blickpunkt(genauer: Blickpunkt - Position)
Klappt wie geschmiert(ich stand mal selbst vor dem Problem)

8

14.03.2006, 12:07

Danke, auf die Idee mit dem normalisierten Blickpunktvektor bin ich noch gar nicht gekommen!
Wenn ich mir das Prinzip mal auf nem Blatt Papier veranschauliche, sind noch zwei Dinge, die mir nicht ganz klar sind:
Zum einen betrifft dies die Y-Achse der Kamera: Befindet sich das Flugzeug beispielsweise im Steigflug, ist diese doch auch gekippt, das heißt, ich müsste diese ebenfalls noch neu berechnen, oder?
Zum zweiten wäre da die Methode, wie ich die Rotationswinkel der Kamera speichere, dies geschieht nämlich akkumulativ, also wenn ich die Kamera erst um 0.02 Radians und dann wieder um 0.04 um die X-Achse rotiere, speichere in den Wert 0.06 in der Variable camRotation.x.
Durch die Betrachtung des Positionsvektors führt aber diese akkumulative Speicherung offensichtlich zu falschen Werten, da bereits durch die Änderung deises Vektors eine vorherige Drehung berücksichtigt wird, richtig?

Ich werde jetzt ma noch etwas rumexperimentieren, so langsam hab ich wenigstens etwas Durchblick, wie die ganze Matrizen-Rotation funktioniert ;)

Ach ja, eine Frage noch: D3DXMatrixRotationAxis liefert mir laut Dokumentation eine um eine gegebene Achse rotierte Matrix zurück. Um diese Rotation auf meine Viewmatrix zu übertragen, brauche ich doch die beiden bloß zu multiplizieren, oder?

Danke schomma für eure Antworten, habt mir alle schon sehr geholfen!
Ich bin nicht verrückt, meine Herren, ich bin lediglich zu allem fähig.

baba_melone

Frischling

Beiträge: 62

Wohnort: 66879 Obermohr

Beruf: Schüler

  • Private Nachricht senden

9

15.03.2006, 14:23

Hier eine Kameraklasse

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
class CCamera
{
private:
    // Daten

    tbVector3 vPosition;
    tbVector3 vBlickpunkt;
    tbVector3 vYAchse;
public:
    // Konstrukturen

    CCamera()
    { 
        vPosition = tbVector3(0.0f, 0.0f, 0.0f); 
        vBlickpunkt = tbVector3(0.0f, 0.0f, 1.0f); 
        vYAchse = tbVector3(0.0f, 1.0f, 0.0f);
    }
    CCamera(const tbVector3& vPos, const tbVector3& vLookAt, const tbVector3& vYAxis)
    {
        vPosition = vPos;
        vBlickpunkt = vLookAt;
        vYAchse = vYAxis;
    }

    // Verschiedene Get und Set-Methoden

    tbMatrix GetMatrix() { return tbMatrixCamera(vPosition, vBlickpunkt, vYAchse);}
    void SetPos(const tbVector3& v) { vPosition = v;}
    tbVector3 GetPos() { return vPosition;}
    void SetBlickpunkt(const tbVector3& v) { vBlickpunkt = v;}
    tbVector3 GetBlickpunkt() { return vBlickpunkt;}
    void SetYAchse(const tbVector3& v) { vYAchse = v;}
    tbVector3 GetYAchse() { return vYAchse;}

    // Bewegungsmethode, zu der Position und dem 

    // Blickpunkt wird der angegebene Vektor hinzuaddiert

    void Move(const tbVector3& vMove) { vPosition += vMove; vBlickpunkt += vMove;}

    // Rotation um die relative x-Achse. Diese berechnet sich aus dem Kreuzprodukt

    // von Y-Achse und dem normalisierten Blickpunkt - der Position. Rotiert werden

    // müssen die y-Achse und der Blickpunkt

    void XRotate(float fGrad)
    {
        vBlickpunkt = vPosition + tbVector3TransformCoords(vBlickpunkt - vPosition, tbMatrixRotationAxis(tbVector3Cross(tbVector3Normalize(vBlickpunkt - vPosition), tbVector3Normalize(vYAchse)), TB_DEG_TO_RAD(fGrad)));
        vYAchse = tbVector3Normalize(tbVector3TransformCoords(vYAchse, tbMatrixRotationAxis(tbVector3Cross(tbVector3Normalize(vBlickpunkt - vPosition), tbVector3Normalize(vYAchse)), TB_DEG_TO_RAD(fGrad))));
    }

    // Rotation um die relative y-Achse. Hier muss die y-Achse nicht rotiert werden!!

    void YRotateRel(float fGrad)
    {
        vBlickpunkt = vPosition + 
                      tbVector3TransformCoords(vBlickpunkt - vPosition, 
                      tbMatrixRotationAxis(tbVector3Normalize(vYAchse), 
                      TB_DEG_TO_RAD(fGrad)));
    }

    // Rotation um die absolute y-Achse. Die y-Achse muss hier mitrotiert werden!!

    void YRotateAbs(float fGrad)
    {
        vBlickpunkt = vPosition + 
                      tbVector3TransformCoords(vBlickpunkt - vPosition, 
                      tbMatrixRotationY(TB_DEG_TO_RAD(fGrad)));
        vYAchse = tbVector3TransformCoords(vYAchse, 
                  tbMatrixRotationY(TB_DEG_TO_RAD(fGrad)));
    }

    // Rotation um die relative z-Achse

    void ZRotate(float fGrad)
    {
        vBlickpunkt = vPosition + 
                      tbVector3TransformCoords(vBlickpunkt - vPosition, 
                      tbMatrixRotationAxis(tbVector3Normalize(vBlickpunkt - vPosition), 
                      TB_DEG_TO_RAD(fGrad)));
        vYAchse = tbVector3Normalize(tbVector3TransformCoords(vYAchse, 
                  tbMatrixRotationAxis(tbVector3Normalize(vBlickpunkt - vPosition), 
                  TB_DEG_TO_RAD(fGrad))));
    }

    // Liefert den relativen Blickpunkt

    tbVector3 GetDir() { return vBlickpunkt - vPosition;}
};

Sry für die Formatierung, kann nichts dafür.
Diese Klasse funtioniert ganz gut. Aus Performance-Gründen kann man auch ein paar Normalisierungen der y-Achse weglassen. Denkbar wäre auch eine relative Move-Methode entlang des Blickpunktes. Dazu müsste man lediglich die bestehende Move-Methode so aufrufen:

C-/C++-Quelltext

1
void MoveRel(float f) { Move(GetDir() * f);}
[/cpp]

Osram

Alter Hase

Beiträge: 889

Wohnort: Weissenthurm

Beruf: SW Entwickler

  • Private Nachricht senden

10

15.03.2006, 22:56

Siehe
http://www.sjbaker.org/steve/omniv/index.html
insbesondere die Matrix Erklärung und vor allem das "Eulers are evil".
"Games are algorithmic entertainment."

Werbeanzeige